How to allow tab key pressing event in pyqt5 - python

Assuming that I have a QPushButton named button, I successfully do the following to allow click event:
class UI(object):
def setupUi(self, Dialog):
# ...
self.button.clicked.connect(self.do_something)
def do_something(self):
# Something here
My question is: how can I call do_something() when the tab key is pressed? For instance, if I have a QlineEdit named tb_id, after entering a value and press tab key, do_something() method should be called in the same way as what clicked does above. How can I do that using pyqt5?
Thank you so much.

To get what you want there are many methods but before pointing it by observing your code I see that you have generated it with Qt Designer so that code should not be modified but create another class that uses that code so I will place the base code:
from PyQt5 import QtCore, QtWidgets
class UI(object):
def setupUi(self, Dialog):
self.button = QtWidgets.QPushButton("Press Me")
lay = QtWidgets.QVBoxLayout(Dialog)
lay.addWidget(self.button)
class Dialog(QtWidgets.QDialog, UI):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.setupUi(self)
self.button.clicked.connect(self.do_something)
#QtCore.pyqtSlot()
def do_something(self):
print("do_something")
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Dialog()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
Also, I recommend you read the difference between event and signal in the world of Qt in What are the differences between event and signal in Qt since you speak of click event but in the world of Qt one must say clicked signal.
Now if going to the point there are the following options:
Using keyPressEvent:
class Dialog(QtWidgets.QDialog, UI):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.setupUi(self)
self.button.clicked.connect(self.do_something)
#QtCore.pyqtSlot()
def do_something(self):
print("do_something")
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_Tab:
self.do_something()
Using an event filter:
class Dialog(QtWidgets.QDialog, UI):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.setupUi(self)
self.button.clicked.connect(self.do_something)
#QtCore.pyqtSlot()
def do_something(self):
print("do_something")
def eventFilter(self, obj, event):
if obj is self and event.type() == QtCore.QEvent.KeyPress:
if event.key() == QtCore.Qt.Key_Tab:
self.do_something()
return super(Dialog, self).eventFilter(obj, event)
Using activated signal of QShorcut:
class Dialog(QtWidgets.QDialog, UI):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.setupUi(self)
self.button.clicked.connect(self.do_something)
shortcut = QtWidgets.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Tab), self)
shortcut.activated.connect(self.do_something)
#QtCore.pyqtSlot()
def do_something(self):
print("do_something")
From the previous methods I prefer the latter because you do not need to overwrite anything and you can connect to several functions.
On the other hand, only events are detected when the focus is in the Qt window.

I assume you put your widget in QDialog widget, so if you want to implement your own key press event, you should override the keyPressEvent of your Dialog widget,
then it can behave as you like.
Here's an example,
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QDialog
class UI(QDialog):
def __init__(self):
super(UI, self).__init__()
# ...
self.button.clicked.connect(self.do_something)
def do_something(self):
# Something here
def keyPressEvent(self, event):
# when press key is Tab call your function
if event.key() == Qt.Key_Tab:
self.do_something()

Related

How to record a pressed key combination in the PyQT5 dialog window

I open the dialog from the main window, where by clamping the keys, I fill the line with their names. The problem is that I can not understand where you need to do a cycle of checking all the keys on their state. Maybe there is another way to get the keys pressed? Or where you need to listen to the clamping so that the dialog box does not hang and the string is updated.
MainWindow:
def showBindings(self, param):
from dialogs import KeyBindingsDialog
self.dialog = KeyBindingsDialog()
self.dialog.show()
Dialog:
class KeyBindingsDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(KeyBindingsDialog, self).__init__(parent)
self.ui = KeyBindings()
self.ui.setupUi(self)
Use QKeySequenceEdit:
from PyQt5 import QtCore, QtGui, QtWidgets
class KeySequenceEdit(QtWidgets.QKeySequenceEdit):
def keyPressEvent(self, event):
super(KeySequenceEdit, self).keyPressEvent(event)
seq_string = self.keySequence().toString(QtGui.QKeySequence.NativeText)
if seq_string:
last_seq = seq_string.split(",")[-1].strip()
le = self.findChild(QtWidgets.QLineEdit, "qt_keysequenceedit_lineedit")
self.setKeySequence(QtGui.QKeySequence(last_seq))
le.setText(last_seq)
self.editingFinished.emit()
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self._keysequenceedit = KeySequenceEdit(editingFinished=self.on_editingFinished)
button = QtWidgets.QPushButton("clear", clicked=self._keysequenceedit.clear)
hlay = QtWidgets.QHBoxLayout(self)
hlay.addWidget(self._keysequenceedit)
hlay.addWidget(button)
#QtCore.pyqtSlot()
def on_editingFinished(self):
sequence = self._keysequenceedit.keySequence()
seq_string = sequence.toString(QtGui.QKeySequence.NativeText)
print("sequence: ", seq_string)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())

PyQt drag and drop event empty

I'm trying to figure out how dnd works with (py)qt. I tried several example applications and.. hm was wondering: how do I see what data is actually inside a drag/drop event? I tried printing the event, the dict of the event, the mimeData().text().. but no mater what i drag in there, there seems to be no data whatsoever. Eg if I drag over a '.desktop' file from /usr/share/applications, shouldn't there be info inside the drag event?
see this eg. application:
#!/usr/bin/python
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
from PyQt4.QtCore import Qt
class DragFromWidget(QtGui.QDockWidget):
def __init__(self, parent=None):
super(DragFromWidget, self).__init__(parent=parent)
self.layout().addWidget(QtGui.QLabel("Label!"))
class DragToWidget(QtGui.QDockWidget):
def __init__(self, parent=None):
super(DragToWidget, self).__init__(parent=parent)
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
#HOW?
print event
print event.__dict__
print event.mimeData()
print event.mimeData().__dict__
print event.mimeData().text()
event.accept()
def dropEvent(self, event):
#HOW?
print event
print event.__dict__
print event.mimeData()
print event.mimeData().__dict__
print event.mimeData().text()
class SandboxApp(QtGui.QApplication):
def __init__(self, *args, **kwargs):
super(SandboxApp, self).__init__(*args)
self.mainwindow = MainWindow()
self.mainwindow.show()
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent=parent)
self.setDockOptions(QtGui.QMainWindow.AllowNestedDocks|QtGui.QMainWindow.AnimatedDocks)
self.addDockWidget(Qt.LeftDockWidgetArea, DragFromWidget())
self.addDockWidget(Qt.RightDockWidgetArea, DragToWidget())
def main():
app = SandboxApp(sys.argv)
sys.exit(app.exec_())
if __name__ == "__main__":
main()

How to find out if second window is closed

I have an application that uses another application from someone else halfway through (both applications use .ui files). Therefore I create the second application in SecondWindow and hide MainWindow. Now I would like to show MainWindow again after SecondWindow is closed. I found the solution in the answer works, but now the background of SecondWindow is wrong because it uses the background of MainWindow. Is there a way to find out if SecondWindow is closed in the class from MainWindow without making MainWindow a parent of SecondWindow or to prevent the background changes caused by the parenthood?
My current code looks somewhat like this:
## Define main window class from template
path = os.path.dirname(os.path.abspath(__file__))
uiFile = os.path.join(path, 'test.ui')
Ui_MainWindow, QtBaseClass = uic.loadUiType(uiFile)
uiFile2 = os.path.join(path, 'monitor.ui')
WindowTemplate, SecondWindowClass = pg.Qt.loadUiType(uiFile2)
class SecondWindow(SecondWindowClass):
def closeThis(self):
self.close()
self.parent().show()
def __init__(self, parent):
super(SecondWindow, self).__init__(parent)
# ensure this window gets garbage-collected when closed
self.setWindowTitle('pyqtgraph example: Qt Designer')
self.ui = WindowTemplate()
self.ui.setupUi(self)
self.show()
class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def showSecond(self):
self.second.show()
self.hide()
def __init__(self):
QtGui.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.ui=uic.loadUi(uiFile, self)
self.setupUi(self)
self.show()
self.second = SecondWindow(self)
self.second.hide()
self.ui.end_button.clicked.connect(lambda x:self.showSecond())
win = MainWindow()
if __name__ == '__main__':
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
It's not actually necessary for the second window to be a child of the first.
So you should be able to do something like this:
class SecondWindow(SecondWindowClass):
def closeThis(self):
self.close()
self.first.show()
def __init__(self, first):
super(SecondWindow, self).__init__()
self.first = first
...
class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def showSecond(self):
self.second.show()
self.hide()
def __init__(self):
...
self.second = SecondWindow(self)
self.second.hide()

Make a modal QDialog minimize when QMainWindow minimized (using PyQt 5)

Example code I am using:
import sys
from PyQt5 import QtCore
from PyQt5 import QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.open_about = False
self.openAction = QtWidgets.QAction('About', self)
self.openAction.triggered.connect(self.aboutDialog)
menuBar = self.menuBar()
fileMenu = menuBar.addMenu('&File')
fileMenu.addAction(self.openAction)
self.calendar = QtWidgets.QCalendarWidget(self)
self.setCentralWidget(self.calendar)
def about_state_upd(self, value):
self.open_about = value
def aboutDialog(self):
self._about = AboutDialog(self)
self._about.exec_()
def hideEvent(self, hideEvent):
if self.open_about == True:
self._about.setVisible(False)
def showEvent(self, showEvent):
if self.open_about == True:
if self._about.isHidden() == True:
self._about.setModal(True)
self._about.setVisible(True)
class AboutDialog(QtWidgets.QDialog):
def __init__(self, parent):
super(AboutDialog, self).__init__(parent)
self.setMinimumSize(400, 350)
self.parent().about_state_upd(True)
def closeEvent(self, closeEvent):
self.parent().about_state_upd(False)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
app_window = MainWindow()
app_window.showMaximized()
sys.exit(app.exec_())
This code basically works, but seems very complicated. Is there a simpler / cleaner way to make it so that when the modal QDialog is open, if the QMainWindow is minimized, the QDialog also gets minimized too (and reverse when QMainWindow is restored)?
Code is running on KDE Neon (Kubuntu-based distro).
May be you can use this: http://korbinin.blogspot.fr/search/label/minimize%20button
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class MainForm(QDialog):
def __init__(self, fn=None,parent=None):
super(MainForm, self).__init__(parent,\
flags=Qt.WindowMinimizeButtonHint|Qt.WindowMaximizeButtonHint)
Thanks to the people on the PyQt Mailing list, I managed to get a workaround for KDE. Instead of using exec_(), I am just using show() - then I use setDisabled() on QMainWindow to make dialog act in a modal fashion. Here is a (very quick and basic) example for anyone interested:
import sys
from PyQt5 import QtCore
from PyQt5 import QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.openAction = QtWidgets.QAction('About', self)
self.openAction.triggered.connect(self.aboutDialog)
menuBar = self.menuBar()
fileMenu = menuBar.addMenu('&File')
fileMenu.addAction(self.openAction)
self.calendar = QtWidgets.QCalendarWidget(self)
self.setCentralWidget(self.calendar)
def aboutDialog(self):
self._about = AboutDialog(self)
self.setDisabled (True)
self._about.show()
def enableWidgets(self):
self.setDisabled(False)
class AboutDialog(QtWidgets.QDialog):
def __init__(self, parent):
super(AboutDialog, self).__init__(parent)
self.setMinimumSize(400, 350)
def closeEvent(self, parent):
self.parent().enableWidgets()
def changeEvent(self, event):
if event.type() == QtCore.QEvent.WindowStateChange:
if self.windowState() & QtCore.Qt.WindowMinimized:
self.parent().showMinimized()
else:
self.parent().showMaximized()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
app_window = MainWindow()
app_window.showMaximized()
sys.exit(app.exec_())
Link to PyQt Mailing List posts.

PyQt5: QPushButton double click?

I can't find a good answer for this: is there a way for double click to execute a certain function, and single click one other function?? For example:
def func1(self):
print('First function')
def func2(self):
print('Second function')
self.ui.button.clicked.connect(self.func1)
self.ui.button.doubleClicked.connect(self.func2)
I've seen double clicking is possible for the QTreeview but not a QPushButton. Thanks!
You can add the functionality easily yourself by extending QPushButton class:
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class QDoublePushButton(QPushButton):
doubleClicked = pyqtSignal()
clicked = pyqtSignal()
def __init__(self, *args, **kwargs):
QPushButton.__init__(self, *args, **kwargs)
self.timer = QTimer()
self.timer.setSingleShot(True)
self.timer.timeout.connect(self.clicked.emit)
super().clicked.connect(self.checkDoubleClick)
#pyqtSlot()
def checkDoubleClick(self):
if self.timer.isActive():
self.doubleClicked.emit()
self.timer.stop()
else:
self.timer.start(250)
class Window(QWidget):
def __init__(self, *args, **kwargs):
QWidget.__init__(self, *args, **kwargs)
self.button = QDoublePushButton("Test", self)
self.button.clicked.connect(self.on_click)
self.button.doubleClicked.connect(self.on_doubleclick)
self.layout = QHBoxLayout()
self.layout.addWidget(self.button)
self.setLayout(self.layout)
self.resize(120, 50)
self.show()
#pyqtSlot()
def on_click(self):
print("Click")
#pyqtSlot()
def on_doubleclick(self):
print("Doubleclick")
app = QApplication(sys.argv)
win = Window()
sys.exit(app.exec_())
However, I would not recommend it. Users do not expect to double-click buttons. You can refer to Command Buttons Microsoft guidelines.

Categories