Results 1 to 20 of 25

Thread: QTableView printing

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Join Date
    Sep 2006
    Posts
    38
    Thanks
    5
    Thanked 3 Times in 2 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Windows

    Default Re: QTableView printing

    Ok, I finally opened my eyes and saw how to get the TableView contents from the view to my subclass (again, model predefined as QAbstractItemModel *model, and mainTableView->setModel(model) happens during MainWindow construction) but I'm back to square 1 - All that prints is a blank page. I know setting the PrintTableView's model to 'model' passes the contents of the mainTableView to tempTableView b/c I can display the contents of the indexes through qDebug() in PrintTableView:rintTable(). Is there something more I need to do to viewOptions()? or is there something else I'm missing?

    Thanks!!

    Qt Code:
    1. void MainWindow::Print()
    2. {
    3. QPrinter printer(QPrinter::HighResolution);
    4. QPrintDialog *dlg = new QPrintDialog(&printer, this);
    5. dlg->setWindowTitle(tr("Print ACLs"));
    6.  
    7. if (dlg->exec() != QDialog::Accepted)
    8. return;
    9.  
    10. PrintTableView *tempTableView = new PrintTableView();
    11. tempTableView->setModel(model);
    12. tempTableView->printTable(printer);
    13. }
    14.  
    15. PrintTableView::PrintTableView(QWidget *parent) : QTableView (parent)
    16. {
    17.  
    18. }
    19.  
    20. void PrintTableView::printTable(QPrinter &printer)
    21. {
    22. QString str;
    23. QPainter painter;
    24. painter.begin(&printer);
    25. const int ItemSize = 256;
    26. int rows = model()->rowCount(QModelIndex());
    27. int columns = model()->columnCount(QModelIndex());
    28. int sourceWidth = (columns+1) * ItemSize;
    29. int sourceHeight = (rows+1) * ItemSize;
    30. painter.save();
    31.  
    32. double xscale = printer.pageRect().width();
    33. double yscale = printer.pageRect().height();
    34. double scale = qMin(xscale, yscale);
    35.  
    36. painter.translate(printer.paperRect().x() + printer.pageRect().width()/2,
    37. printer.paperRect().y() + printer.pageRect().height()/2);
    38. painter.scale(scale, scale);
    39. painter.translate(-sourceWidth/2, -sourceHeight/2);
    40.  
    41. QStyleOptionViewItem option = viewOptions();
    42.  
    43. float x = ItemSize /2;
    44. for (int printRow = 0; printRow < rows; ++printRow) {
    45. float y = ItemSize /2;
    46. for (int column = 0; column < columns; ++column) {
    47. option.rect = QRect(int(x), int(y), ItemSize, ItemSize);
    48. itemDelegate()->paint(&painter, option, model()->index(printRow, column, QModelIndex()));
    49. x = x + 256;
    50. }
    51. y = y + 256;
    52. }
    53. painter.restore();
    54. painter.end();
    55. }
    56.  
    57. QStyleOptionViewItem PrintTableView::viewOptions() const
    58. {
    59. QStyleOptionViewItem option = QAbstractItemView->viewOptions();
    60. return option;
    61. }
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: QTableView printing

    The painter's scale factors don't look proper. They should be pretty close to 1.0..

    Qt Code:
    1. double xscale = printer.pageRect().width();
    2. double yscale = printer.pageRect().height();
    3. double scale = qMin(xscale, yscale);
    4. ...
    5. painter.scale(scale, scale); // causes painter to scale it's result width/height times bigger
    To copy to clipboard, switch view to plain text mode 

    I guess it should be something more like:
    Qt Code:
    1. double xscale = printer.pageRect().width() / width();
    2. double yscale = printer.pageRect().height() / height();
    3. ...
    4. painter.scale(xscale, yscale);
    To copy to clipboard, switch view to plain text mode 
    J-P Nurmi

  3. #3
    Join Date
    Sep 2006
    Posts
    38
    Thanks
    5
    Thanked 3 Times in 2 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Windows

    Default Re: QTableView printing

    J-P,

    Thanks for the reply. I implemented your suggestion, and I'm still getting a blank page.

  4. #4
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: QTableView printing

    Qt Code:
    1. void TableView::print(QPainter* painter, const QRect& area)
    2. {
    3. const int rows = model()->rowCount();
    4. const int cols = model()->columnCount();
    5.  
    6. // calculate the total width/height table would need without scaling
    7. double totalWidth = 0.0;
    8. for (int c = 0; c < cols; ++c)
    9. {
    10. totalWidth += columnWidth(c);
    11. }
    12. double totalHeight = 0.0;
    13. for (int r = 0; r < rows; ++r)
    14. {
    15. totalHeight += rowHeight(r);
    16. }
    17.  
    18. // calculate proper scale factors
    19. const double scaleX = area.width() / totalWidth;
    20. const double scaleY = area.height() / totalHeight;
    21. painter->scale(scaleX, scaleY);
    22.  
    23. // paint cells
    24. for (int r = 0; r < rows; ++r)
    25. {
    26. for (int c = 0; c < cols; ++c)
    27. {
    28. QModelIndex idx = model()->index(r, c);
    29. QStyleOptionViewItem option = viewOptions();
    30. option.rect = visualRect(idx);
    31. itemDelegate()->paint(painter, option, idx);
    32. }
    33. }
    34. }
    35.  
    36. // printer usage
    37. QPainter painter(&printer);
    38. tableView->print(&painter, printer.pageRect());
    39.  
    40. // test on pixmap
    41. QPixmap pixmap(320, 240);
    42. QPainter painter(&pixmap);
    43. tableView->print(&painter, pixmap.rect());
    44. pixmap.save("table.png", "PNG");
    To copy to clipboard, switch view to plain text mode 

    Edit: I forgot to add painter translating but that should be trivial to add once you get the idea..
    Last edited by jpn; 29th September 2006 at 21:24.
    J-P Nurmi

  5. #5
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: QTableView printing

    Yet another (maybe even better?) option is to use QPainter's powerful redirecting mechanism. This approach doesn't even require subclassing of QTableView.

    Qt Code:
    1. QPrinter printer(QPrinter::HighResolution);
    2. QPrintDialog dlg(&printer, this);
    3. if (dlg.exec() == QDialog::Accepted)
    4. {
    5. // calculate the total width/height table would need without scaling
    6. const int rows = table->model()->rowCount();
    7. const int cols = table->model()->columnCount();
    8. double totalWidth = 0.0;
    9. for (int c = 0; c < cols; ++c)
    10. {
    11. totalWidth += table->columnWidth(c);
    12. }
    13. double totalHeight = 0.0;
    14. for (int r = 0; r < rows; ++r)
    15. {
    16. totalHeight += table->rowHeight(r);
    17. }
    18.  
    19. // redirect table's painting on a pixmap
    20. QPixmap pixmap(totalWidth, totalHeight);
    21. QPainter::setRedirected(table->viewport(), &pixmap);
    22. QPaintEvent event(QRect(0, 0, totalWidth, totalHeight));
    23. QApplication::sendEvent(table->viewport(), &event);
    24. QPainter::restoreRedirected(table->viewport());
    25.  
    26. // print scaled pixmap
    27. QPainter painter(&printer);
    28. painter.drawPixmap(printer.pageRect(), pixmap, pixmap.rect());
    29. }
    To copy to clipboard, switch view to plain text mode 
    J-P Nurmi

  6. #6
    Join Date
    Sep 2006
    Posts
    38
    Thanks
    5
    Thanked 3 Times in 2 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Windows

    Default Re: QTableView printing

    J-P,

    This is AWESOME!!! Thank you so much! both of these work well. The first suggestion works nicely and scales the text well. The 2nd option prints only to the printer (i.e., won't print to Adobe PDF's printer - for instance, i get a "Critical: QPixmap::toWinHBITMAP(), failed to create dibsection(Not enough stoarge is available to process this command.) but that's a hurdle to tackle another time) but prints the grid lines, which is REALLY nice. One issue I have with both suggestions, however, is that for large tables (more than 1 page), it scales the text to fit onto one page. I had thought to emit a signal to call QPrinter::newPage(), but, I can't seem to do this with the QPainter you've set up.

    I've also tried :

    Qt Code:
    1. double totalHeight = 0.0;
    2. for (int r = 0; r < 45; ++r){
    3. totalHeight += table->rowHeight(r);
    4. }
    To copy to clipboard, switch view to plain text mode 

    for your examples, but this only prints 1 page as well. Do you know how I can tell QPainter to send a new page request to the Printer?

    Again...Thank you very much for your help!!!

    --D

  7. #7
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: QTableView printing

    I suppose you have two options. Either you will have to do some calculation before hand so that you know how many rows and columns fit to one page and then request the table to paint a certain range of rows and columns to the specified area. Another option is to pass the whole QPrinter instead of just QPainter and do the calculations inside table's printing method where QPrinter::newPage() is invoked when appropriate.
    J-P Nurmi

  8. #8
    Join Date
    Sep 2006
    Posts
    38
    Thanks
    5
    Thanked 3 Times in 2 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Windows

    Default Re: QTableView printing

    J-P,

    I took your 2nd option. I figured that 45 rows comfortably fit on a page. And here's what I have for the table's print method.

    Qt Code:
    1. void PrintTableView::printTable(QPrinter* printer, QPainter* painter, const QRect& area)
    2. {
    3. const int rows = model()->rowCount();
    4. const int columns = model()->columnCount();
    5. double totalWidth = 0.0;
    6. double totalPageHeight = 0.0;
    7. double totalHeight = 0.0;
    8. for (int c = 0; c < columns; ++c)
    9. {
    10. totalWidth += columnWidth(c);
    11. }
    12.  
    13. for (int p = 0; p < 45; ++p)
    14. {
    15. totalPageHeight += rowHeight(p);
    16. }
    17.  
    18. for (int r = 0; r<rows; ++r)
    19. {
    20. totalHeight += rowHeight(r);
    21. }
    22.  
    23. const double xscale = area.width() / totalWidth;
    24. const double yscale = area.height() / totalHeight;
    25. const double pscale = area.height() / totalPageHeight;
    26.  
    27. painter->scale(xscale, yscale);
    28. painter->translate(area.x() + xscale, area.y() + pscale);
    29.  
    30. bool ok;
    31. int x=0;
    32.  
    33. for (int r = 0; r < rows; ++r) {
    34. ++x;
    35. for (int c = 0; c < columns; ++c) {
    36. QModelIndex idx = model()->index(r,c);
    37. QStyleOptionViewItem option = viewOptions();
    38. option.rect = visualRect(idx);
    39. itemDelegate()->paint(painter, option, idx);
    40.  
    41. }
    42. if (x == 45){
    43. ok = printer->newPage();
    44. x = 0;
    45. }
    46. }
    47. }
    To copy to clipboard, switch view to plain text mode 

    What winds up happening is that if I have the following:
    Qt Code:
    1. painter->scale(xscale, yscale);
    2. painter->translate(area.x() + xscale, area.y() + pscale);
    To copy to clipboard, switch view to plain text mode 
    this prints out fine exept the text is EXTREMELY small. When I swap pscale and yscale, as in:
    Qt Code:
    1. painter->scale(xscale, pscale);
    2. painter->translate(area.x() + xscale, area.y() + yscale);
    To copy to clipboard, switch view to plain text mode 

    the first page prints out fine (rows 1 - 45), and then the printer spits out x more blank pages to cover the rest of the rows. Do I need to re-establish the QStyleOptionViewItem for every newPage()? I'm really puzzled why the printing works with when scaled really small, but when scaled to 45 rows per page, only the first page contains text. Any ideas?

    Thanks!
    --Derrick

  9. #9
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: QTableView printing

    Maybe you need to save the QPainter always before scaling and translating and restore it afterwards. You are using the same QPainter object for painting all pages, this means you are also scaling it again and again.
    J-P Nurmi

  10. #10
    Join Date
    Sep 2006
    Posts
    38
    Thanks
    5
    Thanked 3 Times in 2 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Windows

    Default Re: QTableView printing

    hmmm..I'm not exactly sure. Here's what I tried based on your idea...

    Qt Code:
    1. void PrintTableView::printTable(QPrinter* printer, QPainter* painter, const QRect& area)
    2. {
    3. const int rows = model()->rowCount();
    4. const int columns = model()->columnCount();
    5.  
    6. double totalWidth = 0.0;
    7. double totalPageHeight = 0.0;
    8. double totalHeight = 0.0;
    9. for (int c = 0; c < columns; ++c)
    10. {
    11. totalWidth += columnWidth(c);
    12. }
    13.  
    14. for (int p = 0; p < 45; ++p)
    15. {
    16. totalPageHeight += rowHeight(p);
    17. }
    18.  
    19. for (int r = 0; r<rows; ++r)
    20. {
    21. totalHeight += rowHeight(r);
    22. }
    23.  
    24. const double xscale = area.width() / totalWidth;
    25. const double yscale = area.height() / totalHeight;
    26. const double pscale = area.height() / totalPageHeight;
    27.  
    28. painter->scale(xscale, yscale);
    29. painter->translate(area.x() + xscale, area.y() + pscale);
    30. painter->save();
    31.  
    32. bool ok;
    33. int x=0;
    34.  
    35. for (int r = 0; r < rows; ++r) {
    36. ++x;
    37. for (int c = 0; c < columns; ++c) {
    38. QModelIndex idx = model()->index(r,c);
    39. QStyleOptionViewItem option = viewOptions();
    40. option.rect = visualRect(idx);
    41. itemDelegate()->paint(painter, option, idx);
    42. }
    43. if (x == 45)
    44. {
    45. ok = printer->newPage();
    46. x = 0;
    47. painter->restore();
    48. }
    49. }
    50. }
    To copy to clipboard, switch view to plain text mode 

    if I put painter->save() before the painter->scale(), it prints every page, but only in a very very small square. if I leave it the way it is shown here, it prints every page stretched to page width, but compressed to 1/8th the page. If I do painter->scale(xscale, pscale),and leave painter->save() after painter->translate(), then it prints the first page correctly, but all other pages are blank. I tried re-scaling the painter when x == 45, but that only hangs the program.

  11. #11
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: QTableView printing

    Ok, sorry for not paying enough attention. Forget about saving and restoring for now. Seems I didn't read your code carefully enough. I somehow thought you were calling the print function for every page...

    What I'm suspecting is that the areas returned by the visualRect(idx) don't match on the second page because it's not aware of that you have requested a new page and the coordinates have been reseted. So you would have to translate the painter in vertical direction after every new page request. Try to print the pageRect and the visualRects in the debug output or something and you'll see.
    J-P Nurmi

  12. The following user says thank you to jpn for this useful post:

    derrickbj (10th October 2006)

  13. #12
    Join Date
    Sep 2006
    Posts
    38
    Thanks
    5
    Thanked 3 Times in 2 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Windows

    Default Re: QTableView printing

    J-P,

    You have NOTHING to apologize for!! You've been very helpful.

    That's EXACTLY what needed to be done!!! I ran visualRect through qDebug() after every page and found that y() was incrementing by 1350. I also found out that after printing 45 rows, option.rect.x() was 1000 and not 0. So, I did painter->translate(0, -1350) after calling printer->newPage() and everything prints beautifully. I can't thank you enough for your help!! I was really appreciate it!

    Qt Code:
    1. void PrintTableView::printTable(QPrinter* printer, QPainter* painter, const QRect& area)
    2. {
    3. const int rows = model()->rowCount();
    4. const int columns = model()->columnCount();
    5. double totalWidth = 0.0;
    6. double totalPageHeight = 0.0;
    7. double totalHeight = 0.0;
    8. for (int c = 0; c < columns; ++c)
    9. {
    10. totalWidth += columnWidth(c);
    11. }
    12.  
    13. for (int p = 0; p < 45; ++p)
    14. {
    15. totalPageHeight += rowHeight(p);
    16. }
    17.  
    18. for (int r = 0; r<rows; ++r)
    19. {
    20. totalHeight += rowHeight(r);
    21. }
    22.  
    23. const double xscale = area.width() / totalWidth;
    24. const double yscale = area.height() / totalHeight;
    25. const double pscale = area.height() / totalPageHeight;
    26. painter->scale(xscale, pscale);
    27. painter->translate(area.x() + xscale, area.y() + yscale);
    28.  
    29. bool ok;
    30. int x=0;
    31.  
    32. for (int r = 0; r < rows; ++r) {
    33. ++x;
    34. for (int c = 0; c < columns; ++c) {
    35. QModelIndex idx = model()->index(r,c);
    36. option = viewOptions();
    37. option.rect = visualRect(idx);
    38. itemDelegate()->paint(painter, option, idx);
    39. }
    40. if (x == 45)
    41. {
    42. ok = printer->newPage();
    43. x=0;
    44. painter->translate(0, -1350);
    45. }
    46. }
    47. }
    To copy to clipboard, switch view to plain text mode 

  14. The following 2 users say thank you to derrickbj for this useful post:

    Charlie37 (26th November 2010), thae (5th November 2006)

  15. #13
    Join Date
    Mar 2012
    Posts
    3
    Qt products

    Question Re: QTableView printing

    hi friend . how i do translate this part code from c++ to python?


    for (int c = 0; c < cols; ++c)
    {
    QModelIndex idx = model()->index(r, c);
    QStyleOptionViewItem option = viewOptions();
    option.rect = visualRect(idx);
    itemDelegate()->paint(painter, option, idx);
    }


  16. #14
    Join Date
    Mar 2012
    Posts
    3
    Qt products

    Default Re: QTableView printing


Similar Threads

  1. Set height of QTableView to fit exact number of rows.
    By Ben.Hines in forum Qt Programming
    Replies: 3
    Last Post: 17th January 2019, 01:49
  2. QTableView sorting
    By gabriels in forum Qt Programming
    Replies: 11
    Last Post: 6th October 2010, 17:13
  3. QTableView paints too much
    By Jimmy2775 in forum Qt Programming
    Replies: 2
    Last Post: 26th July 2006, 18:42
  4. Replies: 0
    Last Post: 28th June 2006, 20:49
  5. Multi-line messages in QTableView
    By Conel in forum Qt Programming
    Replies: 6
    Last Post: 13th April 2006, 13:49

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Qt is a trademark of The Qt Company.