Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Why does it draw headers like this?



  • Here's how it looks:

    x1.gif

    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:

    x3.gif

    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 document QTextDocument. It says no 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 and Pixel 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:

    x1.gif

    BUT it still gets wrong heightLeft. Restructured 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);
        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 redefining int contentHeight = 728 - 2*document->documentMargin(); With this change from 3rd page onward, every odd page get 1 line (no row).

    EDIT
    Also tried float/double instead of int 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:

    x3.gif

    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);
            }
        }
    }
    

Log in to reply