I'm trying to select/unselect Qcheckbox by clicking on a label and moving the mouse on other Checkboxes
What I would like is, for example, to click on the '0' and maintaining the mouse clicked and move it down on the '1', '2'... by moving on those checkboxes they must change their value (True to False).
I don't understand how to use the mouseMoveEvent.
I made a minimal code to start with
import sys
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class CheckBox(QCheckBox):
def __init__(self, *args, **kwargs):
QCheckBox.__init__(self, *args, **kwargs)
def mouseMoveEvent(self,event):
if event.MouseButtonPress == Qt.MouseButton.LeftButton:
self.setChecked(not self.isChecked())
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__()
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.mainHBOX = QVBoxLayout()
self.CB_list = []
for i in range(20):
CB = CheckBox(str(i))
CB.setChecked(True)
self.CB_list.append(CB)
self.mainHBOX.addWidget(CB)
self.centralWidget.setLayout(self.mainHBOX)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())

There are two problems in your code.
First of all, when a widget receives a mouse button press, it normally becomes the "mouse grabber", and from that moment on only that widget will receive mouse move events until the button is released.
Then you didn't properly check the buttons:
event.MouseButtonPressis a constant that indicates a mouse press event,Qt.MouseButton.LeftButtonis another constant indicating the left button of the mouse; you practically compared two different constants, which would have the same result as in doingif 2 == 1:.A
mouseMoveEventwill always returnevent.type() == event.MouseMove, so there's no need to check for it, but for the current buttons: for mouse press and release events, the button that causes the event is returned byevent.button(), while, for move events, the currently pressed buttons are returned byevent.buttons()(plural). Remember this difference, becauseevent.button()(singular) will always returnNoButtonfor a mouse move events (which is pretty obvious if you think about it, since the event is not generated by a button).With that in mind, what you could do is to check the child widgets of the parent corresponding to the mouse position mapped to it.
In order to achieve this, you have to ensure that the mouse button has been actually pressed on the label (using style functions) and set an instance attribute as a flag to know if the movement should be tracked for other siblings. Note that in the following example I also used another flag to check for children that are direct descendants of the parent: if that flag is set, only siblings of the first pressed checkbox will be toggled, if another
CheckBoxinstance is found but its parent is a child of the first one, no action is performed.The only drawback with this implementation is that it won't work if you need to do this for items that are children of other parents (they share a common ancestor, but not the same parent).
In that case, you need to install an event filter for all check boxes for which you need this behavior and implement the above functions accordingly, with the difference that you need to use the top level window to map mouse coordinates (
self.mapTo(self.window(), event.pos())) and use that window'schildAt().Finally, consider that
SE_CheckBoxContentsreturns the full area of the contents, even if the shown text is smaller than the available space; the default behavior with most styles is to react to click events only when done inside the actual shown contents (the icon and/or the bounding rect of the text). If you want to revert to the default behavior, you need to construct another rectangle forSE_CheckBoxClickRect(which is the whole clickable area including the indicator) and check if the mouse is within the intersected rectangle of both:The
&binary operator for QRects works in the same way as bitwise operators, in their logical sense: it only returns a rectangle that is contained by both source rectangles. It's literal function isintersected().