How to Check Mousebuttonpress Event in Pyqt6

How to check MouseButtonPress event in PyQt6?

One of the main changes that PyQt6 enums use python enums so you must use the enumeration name as an intermediary, in your case MouseButtonPress belongs to the Type enum and RightButton to MouseButtons so you must change it to:

def eventFilter(self, QObject, event):
if event.type() == QEvent.Type.MouseButtonPress:
if event.button() == Qt.MouseButtons.RightButton:
print("Right button clicked")

return True

How to catch left and right mouse click event on QTableWidget in PyQt5?

Using the cellClicked signal won't be enough, because it only works for the left mouse button. Also, your function doesn't actually check anything, as both Qt.LeftButton and Qt.RightButton are constants and you were practically doing something like this:

    def tablewidget_click(self):
if 1:
print('hello')
if 2:
print('hi')

Using an event filter was the right choice, but I don't understand why you would call self.mousePressEvent(): a QMouseEvent is expected as argument, and you should normally not call event handlers manually. Also, calling self.tableWidget.viewport() does not "create" a viewport, it just returns it, as all scroll area based widgets have one.

Here's a working example:

class Test(QtWidgets.QWidget):
def __init__(self):
super().__init__()
layout = QtWidgets.QVBoxLayout(self)
self.clipboardLabel = QtWidgets.QLabel()
layout.addWidget(self.clipboardLabel)
self.tableWidget = QtWidgets.QTableWidget(10, 10)
layout.addWidget(self.tableWidget)
self.tableWidget.viewport().installEventFilter(self)

def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.MouseButtonPress:
if event.button() == QtCore.Qt.LeftButton:
index = self.tableWidget.indexAt(event.pos())
if index.data():
self.clipboardLabel.setText(index.data())
elif event.button() == QtCore.Qt.RightButton:
index = self.tableWidget.indexAt(event.pos())
if index.isValid():
item = self.tableWidget.itemFromIndex(index)
if not item:
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setItem(index.row(), index.column(), item)
item.setText(self.clipboardLabel.text())
return super().eventFilter(source, event)

QMouseEvent' object has no attribute 'pos'

Qt6 has refactored the event inputs API to adapt to new technologies (read https://www.qt.io/blog/input-events-in-qt-6 for more information) so it has introduced new base classes such as QSinglePointEvent from which QMouseEvent inherits that have the position() method that returns the position of the event (in this case the mouse). Even so, Qt6 has the pos() method that is redundant but is maintained for compatibility but it seems that PyQt6 has eliminated it which seems like a bug since PySide6 still maintains it having compatibility with Qt6. So in this case you should use position() instead of pos().

PyQt6 Isn't calling any events for hovering over a frame

First of all it should be noted that clicked is not an event but a signal. The button clicked signal is emitted when the button receives the MouseButtonRelease event.

In this answer I will show at least the following methods to implement the clicked signal in the QFrame.

  • Override mouseReleaseEvent

    import sys

    from PyQt6.QtCore import pyqtSignal, pyqtSlot
    from PyQt6.QtWidgets import QApplication, QFrame, QHBoxLayout, QLabel, QWidget

    class Frame(QFrame):
    clicked = pyqtSignal()

    def mouseReleaseEvent(self, event):
    super().mouseReleaseEvent(event)
    self.clicked.emit()

    class MainApp(QWidget):
    def __init__(self):
    super().__init__()

    self.setWindowTitle("Test Window")
    self.resize(300, 200)

    self.outerLayout = QHBoxLayout(self)
    self.outerLayout.setContentsMargins(50, 50, 50, 50)

    self.frame = Frame()
    self.frame.setStyleSheet("background-color: lightblue;")

    self.label = QLabel(text="Example Frame")

    self.innerLayout = QHBoxLayout(self.frame)
    self.innerLayout.addWidget(self.label)

    self.outerLayout.addWidget(self.frame)

    self.frame.clicked.connect(self.handle_clicked)

    @pyqtSlot()
    def handle_clicked(self):
    print("frame clicked")

    if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainApp()
    window.show()
    sys.exit(app.exec())
  • Use a eventFilter:

    import sys

    from PyQt6.QtCore import QEvent
    from PyQt6.QtWidgets import QApplication, QFrame, QHBoxLayout, QLabel, QWidget

    class MainApp(QWidget):
    def __init__(self):
    super().__init__()

    self.setWindowTitle("Test Window")
    self.resize(300, 200)

    self.outerLayout = QHBoxLayout(self)
    self.outerLayout.setContentsMargins(50, 50, 50, 50)

    self.frame = QFrame()
    self.frame.setStyleSheet("background-color: lightblue;")

    self.label = QLabel(text="Example Frame")

    self.innerLayout = QHBoxLayout(self.frame)
    self.innerLayout.addWidget(self.label)

    self.outerLayout.addWidget(self.frame)

    self.frame.installEventFilter(self)
    # for move mouse
    # self.frame.setMouseTracking(True)

    def eventFilter(self, obj, event):
    if obj is self.frame:
    if event.type() == QEvent.Type.MouseButtonPress:
    print("press")
    # for move mouse
    # elif event.type() == QEvent.Type.MouseMove:
    # print("move")
    elif event.type() == QEvent.Type.MouseButtonRelease:
    print("released")
    return super().eventFilter(obj, event)

    if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainApp()
    window.show()
    sys.exit(app.exec())

Plus

A big part of the error of the O attempt is that by doing window.installEventFilter(window) it is only listening for events from the window itself and not from the QFrame. The solution is to send the QFrame events to the class window.frame.installEventFilter(window).

On the other hand, do not use numerical codes but the enumerations since they are more readable.

On the other hand, for the mouse event, the Qt::WA_Hover attribute must be enabled(Read the docs for more information)

import sys

from PyQt6.QtCore import QEvent, Qt
from PyQt6.QtWidgets import QApplication, QFrame, QHBoxLayout, QLabel, QWidget

class MainApp(QWidget):
def __init__(self):
super().__init__()

self.setWindowTitle("Test Window")
self.resize(300, 200)

self.outerLayout = QHBoxLayout(self)
self.outerLayout.setContentsMargins(50, 50, 50, 50)

self.frame = QFrame()
self.frame.setStyleSheet("background-color: lightblue;")

self.label = QLabel(text="Example Frame")

self.innerLayout = QHBoxLayout(self.frame)
self.innerLayout.addWidget(self.label)

self.outerLayout.addWidget(self.frame)

self.frame.setAttribute(Qt.WidgetAttribute.WA_Hover)
self.frame.installEventFilter(self)

def eventFilter(self, obj, event):
if obj is self.frame:
if event.type() == QEvent.Type.HoverEnter:
print("enter")
elif event.type() == QEvent.Type.HoverMove:
print("move")
elif event.type() == QEvent.Type.HoverLeave:
print("leave")
return super().eventFilter(obj, event)

if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainApp()
window.show()
sys.exit(app.exec())

Pyqt Mouse MouseButtonDblClick event

It's kind of a hack, but it should do the trick.
Also, I used new-style signals instead of your event filter, something you should consider.
Here, the ClickHandler class counts the number of clicks between the first click and the timeout event of its timer.

from PyQt4 import QtCore, QtGui

class ClickHandler():
def __init__(self, time):
self.timer = QtCore.QTimer()
self.timer.setInterval(time)
self.timer.setSingleShot(True)
self.timer.timeout.connect(self.timeout)
self.click_count = 0

def timeout(self):
if self.click_count == 1:
print('Single click')
elif self.click_count > 1:
print('Double click')
self.click_count = 0

def __call__(self):
self.click_count += 1
if not self.timer.isActive():
self.timer.start()

class MyDialog(QtGui.QDialog):
def __init__(self, parent=None):
super(MyDialog, self).__init__(parent)

self.button1 = QtGui.QPushButton("Button 1")
hbox = QtGui.QHBoxLayout()
hbox.addWidget(self.button1)
self.setLayout(hbox)

self.click_handler = ClickHandler(300)
self.button1.clicked.connect(self.click_handler)

if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = MyDialog()
w.show()
sys.exit(app.exec_())

EDIT : A second cleaner version with a CustomButton class that handles left and right click signals:

from PyQt4 import QtCore, QtGui

class CustomButton(QtGui.QPushButton):

left_clicked= QtCore.pyqtSignal(int)
right_clicked = QtCore.pyqtSignal(int)

def __init__(self, *args, **kwargs):
QtGui.QPushButton.__init__(self, *args, **kwargs)
self.timer = QtCore.QTimer()
self.timer.setInterval(250)
self.timer.setSingleShot(True)
self.timer.timeout.connect(self.timeout)
self.left_click_count = self.right_click_count = 0

def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
self.left_click_count += 1
if not self.timer.isActive():
self.timer.start()
if event.button() == QtCore.Qt.RightButton:
self.right_click_count += 1
if not self.timer.isActive():
self.timer.start()

def timeout(self):
if self.left_click_count >= self.right_click_count:
self.left_clicked.emit(self.left_click_count)
else:
self.right_clicked.emit(self.right_click_count)
self.left_click_count = self.right_click_count = 0

class MyDialog(QtGui.QDialog):
def __init__(self, parent=None):
super(MyDialog, self).__init__(parent)
self.button1 = CustomButton("Button 1")
hbox = QtGui.QHBoxLayout()
hbox.addWidget(self.button1)
self.setLayout(hbox)
self.button1.left_clicked[int].connect(self.left_click)
self.button1.right_clicked[int].connect(self.right_click)

def left_click(self, nb):
if nb == 1: print('Single left click')
else: print('Double left click')

def right_click(self, nb):
if nb == 1: print('Single right click')
else: print('Double right click')

if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = MyDialog()
w.show()
sys.exit(app.exec_())

PyQt6 - How to check a checkbox within table view when selecting an item

Thanks to: @musicamante ;

I was able to solve the issue by modifying my selection changed method and singleitem clicked method as follows;

     def tableSelectionChanged(
self, selected: QtCore.QItemSelection, deselected: QtCore.QItemSelection
):
"""Catch Selection changed behaviour"""

for index in selected.indexes():
self.filter_proxy_model.setData(index, Qt.CheckState.Checked, Qt.ItemDataRole.CheckStateRole)
for index in deselected.indexes():
self.filter_proxy_model.setData(index, Qt.CheckState.Unchecked, Qt.ItemDataRole.CheckStateRole)

def tableSingleClicked(self, modelIndex: QtCore.QModelIndex):
"""Single item clicked/checked in the tableview

Select or Unselect item when checkbox is checked or unchecked.

"""
# CheckState key is 10 in itemData - Not read doc for info
# check_state will be Qt.CheckState "enum value" when checkbox item is checked.
# check_state will be Qt.CheckState "enum" when item selected.
# only checkbox item selection is needed, so integer value will consider in here and other ignored which isn't needed.
check_state = self.filter_proxy_model.itemData(modelIndex).get(10)
if (
check_state == 2
and modelIndex not in self.ui.tableView.selectedIndexes()
) or (
check_state == 0
and modelIndex in self.ui.tableView.selectedIndexes()
):
self.ui.tableView.selectionModel().select(
modelIndex, QtCore.QItemSelectionModel.SelectionFlag.Toggle
)

PyQt: eventFilter to get mouse position in a semi-transparent window

Your 4 questions:

1) I want to make: a semi-transparent fullscreen window (rgba(0,0,0,180)).

Yes, you can. Please use QWidget.setWindowOpacity (self, float level).

2) I want to make: while moving mouse, display absolute position on label.

I recommend using QWidget.mouseMoveEvent (self, QMouseEvent) to get current position your mouse and enable QWidget.setMouseTracking (self, bool enable) for track all mouse movement.

QWidget.setMouseTracking (self, bool enable)

QWidget.mouseMoveEvent (self, QMouseEvent)

3) I want to make: user can press on it to get the absolute position of the mouse.

Using QWidget.mousePressEvent (self, QMouseEvent) to track when mouse press.

4) However I cannot achieve the second one. When moving mouse on it, label won't update mouse's position. But I found when moving out of label (after removing layout.setMargin(0) and layout.setSpacing(0)), it works.

Because in default layout height of QLabel has spacing & margin, then real area isn't all area widget solve it is your solution is OK.

Full example for your solution:

import sys
from PyQt4 import QtGui, QtCore

class QCustomLabel (QtGui.QLabel):
def __init__ (self, parent = None):
super(QCustomLabel, self).__init__(parent)
self.setMouseTracking(True)
self.setTextLabelPosition(0, 0)
self.setAlignment(QtCore.Qt.AlignCenter)

def mouseMoveEvent (self, eventQMouseEvent):
self.setTextLabelPosition(eventQMouseEvent.x(), eventQMouseEvent.y())
QtGui.QWidget.mouseMoveEvent(self, eventQMouseEvent)

def mousePressEvent (self, eventQMouseEvent):
if eventQMouseEvent.button() == QtCore.Qt.LeftButton:
QtGui.QMessageBox.information(self, 'Position', '( %d : %d )' % (self.x, self.y))
QtGui.QWidget.mousePressEvent(self, eventQMouseEvent)

def setTextLabelPosition (self, x, y):
self.x, self.y = x, y
self.setText('Please click on screen ( %d : %d )' % (self.x, self.y))

class QCustomWidget (QtGui.QWidget):
def __init__ (self, parent = None):
super(QCustomWidget, self).__init__(parent)
self.setWindowOpacity(0.7)
# Init QLabel
self.positionQLabel = QCustomLabel(self)
# Init QLayout
layoutQHBoxLayout = QtGui.QHBoxLayout()
layoutQHBoxLayout.addWidget(self.positionQLabel)
layoutQHBoxLayout.setMargin(0)
layoutQHBoxLayout.setSpacing(0)
self.setLayout(layoutQHBoxLayout)
self.showFullScreen()

myQApplication = QtGui.QApplication(sys.argv)
myQTestWidget = QCustomWidget()
myQTestWidget.show()
myQApplication.exec_()

Pyqt Mouse hovering on a QPushButton

I found the answer. I was misled as I was searching an event containing the keyword Mouse in it. The event I was looking for actually is QtCore.QEvent.HoverMove.



Related Topics



Leave a reply



Submit