【问题标题】:How can I properly uncheck items in a Qtablewiget based on a condition如何根据条件正确取消选中 Qtablewiget 中的项目
【发布时间】:2016-12-30 02:48:18
【问题描述】:

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

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

    按确定按钮执行

  2. 否则,如果仅选中 remove half of itemremove all of item。将该行添加到文件中。

    按确定按钮执行

问题是它最终得到了我想要的输出,但前提是我多次按确定 处理该行为的函数是def print_checked(self):def setChoice(self, item):

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_())

【问题讨论】:

  • 我无法理解您的要求。在这两种情况下,是否将行添加到文件中?在第一种情况下:检查是否仅在删除一半项目时被删除?
  • 是的,该行已添加到文件中,但我必须按住确定按钮才能在文件中显示正确的输出
  • 另外一件事,如果你知道一种方法可以让表格单元格中的复选框居中,那就太棒了

标签: python python-2.7 pyqt pyqt4


【解决方案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)

输出:

点击确定后:

fully remove a

fully remove of b

remove half of c

【讨论】:

  • 您应该解释 OP 做错了什么,理想情况下(即如果可能,即仅更改几块代码)只发布需要更改的代码,因为 SO 不支持并排差异。
  • 它的工作方式和我喜欢的完全一样,但你能解释一下这行代码是如何工作的吗?我有一个想法,但不完全确定d = dict([(x, 0) for x in range(self.table.rowCount())]) for item in self.choice: d[item.row()] += 2 ** (item.column() - 1)
  • A ** k = {a * a * a * ... * a} k 次
  • 干得好,但我认为列表理解和幂公式使方法难以理解。
  • @Schollii 我只用 1 和 0 编码,例如如果两者都标记:11,如果我只设置第一个,01,如果我设置第二个,10,如果没有,00,如果我们认为它们是二进制数字。
【解决方案2】:

我要更改的第一件事是 setChoice:它应该更清楚地反映状态,通过为至少有一个检查的每一行存储状态:半 (1)、全 (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)

【讨论】:

  • @Schollii 谢谢
猜你喜欢
  • 1970-01-01
  • 2019-04-11
  • 2018-03-22
  • 1970-01-01
  • 2022-01-03
  • 1970-01-01
  • 2021-02-12
  • 2021-10-12
  • 1970-01-01
相关资源
最近更新 更多