2

As extension to my previous question I add a copy_button. When user enter input to cells, and user would like select a row, and click on copy_button to copy contents and add an new row below the selected row with same content. The code below supposes to do the job it adds a new row as user wants, expect from its contents is not copying with? I tried to print to see the problem. I add Qtablewidget items to empty list, then the list is printed before for loop, sees it has content added to it. as it should, but a print of items after setItem method, returns empty. It is the same procedure as serializing of the table. I want also to serialize whole table and paste it back.

List print before and after for loop.

enter image description here

My code:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets, Qt


class loadtable(QtWidgets.QTableWidget):
def __init__(self, parent=None):
    super(loadtable, self).__init__(1, 5,parent)



    self.setColumnCount(5)
    self.setRowCount(1)
    self.setFont(QtGui.QFont("Helvetica", 10, QtGui.QFont.Normal, italic=False))   
    headertitle = ("A","B","C","D","E")
    QtWidgets.QTableWidgetItem(headertitle[i]))
    self.setHorizontalHeaderLabels(headertitle)
    self.verticalHeader().setVisible(False)
    self.horizontalHeader().setHighlightSections(False)
    self.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Fixed)
    self.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
    self.setColumnWidth(0, 130)
    combox_lay = QtWidgets.QComboBox(self)
    combox_lay.addItems(["I","II"])
    self.setCellWidget(0, 4, combox_lay)


    self.cellChanged.connect(self._cellclicked)


def _cellclicked(self):
    self.value = self.currentItem()
    self.value.setTextAlignment(Qt.AlignCenter)

@QtCore.pyqtSlot()  
def _addrow(self):
    rowcount = self.rowCount()
    print(rowcount)
    self.setRowCount(rowcount+1)
    combox_add = QtWidgets.QComboBox(self)
    combox_add.addItems(["I","II"])
    self.setCellWidget(rowcount, 4, combox_add)

@QtCore.pyqtSlot()
def _removerow(self):
    if self.rowCount() > 0:
        self.removeRow(self.rowCount()-1)

@QtCore.pyqtSlot()
def _cellselected(self):
    r = self.currentRow()
    c = self.columnCount()
    cell = []
    for i in range(c):
        if i == c-1:
            it = self.cellWidget(r , i)
        else:
            it = self.item(r , i)
        cell.append(it)
    self.setcopy(cell,r,c)

def setcopy(self,cell,r,c):
    self.insertRow(r+1)
    print(cell)
    for j in range(c):
        if j < c-1:
            it = self.setItem(r+1, j,cell[j])
        else:
            it = self.setCellWidget(r+1, j, cell[j])
        print(it)
    return it    

class thirdtabloads(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(thirdtabloads, self).__init__(parent)      
        table = loadtable()


    button_layout = QtWidgets.QVBoxLayout()
    add_button = QtWidgets.QPushButton("Add")
    add_button.clicked.connect(table._addrow)
    delete_button = QtWidgets.QPushButton("Delete")
    delete_button.clicked.connect(table._removerow)
    copy_button = QtWidgets.QPushButton("Copy")
    copy_button.clicked.connect(table._cellselected)

    button_layout = QtWidgets.QVBoxLayout()
    button_layout.addWidget(add_button, alignment=QtCore.Qt.AlignBottom)
    button_layout.addWidget(delete_button, alignment=QtCore.Qt.AlignTop)
    button_layout.addWidget(copy_button, alignment=QtCore.Qt.AlignTop)


    tablehbox = QtWidgets.QHBoxLayout()
    tablehbox.setContentsMargins(10,10,10,10)
    tablehbox.addWidget(table)

    grid = QtWidgets.QGridLayout(self)
    grid.addLayout(button_layout, 0, 1)
    grid.addLayout(tablehbox, 0, 0)        



if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    w = thirdtabloads()
    w.show()
    sys.exit(app.exec_())
Pavel.D
  • 561
  • 1
  • 15
  • 41

1 Answers1

1

First of all, the setItem() method does not return anything since it is a setter, so if you want to find out if the item exists, you must use the item() method that is a getter.

Going to the problem, you have noticed that you must copy 2 elements: the QTableWidgetItems and the widgets that you set with setCellWidget(). If you want to copy the QTableWidgetItem you must use its clone() method, and in the case of the widget there is no method to do it so you will have to create a method that copies the necessary, in my solution I show how to copy the items from a QComboBox, if you have other widgets you will have to implement more code. Finally always check, for example currentRow can be -1 when nothing has been selected.

import sys
from PyQt5 import QtCore, QtGui, QtWidgets

# copy qwidgets
def copy_widget(w):
    if isinstance(w, QtWidgets.QWidget):
        new_w = type(w)()
        if isinstance(w, QtWidgets.QComboBox):
            vals = [w.itemText(ix) for ix in range(w.count())]
            new_w.addItems(vals)

        # if instance(w, QtWidgets.AnotherWidget):
        #     copy values
        return new_w

class LoadTable(QtWidgets.QTableWidget):
    def __init__(self, parent=None):
        super(LoadTable, self).__init__(1, 5, parent)
        self.setFont(QtGui.QFont("Helvetica", 10, QtGui.QFont.Normal, italic=False))   
        headertitle = ("A","B","C","D","E")
        self.setHorizontalHeaderLabels(headertitle)
        self.verticalHeader().hide()
        self.horizontalHeader().setHighlightSections(False)
        self.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Fixed)

        self.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
        self.setColumnWidth(0, 130)

        combox_lay = QtWidgets.QComboBox(self)
        combox_lay.addItems(["I","II"])
        self.setCellWidget(0, 4, combox_lay)

        self.cellChanged.connect(self._cellclicked)

    @QtCore.pyqtSlot(int, int)
    def _cellclicked(self, r, c):
        it = self.item(r, c)
        it.setTextAlignment(QtCore.Qt.AlignCenter)        

    @QtCore.pyqtSlot()
    def _addrow(self):
        rowcount = self.rowCount()
        self.insertRow(rowcount)
        combox_add = QtWidgets.QComboBox(self)
        combox_add.addItems(["I","II"])
        self.setCellWidget(rowcount, 4, combox_add)

    @QtCore.pyqtSlot()
    def _removerow(self):
        if self.rowCount() > 0:
            self.removeRow(self.rowCount()-1)

    @QtCore.pyqtSlot()
    def _copyrow(self):
        r = self.currentRow()
        if 0 <= r < self.rowCount():
            cells = {"items": [], "widgets": []}
            for i in range(self.columnCount()):
                it = self.item(r, i)
                if it:
                    cells["items"].append((i, it.clone()))
                w = self.cellWidget(r, i)
                if w:
                    cells["widgets"].append((i, copy_widget(w)))
            self.copy(cells, r+1)

    def copy(self, cells, r):
        self.insertRow(r)
        for i, it in cells["items"]:
            self.setItem(r, i, it)
        for i, w in cells["widgets"]:
            self.setCellWidget(r, i, w)


class ThirdTabLoads(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(ThirdTabLoads, self).__init__(parent)    

        table = LoadTable()

        add_button = QtWidgets.QPushButton("Add")
        add_button.clicked.connect(table._addrow)

        delete_button = QtWidgets.QPushButton("Delete")
        delete_button.clicked.connect(table._removerow)

        copy_button = QtWidgets.QPushButton("Copy")
        copy_button.clicked.connect(table._copyrow)

        button_layout = QtWidgets.QVBoxLayout()
        button_layout.addWidget(add_button, alignment=QtCore.Qt.AlignBottom)
        button_layout.addWidget(delete_button, alignment=QtCore.Qt.AlignTop)
        button_layout.addWidget(copy_button, alignment=QtCore.Qt.AlignTop)

        tablehbox = QtWidgets.QHBoxLayout()
        tablehbox.setContentsMargins(10, 10, 10, 10)
        tablehbox.addWidget(table)

        grid = QtWidgets.QGridLayout(self)
        grid.addLayout(button_layout, 0, 1)
        grid.addLayout(tablehbox, 0, 0)        


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    w = ThirdTabLoads()
    w.show()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thanks a lot for solution. {"items": [], "widgets": []} this code! do you greate a list within a dictionary? and could you explain, how if it: cells["items"].append((i, it.clone())). would work? – Pavel.D Sep 16 '18 at 22:22
  • @ZarKha As you have noticed I am creating a list within a dictionary, and the elements of that list are tuples of 2 elements that are the column number and the copy of the QTableWidgetItem. If my answer helps you do not forget to mark it as correct, that is the best way to thank. – eyllanesc Sep 16 '18 at 22:26