python - QListView

时间:2018-06-03 12:58:51

标签: python pyqt pyqt4 qlistview qcheckbox

因此,我开发了一个带有复选框的简单对话框,允许用户从列表中选择一个或多个项目。除了标准的OK和Cancel按钮,它还会添加Select All和Unselect All按钮,允许用户一次检查/取消选中所有项目(这对于大型列表来说非常方便)。

import os, sys
from PyQt4 import Qt, QtCore, QtGui

class ChecklistDialog(QtGui.QDialog):
    def __init__(self, name, stringlist=None, checked=False, icon=None, parent=None):
        super(ChecklistDialog, self).__init__(parent)

        self.name = name
        self.icon = icon
        self.model = QtGui.QStandardItemModel()
        self.listView = QtGui.QListView()

        if stringlist is not None:
            for i in range(len(stringlist)):
                item = QtGui.QStandardItem(stringlist[i])
                item.setCheckable(True)
                check = QtCore.Qt.Checked if checked else QtCore.Qt.Unchecked
                item.setCheckState(check)
                self.model.appendRow(item)

        self.listView.setModel(self.model)

        self.okButton = QtGui.QPushButton("OK")
        self.cancelButton = QtGui.QPushButton("Cancel")
        self.selectButton = QtGui.QPushButton("Select All")
        self.unselectButton = QtGui.QPushButton("Unselect All")

        hbox = QtGui.QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(self.okButton)
        hbox.addWidget(self.cancelButton)
        hbox.addWidget(self.selectButton)
        hbox.addWidget(self.unselectButton)

        vbox = QtGui.QVBoxLayout()
        vbox.addWidget(self.listView)
        vbox.addStretch(1)
        vbox.addLayout(hbox)

        self.setLayout(vbox)    
        #self.setLayout(layout)
        self.setWindowTitle(self.name)
        if self.icon is not None: self.setWindowIcon(self.icon)

        self.okButton.clicked.connect(self.accept)
        self.cancelButton.clicked.connect(self.reject)
        self.selectButton.clicked.connect(self.select)
        self.unselectButton.clicked.connect(self.unselect)

    def reject(self):
        QtGui.QDialog.reject(self)

    def accept(self):
        self.choices = []
        i = 0
        while self.model.item(i):
            if self.model.item(i).checkState():
                self.choices.append(self.model.item(i).text())
            i += 1
        QtGui.QDialog.accept(self)

    def select(self):
        i = 0
        while self.model.item(i):
            item = self.model.item(i)
            if not item.checkState():
                item.setCheckState(True)
            i += 1

    def unselect(self):
        i = 0
        while self.model.item(i):
            item = self.model.item(i)
            item.setCheckState(False)
            i += 1  

if __name__ == "__main__":
    fruits = ["Banana", "Apple", "Elderberry", "Clementine", "Fig",
        "Guava", "Mango", "Honeydew Melon", "Date", "Watermelon",
        "Tangerine", "Ugli Fruit", "Juniperberry", "Kiwi", "Lemon",
        "Nectarine", "Plum", "Raspberry", "Strawberry", "Orange"]
    app = QtGui.QApplication(sys.argv)
    form = ChecklistDialog("Fruit", fruits, checked=True)
    if form.exec_():
        print("\n".join([str(s) for s in form.choices]))

上面的代码可以工作,但我对QListView的奇怪行为感到困扰:当显示对话框并将“check”参数设置为True时,所有的checkboze都会显示为带有“X”标记(如预期的那样)。但是,单击“全选”按钮时,复选框将变为灰色(尽管项目已正确选择)。我希望它们显示为“X”标记,以便向用户呈现一致的外观。

见下图。

Checkbox dialog when first displayed

Checkbox dialog when Select All button is clicked

一般来说,我的问题是:如何控制QListView中复选框的显示方式?

2 个答案:

答案 0 :(得分:1)

问题的原因是QCheckBox的{​​{3}}为3:

  

Qt ::未选中 0该项目未选中。

     

Qt :: PartiallyChecked 1部分检查该项目。中的物品   如果某些但不是全部,则可以部分地检查分层模型   他们的孩子接受了检查。

     

Qt :: Checked 2项目已经过检查。

正如您所看到的那样,它们是整数值,当您传递True值时,这将被转换为1,相当于Qt::PartiallyChecked的那些,您得到的是矩形而不是十字形。

解决方法是将正确的值传递给它:QtCore.Qt.Checked,如下所示:

import sys
from PyQt4 import Qt, QtCore, QtGui


class ChecklistDialog(QtGui.QDialog):

    def __init__(
        self,
        name,
        stringlist=None,
        checked=False,
        icon=None,
        parent=None,
        ):
        super(ChecklistDialog, self).__init__(parent)

        self.name = name
        self.icon = icon
        self.model = QtGui.QStandardItemModel()
        self.listView = QtGui.QListView()

        for string in stringlist:
            item = QtGui.QStandardItem(string)
            item.setCheckable(True)
            check = \
                (QtCore.Qt.Checked if checked else QtCore.Qt.Unchecked)
            item.setCheckState(check)
            self.model.appendRow(item)

        self.listView.setModel(self.model)

        self.okButton = QtGui.QPushButton('OK')
        self.cancelButton = QtGui.QPushButton('Cancel')
        self.selectButton = QtGui.QPushButton('Select All')
        self.unselectButton = QtGui.QPushButton('Unselect All')

        hbox = QtGui.QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(self.okButton)
        hbox.addWidget(self.cancelButton)
        hbox.addWidget(self.selectButton)
        hbox.addWidget(self.unselectButton)

        vbox = QtGui.QVBoxLayout(self)
        vbox.addWidget(self.listView)
        vbox.addStretch(1)
        vbox.addLayout(hbox)

        self.setWindowTitle(self.name)
        if self.icon:
            self.setWindowIcon(self.icon)

        self.okButton.clicked.connect(self.onAccepted)
        self.cancelButton.clicked.connect(self.reject)
        self.selectButton.clicked.connect(self.select)
        self.unselectButton.clicked.connect(self.unselect)

    def onAccepted(self):
        self.choices = [self.model.item(i).text() for i in
                        range(self.model.rowCount())
                        if self.model.item(i).checkState()
                        == QtCore.Qt.Checked]
        self.accept()

    def select(self):
        for i in range(self.model.rowCount()):
            item = self.model.item(i)
            item.setCheckState(QtCore.Qt.Checked)

    def unselect(self):
        for i in range(self.model.rowCount()):
            item = self.model.item(i)
            item.setCheckState(QtCore.Qt.Unchecked)


if __name__ == '__main__':
    fruits = [
        'Banana',
        'Apple',
        'Elderberry',
        'Clementine',
        'Fig',
        'Guava',
        'Mango',
        'Honeydew Melon',
        'Date',
        'Watermelon',
        'Tangerine',
        'Ugli Fruit',
        'Juniperberry',
        'Kiwi',
        'Lemon',
        'Nectarine',
        'Plum',
        'Raspberry',
        'Strawberry',
        'Orange',
        ]
    app = QtGui.QApplication(sys.argv)
    form = ChecklistDialog('Fruit', fruits, checked=True)
    if form.exec_() == QtGui.QDialog.Accepted:
        print '\n'.join([str(s) for s in form.choices])

答案 1 :(得分:0)

这是PyQt5的实现:

from PyQt5 import QtWidgets, QtGui, QtCore

Class ChecklistDialog(QtWidgets.QDialog):

def __init__(self,
    name,
    stringlist=None,
    checked=False,
    icon=None,
    parent=None,
    ):
    super(ChecklistDialog, self).__init__(parent)

    self.name = name
    self.icon = icon
    self.model = QtGui.QStandardItemModel()
    self.listView = QtWidgets.QListView()

    for string in stringlist:
        item = QtGui.QStandardItem(string)
        item.setCheckable(True)
        check = \
            (QtCore.Qt.Checked if checked else QtCore.Qt.Unchecked)
        item.setCheckState(check)
        self.model.appendRow(item)

    self.listView.setModel(self.model)

    self.okButton = QtWidgets.QPushButton('OK')
    self.cancelButton = QtWidgets.QPushButton('Cancel')
    self.selectButton = QtWidgets.QPushButton('Select All')
    self.unselectButton = QtWidgets.QPushButton('Unselect All')

    hbox = QtWidgets.QHBoxLayout()
    hbox.addStretch(1)
    hbox.addWidget(self.okButton)
    hbox.addWidget(self.cancelButton)
    hbox.addWidget(self.selectButton)
    hbox.addWidget(self.unselectButton)

    vbox = QtWidgets.QVBoxLayout(self)
    vbox.addWidget(self.listView)
    vbox.addStretch(1)
    vbox.addLayout(hbox)

    self.setWindowTitle(self.name)
    if self.icon:
        self.setWindowIcon(self.icon)

    self.okButton.clicked.connect(self.onAccepted)
    self.cancelButton.clicked.connect(self.reject)
    self.selectButton.clicked.connect(self.select)
    self.unselectButton.clicked.connect(self.unselect)

def onAccepted(self):
    self.choices = [self.model.item(i).text() for i in
                    range(self.model.rowCount())
                    if self.model.item(i).checkState()
                    == QtCore.Qt.Checked]
    self.accept()

def select(self):
    for i in range(self.model.rowCount()):
        item = self.model.item(i)
        item.setCheckState(QtCore.Qt.Checked)

def unselect(self):
    for i in range(self.model.rowCount()):
        item = self.model.item(i)
        item.setCheckState(QtCore.Qt.Unchecked)

如果名称 =='主要':

import sys

fruits = [
    'Banana',
    'Apple',
    'Elderberry',
    'Clementine',
    'Fig',
    'Guava',
    'Mango',
    'Honeydew Melon',
    'Date',
    'Watermelon',
    'Tangerine',
    'Ugli Fruit',
    'Juniperberry',
    'Kiwi',
    'Lemon',
    'Nectarine',
    'Plum',
    'Raspberry',
    'Strawberry',
    'Orange',
]
app = QtWidgets.QApplication(sys.argv)
form = ChecklistDialog('Fruit', fruits, checked=True)
if form.exec_() == QtWidgets.QDialog.Accepted:
    print('\n'.join([str(s) for s in form.choices]))`