Printing QTableView using render method - c++

I am trying to print a table view. To fill a table view I have created my own model. To print table I am doing following:
QPrinter printer;
QPrintDialog printDialog( &printer, 0);
if( QDialog::Accepted == printDialog.exec() ) {
if( QPrinter::Landscape != printer.orientation() ) {
printer.setOrientation(QPrinter::Landscape);
}
QPoint startPoint = QPoint(20, 20);
QRegion printRegion = QRegion( 20, 20, printer.paperRect().width(),printer.paperRect().height() );
for( int i = 0; i < m_tables.size(); ++i ) {
tableView->render( &printer, startPoint, printRegion, QWidget::DrawChildren );
}
}
The issue is that I am printing into PDF file and there I am able to see only a small part of the table. I thought that changing the region parameter could help, but in the fact not. Any suggestions how to fix this?

Ok, here is my solution. Would be nice to hear your opinion.
PrintTableModel* pTableModel = new PrintTableModel();
QTableView* pTableView = new QTableView;
pTableView->setModel(pTableModel);
int width = 0;
int height = 0;
int columns = pTableModel->columnCount();
int rows = pTableModel->rowCount();
pTableView->resizeColumnsToContents();
for( int i = 0; i < columns; ++i ) {
width += pTableView->columnWidth(i);
}
for( int i = 0; i < rows; ++i ) {
height += pTableView->rowHeight(i);
}
pTableView->setFixedSize(width, height);
pTableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
pTableView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
This code helped me. To print the table correctly, you just can perform a render call:
pTableView->render(printer);

You might try void QPrinter::setResolution ( int dpi ) to force a number of widget pixels per printer inches, effectively zooming your widget on the printout.

Related

How to know header text width in QStyle?

I have a QTreeView and use ProxyStyle for that.
The pic above is just the header. Now I need to draw the up/down arrow (for sorting items) beside header label as in figure. In order to put the arrow in the correct postion I need to know:
the left margin = distance between the text and left border
the text width
the right margin = distance between the text and the arrow
How can I calculate the text width in this case? I thought about QFontMetrics but dont know how to receive the text to calculate.
In my style I use only drawPrimitive function
void MyStyle::drawPrimitive( PrimitiveElement p_pe, const QStyleOption *p_option, QPainter *p_painter, const QWidget *p_widget ) const
{
int leftmargin = 10;
int rightmargin = 10;
if ( p_pe == PE_IndicatorHeaderArrow )
{
if ( const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>( p_option ) )
{
QPixmap pix;
if ( header->sortIndicator & QStyleOptionHeader::SortUp )
{
pix = QPixmap( ":/sortUp.png" );
}
else if ( header->sortIndicator & QStyleOptionHeader::SortDown )
{
pix = QPixmap( ":/sortDown.png" );
}
p_painter->drawPixmap( header->rect.left() + leftmargin+ subElementRect( SE_HeaderLabel, p_option, p_widget ).width() + rightmargin, header->rect.top() + pix.height(), pix );
}
}
else
{
QProxyStyle::drawPrimitive( p_pe, p_option, p_painter, p_widget );
}
}
I use subElementRect( SE_HeaderLabel, p_option, p_widget ).width() in this case but it is wrong. How can I calculate the width of the text?
It is all contained in the QStyleOptionHeader. The text width could be obtained by calling:
int textWidth = header->fontMetrics.boundingRect(header->text).width();

Bar code label printing using html-Qt

I have managed to generate bar-code on a QLabel. I have tried QPainter and I could not get properly aligned output. My label size is 50*25 mm for a label ,one row contain two label.
This is my code for printing label.
I want to know that, is there any solution to print label using html. So that I can design very well.
QPrinter printer1;
QList<QPrinterInfo> printerList = QPrinterInfo::availablePrinters() ;
for(int r=0; r<printerList.size();++r)
{
if(printerList[r].printerName() == "TSC TE200")
{
QPageSize pageSize(QSizeF(45.0,70.0),QPageSize::Millimeter,"",QPageSize::ExactMatch);
QPrinter PRINTER(printerList[r],QPrinter::PrinterResolution);
PRINTER.setOrientation(QPrinter::Portrait);
PRINTER.setPageSize(pageSize);
PRINTER.setFullPage(true);
PRINTER.setOutputFormat(QPrinter::NativeFormat);
// int id = QFontDatabase::addApplicationFont("/Applications/untitledfolder/free3of9.ttf");
// QFontDatabase::applicationFontFamilies(id).at(0);
QFont barcodefont;
barcodefont.setFamily("Code 128");
barcodefont.setWeight(QFont::Normal);
barcodefont.setPointSize(60);
QFontMetrics fntm(barcodefont);
QPainter painter2;
if(!painter2.begin(&PRINTER))
return;
int x1 = printer1.paperRect().x() + printer1.width()/2 -
fntm.width("123456789")/2;enter code here
int y1 = printer1.paperRect().y();
int w1 = fntm.width("123456789");
int h1 = fntm.height()/4;
int x11 = printer1.paperRect().x() + printer1.width() - fntm.width("123456789")/2;
int y11 = printer1.paperRect().y();
int w11 = fntm.width("123456789");
int h11 = fntm.height()/4;
QRect rect10 = QRect(x1,y1,w1,h1);
QRect rect20 = QRect(x11,y11,w11,h11);
painter2.setFont(barcodefont);
painter2.drawText(rect10,Qt::AlignLeft,"123456789");
painter2.end();
break;
}
}
Sorry about my English. I'm not fluent in English.Thanks in advance.

QTableView resize vertically data not refreshed

I've implemented a table through deriving QTableView and QAbstractTableModel. It all seems to work fine except when I resize the table vertically the rows that were originally out of view don't show any data.
There is no issue when resizing horizontally possibly because I've overridden the resizeEvent() method and am recalculating column widths which I obviously don't do if the table is resized vertically.
I'm using the following code in the model to add data to the table:
bool DDUTableModel::insertRow(int row, const QModelIndex& parent)
{
beginInsertRows(parent, row, row);
digital_display_list_.append(DigitalDisplayData(path_));
endInsertRows();
return true;
}
The resizeEvent() looks like this:
void DDUTableView::resizeEvent(QResizeEvent* ev)
{
int num_columns = NUM_ELEMENTS(COLUMN_WIDTHS);
if (num_columns > 0) {
int width = ev->size().width();
int used_width = 0;
// Set our widths to be a percentage of the available width
for (int i = 0; i < num_columns - 1; i++) {
int column_width = (width * COLUMN_WIDTHS[i]) / 100;
this->setColumnWidth(i, column_width);
used_width += column_width;
}
// Set our last column to the remaining width
this->setColumnWidth(num_columns - 1, width - used_width);
}
}
Any ideas?
The problem was with the resizeEvent(). I need to also invoke the method in the QTableView class that I derived from to force a refresh on vertical resizing. Amended method looks like this:
void DDUTableView::resizeEvent(QResizeEvent* ev)
{
int num_columns = NUM_ELEMENTS(COLUMN_WIDTHS);
if (num_columns > 0) {
int width = ev->size().width();
int used_width = 0;
// Set our widths to be a percentage of the available width
for (int i = 0; i < num_columns - 1; i++) {
int column_width = (width * COLUMN_WIDTHS[i]) / 100;
this->setColumnWidth(i, column_width);
used_width += column_width;
}
// Set our last column to the remaining width
this->setColumnWidth(num_columns - 1, width - used_width);
}
QTableView::resizeEvent(ev);
}

Qt setColumnWidth does not work

Have written the following code:
m_selectCategoryTableWidget = new QTableWidget;
m_selectCategoryTableWidget->setRowCount(0);
m_selectCategoryTableWidget->setColumnCount(2);
m_selectCategoryTableWidget->setHorizontalHeaderLabels(QStringList()<<tr("Category")<<tr("Number of items"));
m_selectCategoryTableWidget->verticalHeader()->setVisible(false);
m_selectCategoryTableWidget->horizontalHeader()->setStretchLastSection(true);
//m_selectCategoryTableWidget->setColumnWidth(0,400);
m_selectCategoryTableWidget->resizeColumnsToContents();
m_selectCategoryTableWidget->setColumnWidth(1,100); //this does not take effect
Please help.
Well, Qt's logic is so, that after column resize, scroll bar area checks how columns fit into it. And if the sum of all columns' widths is less than the widget's visible width, then the last column gets resized to fill up the space leading to no visible result of calling setColumnWidth(). Actually two resizes happen - to shrink and reverse to enlarge.
So, the lesson is - get control's visible width, recalculate sizes as you want, and resize all but the last column. For two column case it's really simple:
int secondColumnWidth = 100;
int firstColumnWidth = m_selectCategoryTableWidget->width() - secondColumnWidth;
if (firstColumnWidth > 0)
{
m_selectCategoryTableWidget->setColumnWidth(0, firstColumnWidth);
}
else
{
m_selectCategoryTableWidget->resizeColumnsToContents();
}
Good luck!
It is also possible to specify that you want the first column to fill the remaining space instead of the last column. Unfortunately this does seem to prevent the user from being able to manually resize the columns.
int secondColumnWidth = 100;
m_selectCategoryTableWidget->header()->setStretchLastSection(false);
m_selectCategoryTableWidget->header()->setResizeMode(0, QHeaderView::Stretch);
m_selectCategoryTableWidget->setColumnWidth(1, secondColumnWidth);
This will automatically resize the columns to fit ("view" is an QTableView* and model is a QSqlQueryModel*).
static_cast<QTableView*>(view)->horizontalHeader()
->resizeSections(QHeaderView::ResizeToContents);
QFontMetrics fm(view->font());
for (int i = 0 ; i < model->record().count(); ++i)
{
int maxLength = 0;
for (int j = 0; j < model->rowCount(); ++j)
{
QString cell = model->record(j).value(i).toString();
if (fm.width(cell) > maxLength)
{
maxLength = fm.width(cell);
}
}
QHeaderView& hv = *static_cast<QTableView*>(view)->horizontalHeader();
if (maxLength > hv.sectionSize(i))
{
hv.resizeSection(i, maxLength * 1.5);
}
}

How do I iterate a collection of Excel columns in C++ using Automation?

I want to do the moral equivalent of the following VBA code:
For Each col In Worksheets("Sheet1").Columns
# do stuff
Next col
I have generated MFC wrappers for the Excel type library that get me this far (the generated types all derive from COleDispatchDriver:
CApplication app;
app.CreateDispatch( clsid, e );
CWorkbooks wbks( app.get_Workbooks() );
CWorkbook book( wbks.Open( filename, /* optional args */ ) );
CRange cols( app.get_Columns() );
long numCols = cols.get_Count();
and from there I'm stuck. It looks like I can sort of iterate over cells using Range::get_Item( rowid, colid ), and then get the column from the cell, but I was looking for a more direct translation of the above loop.
(EDIT) Clarification: I don't actually care about the individual cells. My goal is to determine which columns have width 0 (are hidden) and delete them from the worksheet.
I assume that you're trying to traverse all the cells in the spreadsheet. You can get the active worksheet's "all cells" range, and loop through its rows and columns :
CSheets sheets = book.get_WorkSheets();
CWorkSheet sheet = sheets.get_ActiveSheet();
Range cells = sheet.get_Cells();
int nRows = cells.get_Rows().get_Count();
int nCols = cells.get_Columns().get_Count();
for (int i = 0; i <= nRows; i++)
{
for (int j = 0; j <= nCols; j++)
{
Range cell = cells.get_Item(i+1,j+1);
//Do stuff with individual cell
}
}
EDIT: In response to OP clarification:
This will probably do what you're looking for:
CSheets sheets = book.get_WorkSheets();
CWorkSheet sheet = sheets.get_ActiveSheet();
Range cols= sheet.get_Columns();
int nCols = cols.get_Count();
for (int i = nCols; i > 0; i--)
{
Range topCellOfCol = cells.get_Item(1, i);
Range entireCol = topCellOfCol.get_EntireColumn();
if (entireCol.get_Hidden())
entireCol.Delete( xlShiftToLeft );
}
Thanks to Steve, I got most of the way there. It turns out that despite the Excel VBA documentation, Range::Item has different behavior depending on how the range is created; thus:
COleVariant OPTIONAL( (long)DISP_E_PARAMNOTFOUND, VT_ERROR );
Range cols = sheet.get_Columns();
for ( long i = cols.get_Count(); i > 0; --i )
{
Range col = cols.get_Item( COleVariant( i ), OPTIONAL ) ;
// ...
}
will iterate through ranges representing the columns, and
Range rows = sheet.get_Rows();
for ( long i = rows.get_Count(); i > 0; --i )
{
Range row = cols.get_Item( COleVariant( i ), OPTIONAL );
// ...
}
will iterate through ranges representing the rows. This is implicit in the VBA examples, but not actually stated in the documentation.