Search code examples
c++qtqt5qtableviewqprinter

Printing QTableView with vertical and horizontal headers


I have a program that gets data from SQL (using QSQLQuery) and puts the result into a QTableView.

For user ease of reading I needed to transpose the SQL output (swap rows and columns) but couldn't achieve this easily in SQL (even using PIVOT). Instead I used a proxy model in Qt which works great.

Problem is I need to be able to print the entire QTableView. I can print the contents of the table with the horizontal headers but for the life of me, cant work out how to print the vertical headers (technically the first column since each row has a label due to the transposition). Qt doesn't recognize the first 'column' as being a column of row-names, nor do I know how to get it to treat it as vertical headers for printing.

Proxy model code:

class Horizontal_proxy_model : public QAbstractProxyModel {
public:
 Horizontal_proxy_model(QObject * parent = 0);
QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
QModelIndex index(int row, int column, const QModelIndex &parent = 
QModelIndex()) const;
QModelIndex parent(const QModelIndex &child) const;
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) 
const;
};

Horizontal_proxy_model::Horizontal_proxy_model(QObject *parent) :
QAbstractProxyModel(parent) {
}

QModelIndex Horizontal_proxy_model::mapToSource(const QModelIndex 
&proxyIndex) const {
if (sourceModel()) {
  return sourceModel()->index(proxyIndex.column(), proxyIndex.row());
} else {
 return QModelIndex();
}
}

 QModelIndex Horizontal_proxy_model::mapFromSource(const QModelIndex 
 &sourceIndex) const {
 return index(sourceIndex.column(), sourceIndex.row());
 }

 QModelIndex Horizontal_proxy_model::index(int row, int column, const 
 QModelIndex &) const {
 return createIndex(row, column, (void*) 0);
 }

 QModelIndex Horizontal_proxy_model::parent(const QModelIndex &) const {
 return QModelIndex();
 }

 int Horizontal_proxy_model::rowCount(const QModelIndex &) const {
 return sourceModel() ? sourceModel()->columnCount() : 0;
 }

int Horizontal_proxy_model::columnCount(const QModelIndex &) const {
return sourceModel() ? sourceModel()->rowCount() : 0;
}

QVariant Horizontal_proxy_model::headerData(
       int section, Qt::Orientation orientation, int role) const {
 if (!sourceModel()) { return QVariant(); }
 Qt::Orientation new_orientation = orientation == Qt::Horizontal ?
  Qt::Vertical : Qt::Horizontal;
 return sourceModel()->headerData(section, new_orientation, role);
 }

Here are the basics of how I'm trying to print;

void Snapshot_finance::on_pushButton_print_clicked()
{
QString html;
html = "<html><body><table border=\"0\">";
for(int row = 0; row < ui->tableView->model()->rowCount(); row++) {
  html += "<tr>";
  for(int column = 0; column < ui->tableView->model()->columnCount(); 
column++) {
QString data = ui->tableView->model()->data(ui->tableView->model()-> 
index(row, column), Qt::DisplayRole).toString();
    html += "<td>" + data + "</td>";
  }
  html += "</tr>";
}
html += "</table></body></html>";

QPrinter printer;
QPrintDialog *dialog = new QPrintDialog(&printer);
if(dialog->exec() == QDialog::Accepted) {
  QTextDocument document;
  document.setHtml(html);
  document.print(&printer);
}
}

Really appreciate any help or advice!


Solution

  • If you want to print the headers you must add them as shown in the following code:

    void Snapshot_finance::on_pushButton_print_clicked()
        const QString format("<td>%1</td>");
        QString html;
        QAbstractItemModel *md = ui->tableView->model();
        html = "<html><body><table border=\"0\">";
    
        html += "<td></td>";
        for(int column = 0; column < md->columnCount();
            column++) {
            QString data = md->headerData(column, Qt::Horizontal, Qt::DisplayRole).toString();
            html += format.arg(data);
        }
        for(int row = 0; row < md->rowCount() ; row++) {
            html += "<tr>";
            QString data = md->headerData(row, Qt::Vertical, Qt::DisplayRole).toString();
            html += format.arg(data);
            for(int column = 0; column < md->columnCount();
                column++) {
                QString data = md->index(row, column).data(Qt::DisplayRole).toString();
                html += format.arg(data);
            }
            html += "</tr>";
        }
        html += "</table></body></html>";
    
        QPrinter printer;
        QPrintDialog *dialog = new QPrintDialog(&printer);
        if(dialog->exec() == QDialog::Accepted) {
            QTextDocument document;
            document.setHtml(html);
            document.print(&printer);
        }
    }
    

    TableView:

    enter image description here

    Part of PDF

    enter image description here

    The code that is implemented for the test can be found in the following link.