JareBear
JareBear

Reputation: 487

Send state of a QCheckBox and a number when clicked

I'm trying to pass two separate variables via a QCheckBox clicked signal: its post-pressed state, and its index in the list.

For example, this is my code:

# pip install pyqt5
from PyQt5.QtMultimediaWidgets import *
from PyQt5.QtMultimedia import *
from functools import partial
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5 import *
import sys
batch_name = ['Test1', 'test2', 'test']
total_batches = 0
unfinished_batches = 0
class MainMenu(QWidget):
    def __init__(self, parent = None):
        global total_batches, unfinished_batches, batch_name
        super(MainMenu, self).__init__(parent)
        self.scroll = QScrollArea(self)
        self.scroll.setWidgetResizable(True)
        self.content = QWidget()
        self.scroll.setWidget(self.content)
        self.lay = QGridLayout(self.content)
        for i, j in enumerate(batch_name):
            self.btnName = QPushButton(j, self)
            self.btnName.setFlat(True)
            self.lay.addWidget(self.btnName, i, 1)
            self.check_box = QCheckBox(self)
            checkbox_index = partial(self.clickBox, i, i)
            self.check_box.stateChanged.connect(checkbox_index)
            self.lay.addWidget(self.check_box, i, 0)
            total_batches += 1
    def clickBox(self, state, index):
        print(index)
        print(state)
        global unfinished_batches, total_batches
        if state == Qt.Checked:
            unfinished_batches += 1
        else:
            unfinished_batches -= 1


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = MainMenu()
    main.show()
    sys.exit(app.exec_())

(Yes, I know I'm passing the index threw twice.)

So lets say, I press the first QCheckBox (Test1): I should get True for the state, and 0 for the index. If I press Test1 again, I expect to get False for the state, and again 0 for the index. For just one more example, if I press test (last QCheckBox) I should expect to get True for the state, and 2 for the index, and pressing it again, I should get False for the state, and again, 2 for the index.

The code above gives me the index, but it doesn't give me its state - that's what I'm stuck on. What I am expecting to happen if the QCheckBox is pressed then I should get True where I don't.

Upvotes: 1

Views: 270

Answers (2)

S. Nick
S. Nick

Reputation: 13691

Try it:

import sys
from functools import partial
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *


class MainMenu(QWidget):
    def __init__(self, parent = None):
        super(MainMenu, self).__init__(parent)

        batch_name = ['Test1', 'test2', 'test']
        lay = QGridLayout(self)

        for i, j in enumerate(batch_name):
            check_box = QCheckBox()
            lay.addWidget(check_box, i, 0)

            btnName = QPushButton(j)
            btnName.setFlat(True)
            btnName.setCheckable(True)
            btnName.clicked.connect(partial(self.btnCliced, i, j, check_box))
            lay.addWidget(btnName, i, 1)

            check_box.stateChanged.connect(partial(self.clickBox, i, j, btnName))            

    def clickBox(self, i, j, btnName, state):             
        print(f'clickBox:  i={i}, j={j}, state={state} : {bool(state)};')
        if state: btnName.setChecked(True)
        else: btnName.setChecked(False)

    def btnCliced(self, i, j, check_box, state):             
        print(f'btnCliced: i={i}, j={j}, state={state};')
        if state: check_box.setChecked(True)
        else: check_box.setChecked(False)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = MainMenu()
    main.show()
    sys.exit(app.exec_())

enter image description here

Upvotes: 1

ekhumoro
ekhumoro

Reputation: 120768

You're not using partial correctly. If both parameters are specified in partial, then both the arguments of clickBox will be overwritten with the value of i. What you need to do is only specify the value of the index argument, and allow the signal to supply the value of the state argument. This can be done using a keyword argument, like this:

    # checkbox_index = partial(self.clickBox, i, i)
    checkbox_index = partial(self.clickBox, index=i)

But note that state will be a value from the CheckState enum, so if you specifically want to get True/False, you could use a lambda instead:

    checkbox_index = lambda state, index=i: self.clickBox(state == Qt.Checked, index)

and clickState would need to look like this:

def clickBox(self, state, index):
    print(index)
    print(state)
    global unfinished_batches, total_batches
    if state == True:
        unfinished_batches += 1
    else:
        unfinished_batches -= 1

Upvotes: 1

Related Questions