Reputation: 47
I have a problem with QCheckBox.
I am trying to connect a boolean variable to a QCheckBox so that when I change the boolean variable, the QCheckBox will be automatically checked or unchecked.
My Question is similar to the Question below but in opposite way.
question: Python3 PyQt4 Creating a simple QCheckBox and changing a Boolean variable
I just copy one solution from that question to here.
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class SelectionWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.ILCheck = False
ILCheckbox = QCheckBox(self)
ILCheckbox.setCheckState(Qt.Unchecked)
ILCheckbox.stateChanged.connect(self.ILCheckbox_changed)
MainLayout = QGridLayout()
MainLayout.addWidget(ILCheckbox, 0, 0, 1, 1)
self.setLayout(MainLayout)
def ILCheckbox_changed(self, state):
self.ILCheck = (state == Qt.Checked)
print(self.ILCheck)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = SelectionWindow()
window.show()
window.ILCheck = True
sys.exit(app.exec_())
In this case, once I set ILCheck to True, QCheckBox will be checked.
Any help would be appreciated!!!
Thanks!!!!
Update:
I am using MVC on my project, the code above just a example show what I need. The bool value ILCheck
will be use in other place, and I don't want call ILCheckBox
in my model.
I expect that if I modify the value of ILCheck
, ILCheckBox
will react correctlly.
Update:
Thanks for all your reply and help. All your solution is great!!! The way I need is more like a Modeling-View solution so that I can separate modeling part from gui part. When I want to update something, I just need update modeling, and don't need pay attention to what gui looks like. I can't set this Bool property in View Class so that I can't use this solution.
I am not sure MVC is suitable in PyQT. I have a close solution like below with a problem.
from PyQt4 import QtGui, QtCore, uic
import sys
class CellList(QtGui.QStandardItemModel):
def __init__(self, cells = [], parent = None):
QtGui.QStandardItemModel.__init__(self, parent)
self.__cells = cells
self.add(cells)
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
return QtCore.QString("Cell id List")
def flags(self, index):
return QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
def add(self, cells):
for i in xrange(0, len(cells)):
item = QtGui.QStandardItem('Cell %s' % cells[i][0])
if (cells[i][1]):
item.setCheckState(QtCore.Qt.Checked)
else:
item.setCheckState(QtCore.Qt.Unchecked)
item.setCheckable(True)
self.appendRow(item)
def update(self, cells = None):
# TODO: Making this working with out clean all old Cell
self.clear()
if cells is None:
cells = self.__cells
else:
print "hi"
self.__cells = cells
print cells
self.add(cells)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
listView = QtGui.QListView()
listView.show()
data = [[85, True], (105, True), (123, False)]
model = CellList(data)
listView.setModel(model)
data[0][1] = False
model.update(data)
sys.exit(app.exec_())
There is a problem comes with this solution and I can't solve. I think only a view can set a Model. I am not sure if I can set a model to a single QCheckBox
.
.
Upvotes: 0
Views: 3034
Reputation: 14360
As Avaris shows in his/her answer, emulating the overload of operator =
is a good start for solving the question. But yet still the problem of the code being
added to the SelectionWindow
class.
But since we are using Qt
, lets implement a custom QObject
that represents our "smart" boolean variable which will emit a signal when
change its value.
class SmartBool(QObject):
valueChanged = pyqtSignal(bool) # Signal to be emitted when value changes.
def __init__(self):
super(SmartBool, self).__init__() # Call QObject contructor.
self.__value = False # False initialized by default.
@property
def value(self):
return self.__value
@value.setter
def value(self, value):
if self.__value != value:
self.valueChanged.emit(value) # If value change emit signal.
self.__value = value
Now your code needs only a couple of changes:
replace the line:
self.ILCheck = False
by:
self.ILCheck = SmartBool()
and connect the signal and the slot, add the line to the _ _ init _ _ some where after the line above. IMPORTANT, you are not bind to make the connection from within the SelectionWindow
class
self.connect(self.ILCheck, SIGNAL("valueChanged(bool)"), ILCheckbox, SLOT("setChecked(bool)"))
for testing the result just add:
window.ILCheck.value = True
to your "main" and you will see the checkbox checked next time you run the example.
The full code example was added to the end for stetical reasons
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class SmartBool(QObject):
valueChanged = pyqtSignal(bool) # Signal to be emitted when value changes.
def __init__(self, value=False):
super(SmartBool, self).__init__() # Call QObject contructor.
self.__value = value # False initialized by default.
@property
def value(self):
return self.__value
@value.setter
def value(self, value):
if self.__value != value:
self.valueChanged.emit(value) # If value change emit signal.
self.__value = value
class SelectionWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.ILCheck = SmartBool() # Your steroides bool variable.
ILCheckbox = QCheckBox(self)
self.connect(self.ILCheck, SIGNAL("valueChanged(bool)"), ILCheckbox, SLOT("setChecked(bool)"))
ILCheckbox.setCheckState(Qt.Unchecked)
ILCheckbox.stateChanged.connect(self.ILCheckbox_changed)
MainLayout = QGridLayout()
MainLayout.addWidget(ILCheckbox, 0, 0, 1, 1)
self.setLayout(MainLayout)
def ILCheckbox_changed(self, state):
self.ILCheck = (state == Qt.Checked)
print(self.ILCheck)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = SelectionWindow()
window.show()
window.ILCheck.value = True
sys.exit(app.exec_())
Upvotes: 3
Reputation: 5177
just use ILCheckbox.setCheckState(Qt.Checked)
after calling ILCheck.
You don't neet signals here since you can call a slot sirectly.
If you want to do use this feature more than once, you should consider writing a setter which changes the state of self.ILCheck
and emits a signal.
Edit after your clarification:
your_properly_named_anddefine_signal.emit()
. For more information about signal definition see e.g. http://www.pythoncentral.io/pysidepyqt-tutorial-creating-your-own-signals-and-slots/. __init__()
of your controller class.Upvotes: 0
Reputation: 36715
property
is the way to define a variable that does additional work upon assigning/accessing. Below is the code modified for that purpose. It changes ILCheck
to a property such that it'll also update the checkbox upon assigning. Proper error checking for .setter
is left out but most probably needed.
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class SelectionWindow(QWidget):
def __init__(self, parent=None):
super(SelectionWindow, self).__init__(parent)
self._ILCheck = False
self.ILCheckbox = QCheckBox(self)
self.ILCheckbox.setCheckState(Qt.Unchecked)
self.ILCheckbox.stateChanged.connect(self.ILCheckbox_changed)
MainLayout = QGridLayout()
MainLayout.addWidget(self.ILCheckbox, 0, 0, 1, 1)
self.setLayout(MainLayout)
def ILCheckbox_changed(self, state):
self._ILCheck = (state == Qt.Checked)
print(self.ILCheck)
@property
def ILCheck(self):
return self._ILCheck
@ILCheck.setter
def ILCheck(self, value):
self._ILCheck = value
self.ILCheckbox.setChecked(value)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = SelectionWindow()
window.show()
window.ILCheck = True
sys.exit(app.exec_())
Upvotes: 1