0

I'm trying to print data from QTableWidget, which applies span to few columns. Span merges rows to handle one to many relationship.

Problem: Span formatting is ignored while printing.

class TableViewPage(QtWidgets.QMainWindow, Ui_table_MainWindow):
    def __init__(self, parent=None):
        super(TableViewPage, self).__init__(parent)
        self.setupUi(self)
        self.btn_load.clicked.connect(self.loadTable)
        self.btn_preview.clicked.connect(self.handlePreview)
        self.btn_print.clicked.connect(self.handlePrint)

        for row in range(self.tableWidget.rowCount()):
            for col in range(self.tableWidget.columnCount()):
                item = QtWidgets.QTableWidgetItem()
                item.setTextAlignment(QtCore.Qt.AlignCenter)
                self.tableWidget.setItem(row, col, item)
        self.tableWidget.setHorizontalHeaderLabels(
            'Party|Date|Product|Qty|Rate|Amt|Loading|Freight|Net|CD|Comm'.split('|'))

    def loadTable(self):
        connection = sqlite3.connect('main_databaseSample.db')
        connection.execute("DROP VIEW IF EXISTS myview;")
        query = "CREATE VIEW myview as SELECT dispatch_id, d_buyer," \
                "d_date, product, quantity, rate, d_amount, d_addFreight, d_subFreight, d_netAmount " \
                " from " \
                "dispatch, dispatch_products WHERE dispatch.id_dispatch = dispatch_products.dispatch_id " \
                "ORDER BY dispatch_id ASC;"
        connection.execute(query)
        query = "SELECT * FROM myview"
        result = connection.execute(query)
        last_id = -1
        start_row = 0
        for row, row_data in enumerate(result):
            self.tableWidget.insertRow(row)
            current_id, *other_values = row_data
            for col, data in enumerate(other_values):
                it = QtWidgets.QTableWidgetItem(str(data))
                self.tableWidget.setItem(row, col, it)
            if last_id != current_id and last_id != -1:
                self.apply_span(start_row, row - start_row)
                start_row = row
            last_id = current_id
        if start_row != row:
            self.apply_span(start_row, self.tableWidget.rowCount() - start_row)

    def apply_span(self, row, nrow):
        if nrow <= 1:
            return
        for c in (0, 1, 5, 6, 7, 8):
            self.tableWidget.setSpan(row, c, nrow, 1)

    def handlePrint(self):
        dialog = QtPrintSupport.QPrintDialog()
        if dialog.exec_() == QtWidgets.QDialog.Accepted:
            self.handlePaintRequest(dialog.printer())

    def handlePreview(self):
        dialog = QtPrintSupport.QPrintPreviewDialog()
        dialog.paintRequested.connect(self.handlePaintRequest)
        dialog.exec_()

    def handlePaintRequest(self, printer):
        document = QtGui.QTextDocument()
        cursor = QtGui.QTextCursor(document)
        table = cursor.insertTable(
            self.tableWidget.rowCount(), self.tableWidget.columnCount())
        for row in range(table.rows()):
            for col in range(table.columns()):
                cursor.insertText(self.tableWidget.item(row, col).text())
                cursor.movePosition(QtGui.QTextCursor.NextCell)
        document.print_(printer)

Sample Data:

dispatch table:
ID date   mill buyer addF subF amount cd comm netAmount
1  15-10  abc  A     0    0    100    0  0    100
2  16-10  xyz  B     0    0    200    0  0    200

dispatch_products table:
Dispatch_ID product qty rate
1           M       40  1
1           A       60  1
2           S       50  4

Code Output:
buyer date  product quantity rate amount addFreight subFreight NetAmount
A     15-10 M       40       1    100    0          0          100
A     15-10 A       60       1    100    0          0          100
B     16-10 S       50       4    200    0          0          200

Expected Output:
buyer date  product quantity rate amount addFreight subFreight NetAmount
A     15-10 M       40       1    100    0          0          100
            A       60       1                           
B     16-10 S       50       4    200    0          0          200

Using apply_span function I'm able to display the table as 'Expected Output', but while printing data is printed as 'Code Output' formatting.

UPDATE: While printing Column names are also ignored.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
user3170565
  • 59
  • 1
  • 10
  • There is no magic bullet solution that can guess what output format you want. If you want to format spans differently, you will have to write all the necessary code yourself to do that (i.e. check the [rowSpan](https://doc.qt.io/qt-5/qtableview.html#rowSpan) and/or [columnSpan](https://doc.qt.io/qt-5/qtableview.html#columnSpan), and then change the formatting as appropriate). – ekhumoro Oct 29 '18 at 11:48
  • @ekhumoro I understand I’ll have to write the code myself, but it takes some time to learn and I’ll new to PYQt. Also, problem here is, ‘Expected Output’ format is already achieved in QTableWidget, but formatting is lost while printing. So, do I have to format again before printing? – user3170565 Oct 29 '18 at 11:56
  • Do you actually need to print the table as a `QTextDocument`? If you just want to print the table directly, look at the answers to [this question](https://stackoverflow.com/q/8193920/984421). which show different ways of printing widgets. All widgets have a [render](https://doc.qt.io/qt-5/qwidget.html#render) method which allows you to print an image of the widget as it appears on screen. – ekhumoro Oct 29 '18 at 12:22

1 Answers1

1

First of all you have to detect the span and add it but you will probably have problems since there are items that are not visible but they exist, so one task is to eliminate them for this, add more code to apply_span (). On the other hand, a new row must be added for the header.

def apply_span(self, row, nrow):
    if nrow <= 1:
        return
    for c in (0, 1, 5, 6, 7, 8):
        self.tableWidget.setSpan(row, c, nrow, 1)
        # remove hidden items
        for r in range(row+1, row+nrow):
            t = self.tableWidget.takeItem(r, c)
            del t

@QtCore.pyqtSlot(QtPrintSupport.QPrinter)
def handlePaintRequest(self, printer):
    document = QtGui.QTextDocument()
    cursor = QtGui.QTextCursor(document)
    table = cursor.insertTable(self.tableWidget.rowCount()+1, self.tableWidget.columnCount())

    for c in range(table.columns()):
        it = self.tableWidget.horizontalHeaderItem(c)
        cursor.insertText(str(c) if it is None else it.text())
        cursor.movePosition(QtGui.QTextCursor.NextCell)

    for row in range(1, table.rows()):
        for col in range(table.columns()):
            it = self.tableWidget.item(row-1, col)
            cursor.insertText("" if it is None else it.text())
            cursor.movePosition(QtGui.QTextCursor.NextCell)

    for row in range(1, table.rows()):
        for col in range(table.columns()):
            table.mergeCells(row, col, self.tableWidget.rowSpan(row-1, col), 1)
    document.print_(printer)
eyllanesc
  • 235,170
  • 19
  • 170
  • 241