Pyqt Mouse hovering on a QPushButton - python

I want to detect the hovering of the mouse on a QPushButton. For that I installed an event filter on my button. However the MouseMove event does not trigger exactly when the mouse is over the button. It seems it is sometimes triggered when I click the button on a location which is different from the previous one. To put it simply:
I move the mouse on the button: nothing happens.
I click: MouseButtonPressed event is triggered.
I move the mouse to another location on the button: nothing happens.
I click again: MouseButtonPressed is triggered, MouseMove too.
I would like to get the MouseMove triggered each time the mouse hovers the button. How do I do?
Here is my code:
import sys
from PyQt4 import QtCore
from PyQt4.QtGui import *
class eventFilterWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
widget = QWidget()
button = QPushButton("Trigger event!")
button.installEventFilter(self)
hbox = QHBoxLayout()
hbox.addWidget(button)
widget.setLayout(hbox)
self.setCentralWidget(widget)
self.show()
def eventFilter(self, object, event):
if event.type() == QtCore.QEvent.MouseButtonPress:
print "You pressed the button"
return True
elif event.type() == QtCore.QEvent.MouseMove:
print "C'mon! CLick-meeee!!!"
return True
return False
def main():
app = QApplication(sys.argv)
#myWindow = EventsWindow()
window = eventFilterWindow()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
EDIT:
In fact, MouseMove is triggered when the mouse is being moved while the QPushButton is pressed.

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

python pyqt5 mouseEvent and mouseLocation

I'm trying to make videogame macro with pyautogui and pyqt5
this is what I want
Press the button and hold it. (mouse pressed)
Drag somewhere outside the GUI window.
release it. (mouse released)
Get the mouse location when the mouse is released
but I couldn't find a way to connect mouse event with button clicks.
class MyWindow(QDialog, form_class):
def __init__(self):
super().__init__()
self.mouseLocation = {}
self.setupUi(self)
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
self.menuBtn.clicked.connect( lambda: self.addLocation('MenuBtn')) # ButtonEvents
self.traininBtn.pressed.connect( lambda: self.addLocation('TraininBtn'))
self.difficultyBtn.pressed.connect( lambda: self.addLocation('DifficultyBtn'))
self.lonewolfBtn.pressed.connect( lambda: self.addLocation('LonewolfBtn'))
def addLocation(self, name):
self.mouseLocation[name] = [pyautogui.position().x, pyautogui.position().y]
def mouseReleaseEvent(self, e):
print('BUTTON RELEASED')
if __name__ == "__main__":
app = QApplication(sys.argv)
myWindow = MyWindow()
myWindow.show()
app.exec_()

Using a dialog/window app with a SysTray icon: focus problem

I want to use a dialog together with the SysTrayIcon.
The reason for the app is running in a systray, and show the dialog when you press the icon button. The app will close entirely just from the menu option.
Problem to solve: when lose focus (eg:clicking outisde) he dialog should hide even if the dialog had a button to display a modal window
Please test the sample code, as it illustrates everything.
from PySide2.QtWidgets import *
import sys
message = '''
This is a dialog we wanna use together with the SysTrayIcon
The reason of the app is running in a systray, and show the
dialog when you press the icon button. The app will close
entirely from the menu option, explained below.
Clicking SysTray icon use:
1) Click left and right in icon it shows the app
and you can interact with it. If you click again it toggles
show/hide the app.
2) With Middle Click a menu shows up, and dialog hides.
From this menu you can close the app entirely.
PROBLEM TO SOLVE:
When lose focus(eg:clicking outisde) he dialog should hide
Even if the dialog had a button to display a modal window
'''
class LauncherDialog(QDialog):
def __init__(self, x=None, y=None, parent=None):
super(LauncherDialog, self).__init__(parent)
my_lbl = QLabel(message)
my_layout = QVBoxLayout()
my_layout.addWidget(my_lbl)
my_layout.setMargin(0)
self.setLayout(my_layout)
self.setMinimumHeight(630)
self.setMinimumWidth(360)
self.setWindowTitle("Launcher")
if x is not None and y is not None:
self.move(x, y)
class SystrayLauncher(object):
def __init__(self):
# Create the icon
w = QWidget() #just to get the style(), haven't seen other way
icon = w.style().standardIcon(QStyle.SP_MessageBoxInformation)
# Create the tray
self.tray = QSystemTrayIcon()
self.tray.setIcon(icon)
self.tray.setVisible(True)
self.tray_pos = self.tray.geometry()
left = self.tray_pos.left()
height = self.tray_pos.height()
self.menu = QMenu()
self.action = QAction("&Quit", None, triggered=QApplication.instance().quit)
self.tray.setContextMenu(self.menu)
self.launcher_window = LauncherDialog(x=left, y=height)
self.tray.activated.connect(self.handleLeftRightMiddleClick)
def handleLeftRightMiddleClick(self, signal):
if signal == QSystemTrayIcon.ActivationReason.MiddleClick:
self.menu.addAction(self.action) #show menu
self.launcher_window.hide()
elif signal == QSystemTrayIcon.ActivationReason.Trigger: #left / right clicks
self.menu.removeAction(self.action) #hide menu
if self.launcher_window.isHidden():
self.launcher_window.show()
else:
self.launcher_window.hide()
else: #doubleclick
pass
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setQuitOnLastWindowClosed(False)
sl = SystrayLauncher()
sys.exit(app.exec_())

How to restore focus on a widget after hidding then showing the parent widget?

I'm creating a launcher application (like Spotlight/Albert/Gnome-Do). I'm using Python 2.7 and Pyside. Made and used on Windows 10.
It is running in the background and listening to a shortcut with the keyboard (pip install keyboard). When the shortcut is called, a QObject signal calls the show method of my main widget.
My issue is that when the main widget gets hidden by pressing escape or return, next time the widget is shown, the focus will be in the QlineEdit and the user will be able to type its query straight away.
But when the widget is hidden by clicking outside widget (handled by filtering the QEvent WindowDeactivate), the focus won't be on my QLineEdit at next call, which ruins the user experience.
I've tried playing with activateWindow() or raise_(), but it doesn't change anything.
Heree here a simplified example code that shows my problem:
import sys
import keyboard
from PySide.QtCore import *
from PySide.QtGui import *
SHORTCUT = 'Ctrl+space'
class ShortcutThread(QObject):
signal = Signal()
class Launcher(QMainWindow):
def __init__(self, parent=None):
super(Launcher, self).__init__()
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Popup)
self.resize(500, 50)
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
self.layout_ = QHBoxLayout()
self.central_widget.setLayout(self.layout_)
self.search = QLineEdit()
self.layout_.addWidget(self.search)
def eventFilter(self, obj, event):
# Hide dialog when losing focus
if event.type() == QEvent.WindowDeactivate:
self.hide()
return super(Launcher, self).eventFilter(obj, event)
def keyPressEvent(self, e):
# Hide dialog when pressing escape or return
if e.key() in [Qt.Key_Escape, Qt.Key_Return]:
self.hide()
def main():
app = QApplication(sys.argv)
app.setQuitOnLastWindowClosed(False)
launcher = Launcher()
shortcut = ShortcutThread()
shortcut.signal.connect(launcher.show)
keyboard.add_hotkey(SHORTCUT, shortcut.signal.emit, args=[])
launcher.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
When I call the shortcut (Ctrl+Space here) and click elsewhere, next time I'll call the shortcut, the focus won't be set to the QLineEdit widget.
When the launcher is hidden by hitting return or escape, it does work as expected.

Is it possible to trigger a mousePressEvent artificially on a QWebView?

Due to an astronomically atrocious bug on PyQt4, I need to fire a mousePressEvent artificially on a QWebView as a last breath of hope. For some obscure reason, QWebView's linkClicked and urlChanged signals do not pass a QUrl when the clicked link has Javascript involved (It does not work on Youtube videos, for example) and when the link was clicked with the left mouse button. The QUrl can be perfectly accessed when the link was clicked with the middle and right buttons.
class CQWebView(QtWebKit.QWebView):
def mousePressEvent(self, event):
if type(event) == QtGui.QMouseEvent:
if event.button() == QtCore.Qt.LeftButton:
# FIRE A QtCore.Qt.MiddleButton EVENT HERE,
# SO THAT I CAN GET THE BLOODY LINK AFTERWARDS.
elif event.button() == QtCore.Qt.MiddleButton:
self.emit(QtCore.SIGNAL("OPEN_IN_NEW_TAB")) # Example
elif event.button() == QtCore.Qt.RightButton:
self.emit(QtCore.SIGNAL("XXX")) # Example
So, I literally want to "click artificially", click without clicking, just trigger the event of clicking with the middle right button on a link, so that I can catch the QUrl correctly.
You can do it using the QtTest module as well. Set an event filter on your web view and check for left click mouse events and send a middle mouse click
def __init__(...)
self.ui_web_view.installEventFilter(self)
def eventFilter(self, obj, event):
if obj == self.ui_web_view:
if event.type() == QtCore.QEvent.MouseButtonPress:
if event.button() == QtCore.Qt.LeftButton:
print 'Handled'
QtTest.QTest.mouseClick(self.ui_web_view, QtCore.Qt.MiddleButton, QtCore.Qt.NoModifier, event.pos())
return True
return False
I've managed to click with the middle button by clicking with the left button using the sendEvent method from QtGui.QApplication.
class CQWebView(QtWebKit.QWebView):
app = None
def __init__(self, app):
QtWebKit.QWebView.__init__(self)
CQWebView.app = app
def mousePressEvent(self, event):
if type(event) == QtGui.QMouseEvent:
if event.button() == QtCore.Qt.LeftButton:
CQWebView.app.sendEvent(self, QtGui.QMouseEvent(event.type(), event.pos(), QtCore.Qt.MiddleButton, event.buttons(), event.modifiers()))
elif event.button() == QtCore.Qt.MiddleButton:
self.emit(QtCore.SIGNAL("linkClicked(const QUrl&)")) # Problem
elif event.button() == QtCore.Qt.RightButton:
self.emit(QtCore.SIGNAL("XXX")) # Example
I just needed to pass the instance of the QApplication to the instance of the custom QWebView on instantiation:
def compose_tab(self, index):
self.tabs[index].append(CQWebView(self))
This way, I click on the QWebView with the left mouse button and I click artificially on it with the middle button. The problem is that doing so I'm overriding the default behavior of the linkClicked and urlChanged signals from the QWebView. Even though I can emit these signals, I can't have access to the address of the link that was clicked, since by accessing QWebView.url() only gives me the present QUrl, and not the future clicked one.
Really frustrating.

PyQt4 MouseMove event without MousePress

I need to catch when a User moves the mouse over the GUI, but not when they're holding down the mouse button (which would do something different).
I can't find any conveniant method to do this,
except to periodically find the mouse position and check it to it's previous position...
Which would suck.
The mouseMoveEvent is only called when the mouse is moved whilst the left mouse button is pressed,
unless ofcourse the widget has 'mouse tracking'. Mouse tracking is not an option for me, because the GUI must behave differently when the mouse is moved and the left mouse button is pressed.
Are there any inbuilt methods to do this?
(or just any clever ideas?)
eg:
Is there a way to check if the left mouse button is being pressed at any time?
Or a 'mouse hover' event that can be applied to a QRect (coordinates)?
Muchas gracias.
Windows 7 (32)
python 2.7
PyQt4
The most straightforward way to do this is to install an event filter on qApp:
from PyQt4 import QtGui, QtCore
class Window(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
widget = QtGui.QWidget(self)
layout = QtGui.QVBoxLayout(widget)
self.edit = QtGui.QLineEdit(self)
self.list = QtGui.QListWidget(self)
layout.addWidget(self.edit)
layout.addWidget(self.list)
self.setCentralWidget(widget)
def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.MouseMove:
if event.buttons() == QtCore.Qt.NoButton:
pos = event.pos()
self.edit.setText('x: %d, y: %d' % (pos.x(), pos.y()))
else:
pass # do other stuff
return QtGui.QMainWindow.eventFilter(self, source, event)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
win = Window()
win.show()
app.installEventFilter(win)
sys.exit(app.exec_())
As people have said, the correct approach seems to be to call setMouseTracking(True) on the widget. What I'd like to add is that, having done this, you can distinguish between a mouse motion and a mouse drag as follows:
def mouseMoveEvent(self, event):
if event.buttons() == QtCore.Qt.NoButton:
print "Simple mouse motion"
elif event.buttons() == QtCore.Qt.LeftButton:
print "Left click drag"
elif event.buttons() == QtCore.Qt.RightButton:
print "Right click drag"
call setMouseTracking(True) method first. Then mouseMoveEvent will be fired without any button pressed.
It seems you've misunderstood what mouseTracking does. It only causes mouseMoveEvent to be fired, nothing else. In other words, it's exactly what you need.
Check the event's buttons() to see if any button was pressed:
For mouse move events, this is all buttons that are pressed down.

Categories

Resources