How does the keyPressEvent method work in this program? - pyqt

I'm having trouble understanding how the keyPressEvent method works in this program. Specifically, what is "e" here? Is keyPressEvent a redefined method using a pre-existing instance "e"?
import sys
from PyQt4 import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.setGeometry(300,300,250,150)
self.setWindowTitle('Event handler')
self.show()
def keyPressEvent(self, e):
if e.key() == QtCore.Qt.Key_Escape:
self.close()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

e is the "event" that is generated when a user presses a key. This is pretty common in event handlers, it's a great way to pass information (such as which key got pressed - which is what's getting pulled with e.key()) to event handlers, so that we can combine related events and handle them with a single function.
# A key has been pressed!
def keyPressEvent(self, event):
# Did the user press the Escape key?
if event.key() == QtCore.Qt.Key_Escape: # QtCore.Qt.Key_Escape is a value that equates to what the operating system passes to python from the keyboard when the escape key is pressed.
# Yes: Close the window
self.close()
# No: Do nothing.

Related

two keyPressEvent in the same class (Pyqt5)

Hello
I am using Pyqt5 & QT Designer to create a GUI. and i would like to use two keyPressEvent in one class. one of them to exit from the GUI and the other to hide a button.The problem is that the keyPressEvent overwrite each other so that they can't preform together
Part of the code:
....
self.pushButton = MYButton(self.centralwidget)
....
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent=parent)
self.setupUi(self)
self.initMe()
def initMe(self):
self.pushButton.setToolTip('This is a <u> Button </u>')
self.pushButton.clicked.connect(self.pressed)
QToolTip.setFont(QFont('Arial',7))
self.setToolTip('Das ist ein Fenster!')
self.pushButton_2.clicked.connect(self.close)
def druecken(self): #1
Sender = self.sender()
Sender.move(50,50)
print(Sender.text()+'the Button is already pressed')
def keyPressEvent(self, e):
if e.key() == Qt.Key_W:
self.close()
class MYButton(QPushButton):
def keyPressEvent(self, e):
if e.key() == Qt.Key_Escape:
self.close()
So for example i have to press the Escape key first to hide the buttom then i can't press the W Key to close the GUI. But when i do it oppisitly it does not work because MYButton function is still runing and its keyPressEvent is activied. So how i get the both to run together?

Handle arrow key events by setting the focus policy

I want to handle key events of the arrow keys in my application. I have already read that for doing so the focus must be disabled. I follow this method: PyQt not recognizing arrow keys. Indeed, when calling self.setChildrenFocusPolicy(QtCore.Qt.NoFocus) (as defined in the linked thread and in my source code below) within MyApp.__init__, hitting an arrow key raises a key event. However, I do not want to keep the focus disabled during the entire runtime of the application but only upon clicking a button. So I move self.setChildrenFocusPolicy(QtCore.Qt.NoFocus) to the button click function:
def __init__(self):
self.pushButton.clicked.connect(self.pushButtonClicked)
def pushButtonClicked(self):
self.setChildrenFocusPolicy(QtCore.Qt.NoFocus)
Indeed, hitting the push button disables the focus (e.g. a line edit cannot take the text cursor anymore). However, hitting an arrow key still does not raise a key event.
The whole application (you will need a mainwindow.ui with a push button):
import sys
from PyQt4 import QtCore, QtGui, uic
qtCreatorFile = "d:/test/mainwindow.ui"
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
class MyApp(QtGui.QMainWindow, Ui_MainWindow):
def setChildrenFocusPolicy(self, policy):
def recursiveSetChildFocusPolicy (parentQWidget):
for childQWidget in parentQWidget.findChildren(QtGui.QWidget):
childQWidget.setFocusPolicy(policy)
recursiveSetChildFocusPolicy(childQWidget)
recursiveSetChildFocusPolicy(self)
def __init__(self):
QtGui.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.setupUi(self)
self.pushButton.clicked.connect(self.pushButtonClicked)
def pushButtonClicked(self):
self.setChildrenFocusPolicy(QtCore.Qt.NoFocus)
def keyPressEvent(self, event):
print "a"
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MyApp()
window.show()
sys.exit(app.exec_())
There's no need to disable focus. You can get access to all key events by installing an event filter on the application:
class MyApp(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self):
...
QtGui.qApp.installEventFilter(self)
def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.KeyPress:
print(event.key())
return super(MyApp, self).eventFilter(source, event)
But note that this really does get everything, so you may end up with more than you bargained for...

Function is not run when connecting Button to it in PyQt4

I m new to PyQt4 and having problems when trying to connect a button to a function.
I m using PyQt 4.11.4.
Neither the clicked.connect method nor the line in the comment below seemed to work.
from PyQt4 import QtGui, QtCore
import sys
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
def setupUi(self, Window):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(200, 200)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setGeometry(0,0,100,100)
MainWindow.setCentralWidget(self.centralwidget)
self.pushButton = QtGui.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(100, 50, 55, 20))
self.pushButton.setText("Run")
self.pushButton.clicked.connect(self.run)
#OR QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL('clicked()'),self.run)
def run(self):
print("ok")
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
MainWindow = QtGui.QMainWindow()
Window().setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
First of all, by placing statements directly after the __name__ == "__main__" test you introduce global variables. For instance the MainWindow variable is global and is subsequently altered in the Window.setupUi method. This is undesirable. It's better to create a main function and call only that. For example by changing those lines into this...
def main():
app = QtGui.QApplication(sys.argv)
MainWindow = QtGui.QMainWindow()
Window().setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
you will get a run-time error and thus notice something's wrong.
By the way, it is the convention in Python to start class names with an upper case character and objects with a lower case. Therefore, at first glance I thought that MainWindow was a class. It is, however, an object and should better be renamed to mainWindow. Notice how the StackOverflow syntax highlighting colors all identifiers that start with an capital letter light blue?
So, the issue with the signal is that you create two main window objects: first by MainWindow = QtGui.QMainWindow() and then on the next line by Window().setupUi(MainWindow). On that second line you call setupUi with the self parameter set to a temporary Window object, and the Window parameter set to a QtGui.QMainWindow object (MainWindow). It's not surprising that this doesn't work, it is actually a bit surprising it does something at all.
Finally, it is strongly recommended to use layouts in Qt to arrange the widgets. This makes the calls to setGeometry() superfluous. Adding widgets to a layout also set's their parent, so you don't need to do this separately then. I think you definitely should read the docs on layout management (except the last section on writing your own layout manager).
Apply all the advice above and you get something like this...
from PyQt4 import QtGui, QtCore
import sys
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self._setupUi()
def _setupUi(self):
self.resize(200, 200)
# the central widget is called my widget to prevent clashes with
# the centralWidget() function.
self.mainWidget = QtGui.QWidget()
self.setCentralWidget(self.mainWidget)
self.mainLayout = QtGui.QVBoxLayout()
self.mainWidget.setLayout(self.mainLayout)
self.pushButton = QtGui.QPushButton()
self.pushButton.setText("Run")
self.mainLayout.addWidget(self.pushButton)
self.pushButton.clicked.connect(self.run)
def run(self):
print("ok")
def main():
app = QtGui.QApplication(sys.argv)
mainWindow = Window()
mainWindow.setObjectName("mainWindow") # can be omitted.
mainWindow.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Pause execution until button press

I have a QStackedWidget. In the logic (not the UI) I am trying to change pages and wait there until a button on that page is pressed (basically an OK/Cancel). I pass the UI to the function in the class.
Something like this:
def func1(self, window):
window.stackedWidget.setCurrentIndex(4)
while True:
window.btn_OK.clicked.connect(self.OK_func)
window.btn_Cancel.clicked.connect(self.Can_func)
def OK_func(self, window):
do_something
window.stackedWidget.setCurrentIndex(3)
break
def Can_func(self, window):
window.stackedWidget.setCurrentIndex(3)
break
for i in range(5):
#stuff
func1(window) #this is where I want to pause
#other stuff
Now I know that I can't break with the function like that or pass the window variable through connect, but I hope that makes my point clearly enough.
A simple way to do this is to process pending events inside the loop (so the UI remains responsive), and set/unset an internal flag to control starting and stopping of the loop.
The following demo script shows a basic implementation of this idea:
import time
from PyQt4 import QtCore, QtGui
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
layout = QtGui.QVBoxLayout(self)
self.label = QtGui.QLabel(self)
layout.addWidget(self.label)
self.buttonStart = QtGui.QPushButton('Start', self)
self.buttonStart.clicked.connect(self.handleStart)
layout.addWidget(self.buttonStart)
self.buttonStop = QtGui.QPushButton('Stop', self)
self.buttonStop.clicked.connect(self.handleStop)
layout.addWidget(self.buttonStop)
self._running = False
def handleStart(self):
self.buttonStart.setDisabled(True)
self._running = True
while self._running:
self.label.setText(str(time.clock()))
QtGui.qApp.processEvents()
time.sleep(0.05)
self.buttonStart.setDisabled(False)
def handleStop(self):
self._running = False
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 200, 100)
window.show()
sys.exit(app.exec_())
Just remove while and break.
def func1(self, window):
window.stackedWidget.setCurrentIndex(4)
window.btn_OK.clicked.connect(self.OK_func)
window.btn_Cancel.clicked.connect(self.Can_func)
def OK_func(self, window):
# do_something
window.stackedWidget.setCurrentIndex(3)
def Can_func(self, window):
window.stackedWidget.setCurrentIndex(3)

Unable to get key event when using uic.loadUI() in PyQt4

I have the following code that cannot capture the key event.
I used the uic.loadUi() to load my GUI.
But I can't seem to capture the keyboard event.
Pls help!
class cMyApp(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self)
self.ui = uic.loadUi("myApp.ui")
#~ self.ui.show() # Show myApp UI but key event Doesn't Work :(
self.show() # Show a small window but key event works.
def keyPressEvent(self, event):
if type(event)==QtGui.QKeyEvent:
print ("type(event) = ",type(event))
if event.key()==QtCore.Qt.Key_Escape:
print("Esc pressed!!!")
self.close()
event.accept()
else:
event.ignore()
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
myApp = cMyApp()
sys.exit(app.exec_())
Found the problem! ;P
When loading with uic.loadUI(), must supply 'self' as another parameter for baseinstance; otherwise it's default to None.
The corrected codes portion should be:
self.ui = uic.loadUi("myApp.ui", self) # Must supply 'self' as baseinstance.
self.ui.show() # Show myApp UI can work with key event now! :)

Resources