如何根据条件正确取消选中Qtablewiget中的项目

时间:2016-12-30 02:48:18

标签: python python-2.7 pyqt pyqt4

我创建了一个包含三列的表格小部件。桌子在qwizard里面。它通过读取文件并将该文件的行放在其第一列中来填充。它看起来像下面的图片。基本上我希望程序以这种方式运行:

  1. 如果同时选中 remove half of item remove all of item ,请取消选中remove half of item,只留下remove all of item行。然后将该行添加到文件中。

    按OK按钮

  2. 执行
  3. 否则,只检查remove half of itemremove all of item。将行添加到文件中。

    按OK按钮

  4. 执行

    问题是它最终会得到我想要的输出,但只有当我多次按Ok时 处理行为的函数是def print_checked(self):def setChoice(self, item):

    enter image description here

    from PyQt4 import QtCore, QtGui
    import sys
    
    class TablePage(QtGui.QWizardPage):
        def __init__( self, parent=None):
            super(TablePage, self).__init__(parent)
            self.isWrittenTo = False
            self.table = QtGui.QTableWidget()
            self.table.setGeometry(200, 200, 200, 200)
    
            self.configureTable(self.table)
            self.table.verticalHeader().hide()
    
            self.buttonBox = QtGui.QDialogButtonBox(self)
            self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
            self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok)
    
            self.horizontalLayout = QtGui.QHBoxLayout()
            self.verticalLayout = QtGui.QVBoxLayout(self)
            self.horizontalLayout.addWidget(self.table)
            self.verticalLayout.addLayout(self.horizontalLayout)
            self.verticalLayout.addWidget(self.buttonBox)
            self.buttonBox.accepted.connect(self.print_checked)
            self.buttonBox.rejected.connect(self.close)
            self.choice = []
    
            self.table.itemChanged.connect(self.setChoice)
    
    
    
    
        def configureTable(self, table):
            rowf = 0
            rowx = 0
            table.setColumnCount(3)
            table.setHorizontalHeaderItem(0, QtGui.QTableWidgetItem("Whole items"))
            table.setHorizontalHeaderItem(1, QtGui.QTableWidgetItem("remove half of item"))
            table.setHorizontalHeaderItem(2, QtGui.QTableWidgetItem("remove all of item"))
            header = table.horizontalHeader()
            header.setResizeMode(0, QtGui.QHeaderView.ResizeToContents)
            header.setResizeMode(1, QtGui.QHeaderView.ResizeToContents)
            table.horizontalHeader().setStretchLastSection(True)
            item_list = []
    
            with open("/home/test1/items.txt") as in_file:
                if in_file is not None:
                    xvar = in_file.readlines()
                for line in xvar:
                    item_list.append(line)
                    rowf += 1
    
            table.setRowCount(rowf)
    
            for linex in item_list:
                x = QtGui.QTableWidgetItem()
                table.setItem(rowx, 0, x)
                rowx += 1
                x.setText(linex)
            for column in range(3):
                for row in range(rowf):
                    if column % 3:
                        self.item = QtGui.QTableWidgetItem(column)
                        self.item.setFlags(QtCore.Qt.ItemIsUserCheckable |
                                      QtCore.Qt.ItemIsEnabled)
                        self.item.setCheckState(QtCore.Qt.Unchecked)
                        self.item.setTextAlignment(QtCore.Qt.AlignHCenter)
                        table.setItem(row, column, self.item)
    
        def setChoice(self, item):
            if item.checkState() == QtCore.Qt.Checked:
                self.choice.append(item)
            if item.checkState() == QtCore.Qt.Unchecked:
                self.choice.remove(item)
    
        def print_checked(self):
            path = '/home/test1/items-to-mod.txt'
            mode = 'a' if self.isWrittenTo else 'w'
            user = self.table
            if len(self.choice) > 0:
                with open(path, mode) as f:
                    for item in self.choice:
                        delete = user.horizontalHeaderItem(item.column()).text()
                        if delete == "remove all of item" and user.item(item.row(), 1).checkState() == QtCore.Qt.Checked:
                            user.item(item.row(), 1).setCheckState(QtCore.Qt.Unchecked)
                            print ('%s' % user.item(item.row(), 0).text() + 'is marked for %s' % delete)
                            f.write('fully remove %s' % user.item(item.row(), 0).text())
                        elif delete == "remove half of item":
                            print ('%s' % user.item(item.row(), 0).text() + 'is marked for %s' % delete)
                            f.write('remove half of %s' % user.item(item.row(), 0).text())
                        elif delete == "remove all of item":
                            print ('%s' % user.item(item.row(), 0).text() + 'is marked for %s' % delete)
                            f.write('fully remove %s' % user.item(item.row(), 0).text())
                        else:
                            print('%s' % item.text())
                            print (item.row(), item.column())
    
    
    if __name__ == '__main__':
        app = QtGui.QApplication(sys.argv)
        wizard = QtGui.QWizard()
        tablepage = TablePage()
        wizard.addPage(tablepage)
        wizard.button(QtGui.QWizard.NextButton).clicked.connect(tablepage.print_checked)
        wizard.show()
        sys.exit(app.exec_())
    

2 个答案:

答案 0 :(得分:1)

在您的代码中,在取消选中时重复操作,使改进代码成为可能的输出:如果标记为第一次添加1 = 2 ** 0,如果标记为第二次添加2 = 2 ** 1,因此每行只有4个案例:[0,2 ** 0,2 ** 1,2 ** 0 + 2 ** 1] = [0,1,2,3]

改变:

    def print_checked(self):
        path = '/home/test1/items-to-mod.txt'
        mode = 'a' if self.isWrittenTo else 'w'
        user = self.table
        d = dict([(x, 0) for x in range(self.table.rowCount())])

        for item in self.choice:
            d[item.row()] += 2 ** (item.column() - 1)

        text = ""
        for row, value in d.iteritems():
            if value == 3:  # They are both checked
                print("fully remove %s" % user.item(row, 0).text())
                user.item(row, 1).setCheckState(QtCore.Qt.Unchecked)
                text += 'fully remove %s' % user.item(row, 0).text()
            elif value == 2:    # only second is checked
                print('fully remove of %s' % user.item(row, 0).text())
                text += 'fully remove %s' % user.item(row, 0).text()
            elif value == 1:    # only first is checked
                print("remove half of %s" % user.item(row, 0).text())
                text += 'remove half of %s' % user.item(row, 0).text()

        with open(path, mode) as f:
            f.write(text)

输出:

enter image description here

单击确定后

enter image description here

fully remove a

fully remove of b

remove half of c

答案 1 :(得分:1)

我要改变的第一件事是setChoice:它应该更清楚地反映状态,通过存储至少有一个支票的每一行,状态:half(1),full(2)或两者(1 + 2 = 3):

def setChoice(self, item):
    row = item.row()
    if item.checkState() == QtCore.Qt.Checked:
        self.choice.setdefault(row, 0)
        self.choice[row] += item.column()
        print(item, row, self.choice[row])

    else:
        assert item.checkState() == QtCore.Qt.Unchecked
        self.choice[row] -= item.column()
        print(item, row, self.choice[row])
        # if checked state is now 0, remove it (could instead leave it
        # but filter on checked==0 in print_checked):
        if self.choice[row] == 0:
            del self.choice[row]

这需要对print_checked进行一些更改。有很多方法可以做到这一点,但我喜欢让代码反映意图:你需要“修复”或“调整”一行有2个复选标记的行;然后像往常一样处理。我还简化了一些格式字符串。结果是:

with open(path, mode) as f:
    for item_row, checked in self.choice.items():
        item_text = user.item(item_row, 0).text()
        if checked == 3:  # delete == "remove all of item" and user.item(item.row(), 1).checkState() == QtCore.Qt.Checked:
            # need to fix it!
            item_half = user.item(item_row, 1)
            item_half.setCheckState(QtCore.Qt.Unchecked)
            checked = 2
            f.write('fixing %s\n' % item_text)

        delete = user.horizontalHeaderItem(checked).text()
        if checked == 1:  # delete == "remove half of item":
            f.write ('%s is marked for %s\n' % (item_text, delete))
            f.write('remove half of %s\n' % item_text)

        elif checked == 2:  # delete == "remove all of item":
            f.write ('%s is marked for %s\n' % (item_text, delete))
            f.write('fully remove %s\n' % item_text)

        else:
            f.write('%s\n' % item_text)
            f.write(item_row, checked)