отмените выбор и установите все флажки в PyQt5 - PullRequest
0 голосов
/ 25 марта 2020

аналогично Python PyQt - флажок, чтобы снять все остальные флажки

Я хочу установить флажок

  1. , чтобы снять все выбранные флажки.
  2. И флажок для выбора всех флажков
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableView, QGridLayout, QWidget, QCheckBox
from PyQt5.QtGui import QFont
from functools import partial

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.font = QFont("Helvetica", 9)
        self.setFont(self.font)
        self.showMaximized()     
        grid = QGridLayout()
        self.setLayout(grid)

        positions = [(i,j) for i in range(5) for j in range(5)]
        print('\npostions: ', positions)
        wordlist = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y']


        for position, wordlist in zip(positions, wordlist): 
            checkB =(QCheckBox(wordlist)) 
            checkB.setStatusTip("Crawling best singals for "+wordlist+"." ) # set Statusbar
            checkB.stateChanged.connect(partial(self.checkState, wordlist))
            grid.addWidget(checkB, *position)

        checkBoxNone = QCheckBox("None Selected")
        checkBoxNone.setChecked(True)
        checkBoxNone.stateChanged.connect(self.checkState)
        grid.addWidget(checkBoxNone, 6, 1)

        checkAll = QCheckBox("Select All")
        checkAll.setChecked(False)
        checkAll.stateChanged.connect(self.selectAll)
        grid.addWidget(checkAll, 6, 2)

        widget = QWidget()
        widget.setLayout(grid) 
        self.setCentralWidget(widget)      

        self.statusBar().showMessage('Ready')

    # Here are the problems. 
    # Is it because I have create checkboxes with a for loop?

    def selectAll(self, state):
        if state == Qt.Checked:
            if self.sender() == MainWindow.checkAll:
                MainWindow.checkB.setChecked(True)

    def checkState(self, checktext, state):
        if state == Qt.Checked:
            print(checktext)
            if self.sender() == MainWindow.checkBoxNone:
                MainWindow.checkB.setChecked(False)
            elif self.sender() == MainWindow.checkB:
                MainWindow.checkBoxNone.setChecked(False)

if __name__ == '__main__':

    app = QApplication(sys.argv)
    app.setStyle('Fusion')
    mw = MainWindow()

Как я могу получить рабочий код с этой настройкой?

1 Ответ

0 голосов
/ 25 марта 2020

Существуют различные проблемы с вашим кодом.

  1. вы пытаетесь получить доступ к class атрибутам, таким как MainWindow.checkB, MainWindow.checkBoxNone, et c. Их не существует. Вы должны использовать атрибуты instance , используя такие вещи, как self.checkB;
  2. , чтобы вышеупомянутая работа, вы также должны установить эти атрибуты, поэтому checkBoxNone = QCheckBox("None Selected") должен be self.checkBoxNone = QCheckBox("None Selected"), et c.
  3. вы подключаете checkBoxNone.stateChanged к функции, которая требует двух позиционных аргументов, но stateChanged() имеет только один (состояние) ; Сигнал no checkbox не возвращает текст;
  4. в ваших функциях вы не проверяете и не снимаете какие-либо другие флажки;
  5. даже при условии, что вы использовали правильные ссылки (self.checkBoxNone, et c), вы никогда не должны ставить галочку (или наоборот) в результате сигнала stateChanged, как вы это сделали в своем коде, потому что это приведет к рекурсии;
  6. QMainWindow имеет свою собственную разметку, Вы не можете установить свои собственные; Кроме того, вы уже собираетесь установить его для центрального виджета;

Для того, чтобы он работал, вы должны иметь некоторую ссылку на все созданные вами флажки, а затем применить желаемое состояние, оставаясь при этом очень внимательно относитесь к изменению состояния проверки каждого блока.

В следующем примере флажки «выбрать все» и «выбрать нет» отображаются частично отмеченными, если, соответственно, установлены не все флажки или хотя бы один .

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        grid = QGridLayout()
        # You *cannot* set a layout to a main window
        # self.setLayout(grid)

        positions = [(i,j) for i in range(5) for j in range(5)]
        wordlist = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y']


        # use a list to keep a reference to all checkboxes
        <b>self.checkBoxes = []</b>
        for position, <b>word</b> in zip(positions, wordlist): 
            checkB =(QCheckBox(word)) 
            checkB.setStatusTip("Crawling best singals for "+<b>word</b>+"." ) # set Statusbar
            checkB.stateChanged.connect(self.checkStates)
            grid.addWidget(checkB, *position)
            <b>self.checkBoxes.append(checkB)</b>

        <b>self.</b>checkBoxNone = QCheckBox("Select none")
        self.checkBoxNone.setCheckState(Qt.Unchecked)
        self.checkBoxNone.stateChanged.connect(
            partial(self.selectBoxes, False))
        grid.addWidget(self.checkBoxNone, 6, 1)

        <b>self.</b>checkBoxAll = QCheckBox("Select All")
        self.checkBoxAll.setCheckState(Qt.PartiallyChecked)
        self.checkBoxAll.stateChanged.connect(
            partial(self.selectBoxes, True))
        grid.addWidget(self.checkBoxAll, 6, 2)

        widget = QWidget()
        widget.setLayout(grid) 
        self.setCentralWidget(widget)      

        self.statusBar().showMessage('Ready')

    def checkStates(self):
        states = [c.isChecked() for c in self.checkBoxes]

        # temporarily block signals so that there is no recursive calls
        self.checkBoxAll.blockSignals(True)
        self.checkBoxNone.blockSignals(True)

        # set the "select all" fully checked too if all boxes are checked,
        # otherwise make it partially checked
        self.checkBoxAll.setCheckState(
            Qt.Checked if all(states) else Qt.PartiallyChecked)

        # set the "select none" unchecked only if all boxes are unchecked,
        # otherwise make it partially checked
        self.checkBoxNone.setCheckState(
            Qt.Unchecked if not any(states) else Qt.PartiallyChecked)

        # unblock signals back
        self.checkBoxAll.blockSignals(False)
        self.checkBoxNone.blockSignals(False)

    def selectBoxes(self, state):
        for check in self.checkBoxes:
            check.blockSignals(True)
            check.setChecked(state)
            check.blockSignals(False)
        self.checkStates()

Тем не менее, позвольте мне сказать вам, что использование флажка для того, чтобы делать то, что вы делаете, не рекомендуется, так как это нелогично, как визуально, так и с точки зрения взаимодействия. Лучше использовать кнопку для проверки всего, а другую для снятия отметки.
Также будьте осторожны при именовании переменных и атрибутов; например, checkAll и selectAll очень похожи, но они ссылаются на два разных и очень разных объекта: флажок и функцию; их имена также должны отражать эту разницу. Хотя несоблюдение этого принципа не представляет технической проблемы, оно может стать проблемой, когда число объектов (функций, атрибутов и т. Д. c) растет вместе с вашей программой: использование понятных и описательных имен улучшает читабельность (и умственную ссылку) , что является важным аспектом как для разработки , так и отслеживания проблем.
Та же концепция применима к циклам: не используйте wordlist для списка и элемента итератора.

...