Solved Why does it draw headers like this?
-
Here's how it looks:
on the first page it's perfect. On the second page, I get a piece of overflown text from first page and after that it draws the header in between black horizontal lines. On the 3rd and 4th page those header texts are not in between lines! Is there anything wrong in the computation? Here's the code:
Window::Window(QWidget *parent) : QWidget(parent){ printer = new QPrinter(); printer->setPageSize(QPageSize::A4); printer->setPageMargins(QMarginsF(20,20,20,20), QPageLayout::Millimeter); document = new QTextDocument(this); auto rect = printer->pageRect(QPrinter::Point).size(); // w: 481 h:728 document->setPageSize(QSizeF(rect.width(), rect.height())); createDocument(); auto preview = new QPrintPreviewWidget(printer); preview->setZoomMode(QPrintPreviewWidget::ZoomMode::FitToWidth); connect(preview, &QPrintPreviewWidget::paintRequested, [=]{document->print(printer);}); auto lay = new QVBoxLayout(this); lay->addWidget(preview); } void Window::addHeader(int row, QTextCursor& cursor){ for (int i = 0; i < 4; i++) { auto cell = cursor.currentTable()->cellAt(row, i); QTextTableCellFormat cellFormat; cellFormat.setTopBorder(1); cellFormat.setBottomBorder(1); cellFormat.setBorderBrush(Qt::black); cellFormat.setTopBorderStyle(QTextFrameFormat::BorderStyle_Solid); cellFormat.setBottomBorderStyle(QTextFrameFormat::BorderStyle_Solid); cell.setFormat(cellFormat); QTextCharFormat textFormat; textFormat.setFontWeight(QFont::Bold); QTextBlockFormat blockFormat; blockFormat.setAlignment(Qt::AlignCenter); cursor.setBlockFormat(blockFormat); cursor.insertText("Column " + QString::number(i + 1), textFormat); cursor.movePosition(QTextCursor::NextCell); } } void Window::createDocument(){ int row = 50, column = 4; QTextCursor cursor(document); QTextTableFormat tableFormat; tableFormat.setBorder(0); tableFormat.setCellSpacing(0); tableFormat.setCellPadding(3); QVector<QTextLength> columnLengths; columnLengths.append(QTextLength(QTextLength::PercentageLength, 40)); columnLengths.append(QTextLength(QTextLength::PercentageLength, 20)); columnLengths.append(QTextLength(QTextLength::PercentageLength, 20)); columnLengths.append(QTextLength(QTextLength::PercentageLength, 20)); tableFormat.setColumnWidthConstraints(columnLengths); cursor.insertTable(1, 4, tableFormat); addHeader(0, cursor); QFontMetrics fm(font()); // w: 481 h:728 int heightLeft = 728 - 20; // for single line QFontMetrics says 16 and assumed each of those line in header are 2px/pt QRect col1Rect(0,0, 481 * 0.40, fm.boundingRect("tg").height()); for (int r = 1; r < row; r++) { cursor.currentTable()->appendRows(1); cursor = cursor.currentTable()->rowStart(cursor); cursor.movePosition(QTextCursor::NextCell); for (int c = 0; c < column; c++) { if(c == 0){ auto col1Text = "Column1 Text Column1 Text Column1 Text Column1 Text Column1 Text"; auto reqRect = fm.boundingRect(col1Rect, Qt::AlignLeft | Qt::TextWordWrap, col1Text); heightLeft -= reqRect.height() + 6; // 6 for cell padding if(heightLeft < 0){ heightLeft = 728 - 20; addHeader(r, cursor); cursor.currentTable()->appendRows(1); cursor = cursor.currentTable()->rowStart(cursor); cursor.movePosition(QTextCursor::NextCell); } else{ cursor.insertText(col1Text); cursor.movePosition(QTextCursor::NextCell); continue; } } cursor.insertText("Row " + QString::number(r) + " Column " + QString::number(c)); cursor.movePosition(QTextCursor::NextCell); } } }
-
Adding header is actually much simpler than what I thought. All I need is
tableFormat.setHeaderRowCount(1);
and add header just once and no need to calculate anything manually:The only thing that bothers now is those horizontal lines, appears/disappears when I scroll. Here's the updated code:
Window::Window(QWidget *parent) : QWidget(parent){ document = new QTextDocument(); document->setUndoRedoEnabled(false); printer = new QPrinter(); printer->setPageSize(QPageSize::A4); printer->setPageMargins(QMarginsF(72,72,72,72), QPageLayout::Point); printer->setResolution(fontMetrics().fontDpi()); // no need if you want bigger font auto pageRect = printer->pageRect(QPrinter::DevicePixel).size(); // set to QPrinter::Point if you want bigger font document->setPageSize(QSizeF(pageRect.width(), pageRect.height())); //document->documentLayout()->setPaintDevice(printer); createDocument(); auto preview = new QPrintPreviewWidget(printer); preview->setZoomMode(QPrintPreviewWidget::ZoomMode::FitToWidth); connect(preview, &QPrintPreviewWidget::paintRequested, [=](QPrinter *p){document->print(p);}); auto lay = new QVBoxLayout(this); auto button = new QPushButton("Pint PDF", this); lay->addWidget(button); lay->addWidget(preview); connect(button, &QPushButton::clicked, [=]{ printer->setOutputFormat(QPrinter::PdfFormat); printer->setOutputFileName("test.pdf"); document->print(printer); }); } void Window::addHeader(QTextCursor& cursor){ QTextTableCellFormat cellFormat; cellFormat.setTopBorder(1); cellFormat.setBottomBorder(1); cellFormat.setBorderBrush(Qt::black); cellFormat.setTopBorderStyle(QTextFrameFormat::BorderStyle_Solid); cellFormat.setBottomBorderStyle(QTextFrameFormat::BorderStyle_Solid); QTextCharFormat textFormat; textFormat.setFontWeight(QFont::Bold); QTextBlockFormat blockFormat; blockFormat.setAlignment(Qt::AlignCenter); cursor.setBlockFormat(blockFormat); for (int i = 0; i < 4; i++) { auto cell = cursor.currentTable()->cellAt(0, i); cell.setFormat(cellFormat); cursor.insertText("Column " + QString::number(i + 1), textFormat); cursor.movePosition(QTextCursor::NextCell); } } QTextTableFormat Window::format(){ QTextTableFormat tableFormat; tableFormat.setBorder(0); tableFormat.setCellSpacing(0); tableFormat.setCellPadding(0); tableFormat.setHeaderRowCount(1); QVector<QTextLength> columnLengths; columnLengths.append(QTextLength(QTextLength::PercentageLength, 40)); columnLengths.append(QTextLength(QTextLength::PercentageLength, 20)); columnLengths.append(QTextLength(QTextLength::PercentageLength, 20)); columnLengths.append(QTextLength(QTextLength::PercentageLength, 20)); tableFormat.setColumnWidthConstraints(columnLengths); return tableFormat; } void Window::createDocument(){ int row = 100, column = 4; QTextCursor cursor(document); cursor.insertTable(1, 4, format()); addHeader(cursor); for (int r = 1; r < row; r++) { cursor.currentTable()->appendRows(1); cursor = cursor.currentTable()->rowStart(cursor); cursor.movePosition(QTextCursor::NextCell); for (int c = 0; c < column; c++) { if(c == 0){ QString col1Text; if(r % 2 == 0) col1Text = "Column1 Text Column1 Text Column1 Text Column1 Text Column1 Text Column1 Text Column1 Text"; else col1Text = "Some other Column1 Text text text"; cursor.insertText(col1Text); cursor.movePosition(QTextCursor::NextCell); continue; } cursor.insertText("Row " + QString::number(r) + " Column " + QString::number(c)); cursor.movePosition(QTextCursor::NextCell); } } }
-
Update is too fast and you may need to slow down the scroll speed.
setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
and play with frame rate
QScroller::grabGesture( your widget, QScroller::TouchGesture ); /* for touch screen in case */
QScrollerProperties properties = QScroller::scroller( your widget )->scrollerProperties();
properties.setScrollMetric( QScrollerProperties::FrameRate, frame_rates ); -
@JoeCFD, couldn't do
setVerticalScrollMode( QAbstractItemView::ScrollPerPixel )
on any of Window (QWidget
), preview (QPrintPreviewWidget
) or documentQTextDocument
. It saysno member named 'setVerticalScrollMode' in ...
Tried this:auto properties = QScroller::scroller(/*this/preview/document*/)->scrollerProperties(); properties.setScrollMetric( QScrollerProperties::FrameRate, /*from 10 to 60*/ );
in all of those 3. same output.
-
@Emon-Haque true. There is no scroller for you to manipulate. Adding your own one? I am not familiar with this widget. It is scroll speed problem.
-
@JoeCFD, no idea about creating my own.
Point
andPixel
could be another reason, not sure. -
With
tableFormat.setPageBreakPolicy(QTextTableFormat::PageBreak_AlwaysBefore);
it's slightly better, I always get header text in between lines and on a new page:BUT it still gets wrong
heightLeft
. Restructured the codeWindow::Window(QWidget *parent) : QWidget(parent){ printer = new QPrinter(); printer->setPageSize(QPageSize::A4); printer->setPageMargins(QMarginsF(20,20,20,20), QPageLayout::Millimeter); document = new QTextDocument(this); auto rect = printer->pageRect(QPrinter::Point).size(); //w:481 h:728 document->setPageSize(QSizeF(rect.width(), rect.height())); createDocument(); auto preview = new QPrintPreviewWidget(printer); preview->setZoomMode(QPrintPreviewWidget::ZoomMode::FitToWidth); connect(preview, &QPrintPreviewWidget::paintRequested, [=]{document->print(printer);}); auto lay = new QVBoxLayout(this); auto button = new QPushButton("Pint PDF", this); lay->addWidget(button); lay->addWidget(preview); connect(button, &QPushButton::clicked, [=]{ printer->setOutputFormat(QPrinter::PdfFormat); printer->setOutputFileName("test.pdf"); document->print(printer); }); } void Window::addHeader(QTextCursor& cursor){ for (int i = 0; i < 4; i++) { auto cell = cursor.currentTable()->cellAt(0, i); QTextTableCellFormat cellFormat; cellFormat.setTopBorder(1); cellFormat.setBottomBorder(1); cellFormat.setBorderBrush(Qt::black); cellFormat.setTopBorderStyle(QTextFrameFormat::BorderStyle_Solid); cellFormat.setBottomBorderStyle(QTextFrameFormat::BorderStyle_Solid); cell.setFormat(cellFormat); QTextCharFormat textFormat; textFormat.setFontWeight(QFont::Bold); QTextBlockFormat blockFormat; blockFormat.setAlignment(Qt::AlignCenter); cursor.setBlockFormat(blockFormat); cursor.insertText("Column " + QString::number(i + 1), textFormat); cursor.movePosition(QTextCursor::NextCell); } } QTextTableFormat Window::format(bool pageBreak = true){ QTextTableFormat tableFormat; tableFormat.setBorder(0); tableFormat.setCellSpacing(0); tableFormat.setCellPadding(3); QVector<QTextLength> columnLengths; columnLengths.append(QTextLength(QTextLength::PercentageLength, 40)); columnLengths.append(QTextLength(QTextLength::PercentageLength, 20)); columnLengths.append(QTextLength(QTextLength::PercentageLength, 20)); columnLengths.append(QTextLength(QTextLength::PercentageLength, 20)); tableFormat.setColumnWidthConstraints(columnLengths); if(pageBreak) tableFormat.setPageBreakPolicy(QTextTableFormat::PageBreak_AlwaysBefore); return tableFormat; } void Window::createDocument(){ int row = 100, column = 4; QTextCursor cursor(document); cursor.insertTable(1, 4, format(false)); addHeader(cursor); QFontMetrics fm(font()); int cellPadding = 3 * 2; int headerLineHeight = 1 * 2; int headerHeight = 16 + headerLineHeight; int contentHeight = 728; int heightLeft = contentHeight - headerHeight - cellPadding; qDebug() << heightLeft; QRect col1Rect(0,0, 481 * 0.40, fm.boundingRect("tg").height()); for (int r = 1; r < row; r++) { cursor.currentTable()->appendRows(1); cursor = cursor.currentTable()->rowStart(cursor); cursor.movePosition(QTextCursor::NextRow /*QTextCursor::NextCell*/); for (int c = 0; c < column; c++) { if(c == 0){ auto col1Text = "Column1 Text Column1 Text Column1 Text Column1 Text Column1 Text"; auto reqRect = fm.boundingRect(col1Rect, Qt::AlignLeft | Qt::TextWordWrap, col1Text); heightLeft -= reqRect.height() + cellPadding; if(heightLeft < 0){ heightLeft = contentHeight - headerHeight - cellPadding; qDebug() << heightLeft; cursor.movePosition(QTextCursor::End); cursor.insertTable(1, 4, format()); addHeader(cursor); cursor.currentTable()->appendRows(1); cursor = cursor.currentTable()->rowStart(cursor); cursor.movePosition(QTextCursor::NextRow /*QTextCursor::NextCell*/); } cursor.insertText(col1Text); cursor.movePosition(QTextCursor::NextCell); continue; } cursor.insertText("Row " + QString::number(r) + " Column " + QString::number(c)); cursor.movePosition(QTextCursor::NextCell); } } }
on the second page I get 1 line and after that on every subsequent even page I get that line and a row.
EDIT
Very close after redefiningint contentHeight = 728 - 2*document->documentMargin();
With this change from 3rd page onward, every odd page get 1 line (no row).EDIT
Also triedfloat/double
instead ofint
BUT the result is identical:void Window::createDocument(){ int row = 100, column = 4; QTextCursor cursor(document); cursor.insertTable(1, 4, format(false)); addHeader(cursor); QFontMetricsF headerFm(QFont(font().family(), -1, QFont::Bold, false));; auto header = headerFm.boundingRect("Column 1"); QFontMetricsF fm(font()); qreal cellPadding = 3 * 2; qreal headerLineHeight = 1 * 2; qreal headerHeight = header.height() + headerLineHeight; qreal contentHeight = 728 - 2 * document->documentMargin(); qreal heightLeft = contentHeight - headerHeight - cellPadding; QRectF col1Rect(0,0, 481 * 0.40, fm.boundingRect("tg").height()); ... }
-
Adding header is actually much simpler than what I thought. All I need is
tableFormat.setHeaderRowCount(1);
and add header just once and no need to calculate anything manually:The only thing that bothers now is those horizontal lines, appears/disappears when I scroll. Here's the updated code:
Window::Window(QWidget *parent) : QWidget(parent){ document = new QTextDocument(); document->setUndoRedoEnabled(false); printer = new QPrinter(); printer->setPageSize(QPageSize::A4); printer->setPageMargins(QMarginsF(72,72,72,72), QPageLayout::Point); printer->setResolution(fontMetrics().fontDpi()); // no need if you want bigger font auto pageRect = printer->pageRect(QPrinter::DevicePixel).size(); // set to QPrinter::Point if you want bigger font document->setPageSize(QSizeF(pageRect.width(), pageRect.height())); //document->documentLayout()->setPaintDevice(printer); createDocument(); auto preview = new QPrintPreviewWidget(printer); preview->setZoomMode(QPrintPreviewWidget::ZoomMode::FitToWidth); connect(preview, &QPrintPreviewWidget::paintRequested, [=](QPrinter *p){document->print(p);}); auto lay = new QVBoxLayout(this); auto button = new QPushButton("Pint PDF", this); lay->addWidget(button); lay->addWidget(preview); connect(button, &QPushButton::clicked, [=]{ printer->setOutputFormat(QPrinter::PdfFormat); printer->setOutputFileName("test.pdf"); document->print(printer); }); } void Window::addHeader(QTextCursor& cursor){ QTextTableCellFormat cellFormat; cellFormat.setTopBorder(1); cellFormat.setBottomBorder(1); cellFormat.setBorderBrush(Qt::black); cellFormat.setTopBorderStyle(QTextFrameFormat::BorderStyle_Solid); cellFormat.setBottomBorderStyle(QTextFrameFormat::BorderStyle_Solid); QTextCharFormat textFormat; textFormat.setFontWeight(QFont::Bold); QTextBlockFormat blockFormat; blockFormat.setAlignment(Qt::AlignCenter); cursor.setBlockFormat(blockFormat); for (int i = 0; i < 4; i++) { auto cell = cursor.currentTable()->cellAt(0, i); cell.setFormat(cellFormat); cursor.insertText("Column " + QString::number(i + 1), textFormat); cursor.movePosition(QTextCursor::NextCell); } } QTextTableFormat Window::format(){ QTextTableFormat tableFormat; tableFormat.setBorder(0); tableFormat.setCellSpacing(0); tableFormat.setCellPadding(0); tableFormat.setHeaderRowCount(1); QVector<QTextLength> columnLengths; columnLengths.append(QTextLength(QTextLength::PercentageLength, 40)); columnLengths.append(QTextLength(QTextLength::PercentageLength, 20)); columnLengths.append(QTextLength(QTextLength::PercentageLength, 20)); columnLengths.append(QTextLength(QTextLength::PercentageLength, 20)); tableFormat.setColumnWidthConstraints(columnLengths); return tableFormat; } void Window::createDocument(){ int row = 100, column = 4; QTextCursor cursor(document); cursor.insertTable(1, 4, format()); addHeader(cursor); for (int r = 1; r < row; r++) { cursor.currentTable()->appendRows(1); cursor = cursor.currentTable()->rowStart(cursor); cursor.movePosition(QTextCursor::NextCell); for (int c = 0; c < column; c++) { if(c == 0){ QString col1Text; if(r % 2 == 0) col1Text = "Column1 Text Column1 Text Column1 Text Column1 Text Column1 Text Column1 Text Column1 Text"; else col1Text = "Some other Column1 Text text text"; cursor.insertText(col1Text); cursor.movePosition(QTextCursor::NextCell); continue; } cursor.insertText("Row " + QString::number(r) + " Column " + QString::number(c)); cursor.movePosition(QTextCursor::NextCell); } } }