python - выбор флажка в QListView - PullRequest
0 голосов
/ 03 июня 2018

Итак, я разработал простой диалог с флажком, который позволяет пользователю выбирать один или несколько элементов из списка.Помимо стандартных кнопок «ОК» и «Отмена», он добавляет кнопки «Выбрать все» и «Отменить выбор всех», позволяя пользователю отмечать / снимать все пункты сразу (это удобно для больших списков).

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», все флажки появляются с пометкой «X» (как и ожидалось).Однако при нажатии кнопки «Выбрать все» флажки вместо этого становятся серыми (хотя элементы выбраны правильно).Я бы предпочел, чтобы они отображались со знаком «X», чтобы обеспечить постоянный внешний вид для пользователя.

См. Рисунки ниже.

Checkbox dialog when first displayed

Checkbox dialog when Select All button is clicked

В общих чертах мой вопрос: как управлять отображением флажков в QListView?

1 Ответ

0 голосов
/ 03 июня 2018

Проблема вызвана тем, что состояния для QCheckBox равны 3:

Qt :: Unchecked 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])
...