I try to change cursor icon when the Ctrl button is pressed. The problem is, that if you press and hold down a button, the keyPressEvent method is not called. If you press two buttons at once, e.g. Ctrl+Shift, then it works as expected.
Test environment: system SUSE 12.2, python 3.6.4, pyqt5 5.11.3 (also tested pyqt5 5.9.2).
This is a minimal (not)working example:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication, QWidget
class Example(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(300, 300, 300, 220)
self.show()
def keyPressEvent(self, event):
print('Press')
def keyReleaseEvent(self, event):
print('Release')
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Once pressing and holding Ctrl button, the 'Press' should be printed. However, it is not until you release the button or click another one simultaneously.
I noticed different behavior for different keys. Both left and right Ctrl behave the same, also the left Shift, but the right Shift behaves as desired.
def keyPressEvent(self, event):
print('Press')
QApplication.setOverrideCursor(Qt.WaitCursor)
def keyReleaseEvent(self, event):
print('Release')
QApplication.restoreOverrideCursor()
Related
I used PyQt5 to set a shortcut to a button.
self.but2.setShortcut('Ctrl+Shift+Y')
As long as the window is active in Windows, the shotcut works just fine, but when I deselect or minimize the window, the shortcut stops working.
Is it possible to make this shortcut working when the window is not active/minimized?
You will need to use a library that detects inputs and activate the button using that.
You could use pynput:
https://pypi.org/project/pynput/
Here is an example, with code from https://pythonpyqt.com/pyqt-button/ and the pynput documentation, that toggles a pyQt close window button with your keyboard shortcut:
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
from PyQt5.QtGui import QIcon
import sys
from pynput import keyboard
class PushButton(QWidget):
def __init__(self):
super(PushButton, self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("PushButton")
self.setGeometry(400,400,300,260)
self.closeButton = QPushButton(self)
self.closeButton.setText("Close") #text
self.closeButton.setIcon(QIcon("close.png")) #icon
self.closeButton.setShortcut('Ctrl+D') #shortcut key
self.closeButton.clicked.connect(self.close)
self.closeButton.setToolTip("Close the widget") #Tool tip
self.closeButton.move(100,100)
def hotkey(self):
def on_activate():
self.closeButton.click()
def for_canonical(f):
return lambda k: f(l.canonical(k))
hotkey = keyboard.HotKey(
keyboard.HotKey.parse('<ctrl>+<shift>+y'),
on_activate)
l = keyboard.Listener(
on_press=for_canonical(hotkey.press),
on_release=for_canonical(hotkey.release)
)
l.start()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = PushButton()
ex.show()
ex.hotkey()
sys.exit(app.exec_())
I use KDE on Manjaro linux. I have this script in python to turn off touchpad:
#!/usr/bin/python
import sys
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication
from PyQt5.QtCore import QCoreApplication
from subprocess import call
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
qbtn = QPushButton('On', self)
qbtn.clicked.connect(self.handleButtonOn)
qbtn.resize(qbtn.sizeHint())
qbtn.move(25, 50)
qbtn = QPushButton('Off', self)
qbtn.clicked.connect(self.handleButtonOff)
qbtn.resize(qbtn.sizeHint())
qbtn.move(125, 50)
self.setGeometry(300, 300, 250, 100)
self.setWindowTitle('Touchpad On/Off')
self.show()
def handleButtonOn(self, event):
print ('On')
call(["synclient", "touchpadoff=0"])
call(["notify-send", "Your touchpad is set to ON"])
self.destroy()
def handleButtonOff(self, event):
print ('Off')
call(["synclient", "touchpadoff=1"])
call(["notify-send", "Your touchpad is set to OFF"])
self.destroy()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
It's works almost perfect (turn off my touchpad) but when I start script it's turn off my power button so I can't turn off computer by this button.
There is a problem with Yakuake too, can't write in this terminal. Finally i've start some other terminal for example "konsole" and turn off computer by shutdown command.
I'm new in python. How to make this work OK. I need turn off my touchpad, I use external mouse.
I can't reproduce your issue with power button, but I found out that self.destroy() is causing your script to freeze in some corrupted-not-responding-to-SIGINT state. Replacing self.destroy() with self.close() makes it work on my machine.
Please try replacing self.destroy() with self.close().
I have tried to implement in Pyside the method described in How to distinguish between mouseReleaseEvent and mousedoubleClickEvent on QGrapnhicsScene, but I had to add a crufty flag to keep it from showing single click after the second button release in a double click.
Is there a better way?
import sys
from PySide import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
"""an attempt to implement
https://stackoverflow.com/questions/18021691/how-to-distinguish-between-mousereleaseevent-and-mousedoubleclickevent-on-qgrapn
main()
connect(timer, SIGNAL(timeout()), this, SLOT(singleClick()));
mouseReleaseEvent()
timer->start();
mouseDoubleClickEvent()
timer->stop();
singleClick()
// Do single click behavior
"""
self.timer = QtCore.QTimer()
self.timer.setSingleShot(True)
# had to add a "double_clicked" flag
self.double_clicked = False
self.timer.timeout.connect(self.singleClick)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Single click, double click')
self.show()
def mouseReleaseEvent(self, event):
if not self.double_clicked:
self.timer.start(200)
else:
self.double_clicked = False
def mouseDoubleClickEvent(self, event):
self.timer.stop()
self.double_clicked = True
print 'double click'
def singleClick(self):
print 'singleClick'
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Well, as you've discovered, the original description is incomplete.
It gives a solution for distinguishing between the first click of a double-click and single-click, but not the second click of a double-click and a single-click.
The simplest solution for distinguishing the second click is to use a flag.
PS: you could slightly improve your example by using QtGui.qApp.doubleClickInterval for the timer interval.
How can i simulate mouse release action using Qt.SIGNAL?
I need to simulate a mouseRelease without user's interaction.
Thanks in advance!
Here is an example using the clicked signal of a QPushButton:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from PyQt4 import QtGui, QtCore
class MyWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.pushButtonSimulate = QtGui.QPushButton(self)
self.pushButtonSimulate.setText("Simulate Mouse Release!")
self.pushButtonSimulate.clicked.connect(self.on_pushButtonSimulate_clicked)
self.layoutHorizontal = QtGui.QHBoxLayout(self)
self.layoutHorizontal.addWidget(self.pushButtonSimulate)
#QtCore.pyqtSlot()
def on_pushButtonSimulate_clicked(self):
mouseReleaseEvent = QtGui.QMouseEvent(
QtCore.QEvent.MouseButtonRelease,
self.cursor().pos(),
QtCore.Qt.LeftButton,
QtCore.Qt.LeftButton,
QtCore.Qt.NoModifier,
)
QtCore.QCoreApplication.postEvent(self, mouseReleaseEvent)
def mouseReleaseEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
print "Mouse Release"
super(MyWindow, self).mouseReleaseEvent(event)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('MyWindow')
main = MyWindow()
main.show()
sys.exit(app.exec_())
You can use:
from PyQt4.QtTest import QTest
#(...) Where you want to release
QTest.mouseRelease(widget_to_release, Qt.LeftButton)
This will release the mouse at the center of the widget.
There are also methods for mousePress(), mouseClick(), and others. However, if you're testing Drag & Drop on Windows, be careful that the equivalent QTest.mousePress() will block, since QDrag.exec_() blocks.
I'm currently connecting this signal with a function that handles the click. For example:
QtCore.QObject.connect(self.ui.webView, QtCore.SIGNAL("linkClicked (const QUrl&)"), self.navigate)
def navigate(self, url):
#do something
What I'd like to is for the for the navigate function to know if the link was clicked on by the left or right mouse button. Something like
def navigate(self, url, event):
if event == Qt.LeftClick:
#do something
if event == Qt.MidClick:
#do something else
Is this possible?
Another method is reimplementing the mousePressEvent and filtering mouse events there:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from PyQt4 import QtCore, QtGui
class myWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(myWindow, self).__init__(parent)
self.label = QtGui.QLabel(self)
self.label.setText("Click Me")
self.layout = QtGui.QHBoxLayout(self)
self.layout.addWidget(self.label)
def mousePressEvent(self, event):
if event.buttons() == QtCore.Qt.LeftButton:
self.label.setText("Left Mouse Click!")
elif event.buttons() == QtCore.Qt.RightButton:
self.label.setText("Right Mouse Click!")
return super(myWindow, self).mousePressEvent(event)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('myWindow')
main = myWindow()
main.resize(150, 150)
main.show()
sys.exit(app.exec_())
You should subclass QWebView, and override mousePressEvent. You could store in a variable the button that was pressed using the button() function of the QMouseEvent .
In your slot you can simply check the value of the last button pressed and handle it the way you want.
If you take a look at the docs there's some information on which buttons have been pressed in the QMouseEvent and you can handle them inside an event filter: QMouseEvent.button docs.