How to design enter button functionality in virtual keyboard? - python-3.x

I have some QLineEdit widgets in my program. I connected their returnPressed signal to different functions. I also have a virtual keyboard. When one of these QLineEdit widgets are under focus and I press enter in my virtual keyboard how can I run the function for that input?
from PyQt5.QtWidgets import QMainWindow, QApplication, QLineEdit, QPushButton
from PyQt5.QtCore import Qt
import sys
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.resize(400, 200)
self.inputA = QLineEdit('inputA', self)
self.inputB = QLineEdit('inputB', self)
self.inputA.returnPressed.connect(self.funcInputA)
self.inputB.returnPressed.connect(self.funcInputB)
self.inputB.move(150, 0)
self.btnEnter = QPushButton('Enter', self)
self.btnEnter.move(0, 100)
self.btnEnter.clicked.connect(self.enter)
self.btnEnter.setFocusPolicy(Qt.NoFocus)
def funcInputA(self):
print('inputA')
def funcInputB(self):
print('inputB')
def enter(self):
widget = QApplication.focusWidget()
print(widget.text())
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())

Most events can be synthesized, including key events, and relayed to target widgets.
Note that, for consistency, you should always send both key press and release events for each "virtual" key press.
def enter(self):
widget = QApplication.focusWidget()
if widget is not None:
modifiers = Qt.KeyboardModifiers()
for evType in (QEvent.KeyPress, QEvent.KeyRelease):
event = QKeyEvent(evType, Qt.Key_Return, modifiers)
QApplication.postEvent(widget, event)

Related

QSystemTrayIcon context menu doesn't show when subclassed

I'm running python 3.9.7 on windows 10. Please consider the following code (note you will need icon.png to run)
from PyQt6.QtGui import QAction, QIcon
from PyQt6.QtWidgets import QSystemTrayIcon, QApplication, QMenu
app = QApplication([])
app.setQuitOnLastWindowClosed(False)
'''Create the system tray'''
tray = QSystemTrayIcon()
tray.setIcon(QIcon("icon.png"))
tray.show()
'''Add a menu with a quit action'''
menu = QMenu()
quit = QAction("Quit")
quit.triggered.connect(app.quit)
menu.addAction(quit)
'''Give the menu to the tray'''
tray.setContextMenu(menu)
'''Lets see where the menu is drawn'''
menu.aboutToShow.connect(lambda: print(menu.pos()))
app.exec()
The above works as expected on my system. However, when I subclass QSystemTrayIcon like so:
from PyQt6.QtGui import QAction, QIcon
from PyQt6.QtWidgets import QSystemTrayIcon, QApplication, QMenu
class SystemTrayIcon(QSystemTrayIcon):
def __init__(self, icon: QIcon, app: QApplication, *args, **kwargs):
super().__init__(*args, **kwargs)
'''setup'''
self.setIcon(icon)
self.show()
'''Add a menu with a quit action'''
menu = QMenu()
quit = QAction("Quit")
quit.triggered.connect(app.quit)
menu.addAction(quit)
'''Give the menu to the tray'''
self.setContextMenu(menu)
'''Lets see where the menu is drawn'''
menu.aboutToShow.connect(lambda: print(menu.pos()))
def main():
'''Define app'''
app = QApplication([])
app.setQuitOnLastWindowClosed(False)
'''System tray'''
tray_icon = SystemTrayIcon(QIcon('icon.png'), app)
app.exec()
if __name__ == '__main__':
main()
The menu does not show up. The lambda print positions are interesting, on my screen the first code returns something like: PyQt6.QtCore.QPoint(1686, 1036) whereas the second code returns PyQt6.QtCore.QPoint(1686, 1064), which is about 30 pixels lower. My screen resolution is 1080p so it's not off the screen as such but does indicate some different behaviour here. Any ideas why the menu doesn't display in the second example?
A reference to the QAction needs to be kept. This works:
from PyQt6.QtGui import QAction, QIcon
from PyQt6.QtWidgets import QSystemTrayIcon, QApplication, QMenu
class SystemTrayIcon(QSystemTrayIcon):
def __init__(self, icon: QIcon, app: QApplication, *args, **kwargs):
super().__init__(*args, **kwargs)
'''setup'''
self.setIcon(icon)
self.show()
'''Add a menu with a quit action'''
menu = QMenu()
self.quit = QAction("Quit")
self.quit.triggered.connect(app.quit)
menu.addAction(self.quit)
'''Give the menu to the tray'''
self.setContextMenu(menu)
'''Lets see where the menu is drawn'''
menu.aboutToShow.connect(lambda: print(menu.pos()))
def main():
'''Define app'''
app = QApplication([])
app.setQuitOnLastWindowClosed(False)
'''System tray'''
tray_icon = SystemTrayIcon(QIcon('icon.png'), app)
app.exec()
if __name__ == '__main__':
main()

Entering fullscreen mode hides the icon from taskbar and the application runs from background

When I made a window go into fullscreen mode, the application icon was hidden from the taskbar (after doing alt-tab). It also didn't appear in the alt+tab windows. It only showed the other windows that I had open.
When I checked task manager, the python process was under the background processes category. I couldn't switch back to the window.
How can I stop the application from running in the background when I enter fullscreen mode?
My code:
import sys
from PyQt5.QtGui import QKeySequence
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QShortcut
from PyQt5.QtCore import Qt
# Subclass QMainWindow to customise your application's main window
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setWindowTitle("Hello fullscreen world")
label = QLabel("Hello fullscreen world")
# The `Qt` namespace has a lot of attributes to customise
# widgets. See: http://doc.qt.io/qt-5/qt.html
label.setAlignment(Qt.AlignCenter)
# Set the central widget of the Window. Widget will expand
# to take up all the space in the window by default.
self.setCentralWidget(label)
self.shortcut_close_window = QShortcut(QKeySequence('F11'), self)
self.shortcut_close_window.activated.connect(self.goFullscreen)
def goFullscreen(self):
if self.isFullScreen():
self.setWindowFlags(self._flags)
self.showNormal()
else:
self._flags = self.windowFlags()
self.setWindowFlags(Qt.WindowCloseButtonHint | Qt.WindowType_Mask)
self.showFullScreen()
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
Note: even terminating the process using ctrl+c or closing command prompt doesn't work, only task manager does.
I don't know why you are using self.setWindowFlags in goFullscreen() function. It is unnecessary.
def goFullscreen(self):
if self.isFullScreen():
#self.setWindowFlags(self._flags)
self.showNormal()
else:
#self._flags = self.windowFlags()
#self.setWindowFlags(Qt.WindowCloseButtonHint | Qt.WindowType_Mask)
self.showFullScreen()
Btw, the reason is that you use the Qt.WindowType_Mask flag.
WindowType_Mask: A mask for extracting the window type part of the
window flags.
~Window Flags~
I had no idea that there was such a strange bug in Ubuntu. So all you have to do is write your own FullScreen method:
(I don't use ubuntu. So I don't know if you will run into a bug again.)
import sys
from PyQt5.QtGui import QKeySequence
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QShortcut
from PyQt5.QtCore import Qt
# Subclass QMainWindow to customise your application's main window
class MainWindow(QMainWindow):
isfullscreen = False
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setWindowTitle("Hello fullscreen world")
self._flags = self.windowFlags()
self._geometry = ((self.screen().size().width() / 2) - (self.width() / 2),
(self.screen().size().height() / 2) - (self.height() / 2), 600, 400)
self.setGeometry(*self._geometry)
label = QLabel("Hello fullscreen world")
# The `Qt` namespace has a lot of attributes to customise
# widgets. See: http://doc.qt.io/qt-5/qt.html
label.setAlignment(Qt.AlignCenter)
# Set the central widget of the Window. Widget will expand
# to take up all the space in the window by default.
self.setCentralWidget(label)
self.shortcut_close_window = QShortcut(QKeySequence('F11'), self)
self.shortcut_close_window.activated.connect(self.goShowFullScreen)
self._geometry = self.geometry()
def goShowFullScreen(self):
if not self.isfullscreen:
self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
self.setGeometry(self.screen().geometry())
self.show()
self.isfullscreen = True
else:
self.setWindowFlags(self.windowFlags() & ~Qt.WindowStaysOnTopHint)
self.setWindowFlags(self.windowFlags() & ~Qt.FramelessWindowHint)
self.setGeometry(self._geometry)
self.show()
self.isfullscreen = False
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()

slot to right click menu action does does not work

I have written the below code to which I finally managed to add menu but connecitn menu to a function doesnt seem to work:
import os
from PyQt5 import uic
from PyQt5 import QtWidgets
from PyQt5 import QtCore
FILE_LOCATION = os.path.dirname(os.path.realpath(__file__))
class MainDialogWindow(QtWidgets.QDialog):
def __init__(self):
super(MainDialogWindow,self).__init__()
ui_file = os.path.join(FILE_LOCATION, "example.ui")
self._ui = uic.loadUi(ui_file, self)
self.registerCallbacks()
self.initUI()
def initUI(self):
"""Initialize the UI.
"""
self.textBrowser.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
def registerCallbacks(self):
self.textBrowser.customContextMenuRequested.connect(self.context_menu)
# self.connect(self.textBrowser, QtCore.Signal('customContextMenuRequested(const QPoint &)'), self.context_menu)
def context_menu(self, pos):
menu = QtWidgets.QMenu(self)
action = menu.addAction("clear")
menu.exec_(self.mapToGlobal(pos))
action.trigered.connect(self.clear)
def clear(self):
"""Slot to claer text.
"""
print("clear")
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainDialogWindow()
window.show()
window.setGeometry(500, 300, 300, 300)
sys.exit(app.exec_())
please helpp,, I want call the clear function from the right click menu
I don't seem to understand how the menu.exec_() method works, that method blocks the execution of sequential tasks until the user selects a QAction from the QMenu. In your case, for example, until when you press "clear" and the triggered signal is emitted (note: you have a typo), but at that moment there is no connection, so the clear method will not be called. The solution is to make the connection before invoking the QMenu exec_():
def context_menu(self, pos):
menu = QtWidgets.QMenu(self)
action = menu.addAction("clear")
action.triggered.connect(self.clear)
menu.exec_(self.mapToGlobal(pos))

PyQt keyPressEvent not triggered from QDialog

I have a simple example of of a dialog window that has the keyPressEvent method. However, no matter what is typed when the sub window has focus, the event is not triggered.
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import PyQt4.Qt
class KpeWindow(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
main = QVBoxLayout(self)
label = QLabel(self)
label.setText('Test the keyPressEvent')
self.adjustSize()
self.setLayout(main)
def keyPressEvent(self, event):
QMessageBox.warning(self, 'MDI', 'keyPressEvent')
super().keyPressEvent(event)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('KeyPressEvent Test')
child = KpeWindow()
self.setCentralWidget(child)
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit(app.exec_())
The following code works:
class KpeWindow(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self,parent)
main = QVBoxLayout(self)
label = QLabel(self)
label.setText('Test the keyPressEvent')
main.addWidget(label)
self.adjustSize()
self.setLayout(main)
def keyPressEvent(self, event):
QMessageBox.warning(self, 'MDI', 'keyPressEvent')
self.parent().keyPressEvent(event)
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setWindowTitle('KeyPressEvent Test')
main = QVBoxLayout(self)
child = KpeWindow(self)
child.setFocusPolicy(Qt.StrongFocus)
self.setFocusProxy(child)
main.addWidget(child)
child.setFocus(True)
self.adjustSize()
self.setLayout(main)
I am not sure which of my changes work, I suspect setFocusProxy. In general I would recommend using QWidget as the child, and putting things into layouts even when there are no siblings.
The keyPressEvent is sensitive to the focus policy. In your example, the event is going to the QMainWindow (if you move the keyPressEvent to there, it does receive key events).
Is there any reason to have a dialog within a window? If you launch the dialog in the usual way, using child.show(), child.exec_() instead of setCentralWidget, it shows in a separate window and captures the key event.

QMainWindow flashes and disappears when called from another QMainWindow

This fairly minimal code creates a systray item with three right click options. One is an instance of QDialog, another QMainWindow, and also Quit. It's for a systray-driven app that will have some qdialogs and also a qmainwindow containing a table widget (or, is it possible to create a table into a qdialog?). I've been stuck on this for a week or so, read a lot of related materials and do not understand how to resolve it.
From the systray icon menu, clicking on QDialog, the dialog opens, waits for user action, and clicking the Ok or Cancel buttons will print which one was clicked. It would seem this works because QDialog has its own exec_(). Great so far.
However, clicking on the QMainWindow menu option, the main window dialog appears briefly and disappears with no chance for user input, of course. Maybe instead, the qmainwindow dialog would need to rely on the QApplication's exec_() where the object would instead be initialized just before app.exec_() perhaps? If that would work, I'm not clear on how def qmainwindow() would retrieve the information back from the user.
Hopefully a simple matter for someone who knows, a few changes, bingo.
Current environment: Windows 7 or XP, Python 2.7, Pyside
If you run this, there will be a blank place-holder in the systray that is clickable (right click), or you can also give it an actual image in place of 'sample.png'.
#!python
from PySide import QtGui, QtCore
from PySide.QtGui import QApplication, QDialog, QMainWindow
def qdialog():
qdialog_class_obj = TestClassQDialog()
qdialog_class_obj.show()
qdialog_class_obj.exec_() # wait for user
print "qdialog_user_action: ", qdialog_class_obj.qdialog_user_action
def qmainwindow():
qmainwindow_class_obj = TestClassQMainWindow()
qmainwindow_class_obj.show()
#qmainwindow_class_obj.exec_() # 'TestClassQMainWindow' object has no attribute 'exec_'
class TestClassQDialog(QDialog):
def __init__(self, parent=None):
super(TestClassQDialog, self).__init__(parent)
self.ok_cancel = QtGui.QDialogButtonBox(self)
self.ok_cancel.setStandardButtons(QtGui.QDialogButtonBox.Ok|QtGui.QDialogButtonBox.Cancel)
QtCore.QObject.connect(self.ok_cancel, QtCore.SIGNAL("accepted()"), self.button_ok)
QtCore.QObject.connect(self.ok_cancel, QtCore.SIGNAL("rejected()"), self.button_cancel)
def button_ok(self):
self.qdialog_user_action = 'ok'
self.hide()
def button_cancel(self):
self.qdialog_user_action = 'cancel'
self.hide()
class TestClassQMainWindow(QMainWindow):
def __init__(self, parent=None):
super(TestClassQMainWindow, self).__init__(parent)
self.ok_cancel = QtGui.QDialogButtonBox(self)
self.ok_cancel.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
QtCore.QObject.connect(self.ok_cancel, QtCore.SIGNAL("accepted()"), self.button_ok)
QtCore.QObject.connect(self.ok_cancel, QtCore.SIGNAL("rejected()"), self.button_cancel)
def button_ok(self):
self.hide()
def button_cancel(self):
self.hide()
class SysTrayIcon(QMainWindow):
def __init__(self, parent=None):
super(SysTrayIcon, self).__init__(parent)
self.qdialog_action = QtGui.QAction("QDialog", self, triggered=qdialog)
self.qmainwindow_action = QtGui.QAction("QMainWindow", self, triggered=qmainwindow)
self.quit_action = QtGui.QAction("Quit", self, triggered=QtGui.qApp.quit)
self.createSystrayIcon()
self.systrayIcon.show()
def createSystrayIcon(self):
self.systrayIconMenu = QtGui.QMenu(self)
self.systrayIconMenu.addAction(self.qdialog_action)
self.systrayIconMenu.addAction(self.qmainwindow_action)
self.systrayIconMenu.addSeparator()
self.systrayIconMenu.addAction(self.quit_action)
self.systrayIcon = QtGui.QSystemTrayIcon(self)
self.systrayIcon.setContextMenu(self.systrayIconMenu)
self.systrayIcon.setIcon(QtGui.QIcon('sample.png')) # point to a valid image if you want.
self.systrayIcon.setVisible(True)
if __name__ == '__main__':
app = QtGui.QApplication([])
systrayicon = SysTrayIcon()
app.exec_()
I've got it working. What I did was move your external method qmainwindow inside of your
SysTrayIcon and created the class parameter self.qmainwindow_class_obj = TestClassQMainWindow(). I've attached the working code below. Also, you're using the old style signal slot method, I take it you're coming from old school PyQt. The new method if very nice, clean and pythonic. I've also put the new style methods in the below code. Another thing I would do is move your qdialog method inside the SysTrayIcon class. I don't really understand why you have it outside the class but maybe I'm missing something. Hope this helps.
#!python
from PySide import QtGui, QtCore
from PySide.QtGui import QApplication, QDialog, QMainWindow
def qdialog():
qdialog_class_obj = TestClassQDialog()
qdialog_class_obj.show()
qdialog_class_obj.exec_() # wait for user
print "qdialog_user_action: ", qdialog_class_obj.qdialog_user_action
class TestClassQDialog(QDialog):
def __init__(self, parent=None):
super(TestClassQDialog, self).__init__(parent)
self.ok_cancel = QtGui.QDialogButtonBox(self)
self.ok_cancel.setStandardButtons(QtGui.QDialogButtonBox.Ok|QtGui.QDialogButtonBox.Cancel)
self.ok_cancel.accepted.connect(self.button_ok)
self.ok_cancel.rejected.connect(self.button_cancel)
def button_ok(self):
self.qdialog_user_action = 'ok'
self.hide()
def button_cancel(self):
self.qdialog_user_action = 'cancel'
self.hide()
class TestClassQMainWindow(QMainWindow):
def __init__(self, parent=None):
super(TestClassQMainWindow, self).__init__(parent)
self.ok_cancel = QtGui.QDialogButtonBox(self)
self.ok_cancel.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
self.ok_cancel.accepted.connect(self.button_ok)
self.ok_cancel.rejected.connect(self.button_cancel)
def button_ok(self):
self.hide()
def button_cancel(self):
self.hide()
class SysTrayIcon(QMainWindow):
def __init__(self, parent=None):
super(SysTrayIcon, self).__init__(parent)
self.qmainwindow_class_obj = TestClassQMainWindow()
self.qdialog_action = QtGui.QAction("QDialog", self, triggered=qdialog)
self.qmainwindow_action = QtGui.QAction("QMainWindow", self, triggered=self.qmainwindow)
self.quit_action = QtGui.QAction("Quit", self, triggered=QtGui.qApp.quit)
self.createSystrayIcon()
self.systrayIcon.show()
def createSystrayIcon(self):
self.systrayIconMenu = QtGui.QMenu(self)
self.systrayIconMenu.addAction(self.qdialog_action)
self.systrayIconMenu.addAction(self.qmainwindow_action)
self.systrayIconMenu.addSeparator()
self.systrayIconMenu.addAction(self.quit_action)
self.systrayIcon = QtGui.QSystemTrayIcon(self)
self.systrayIcon.setContextMenu(self.systrayIconMenu)
self.systrayIcon.setIcon(QtGui.QIcon('linux.jpeg')) # point to a valid image if you want.
self.systrayIcon.setVisible(True)
def qmainwindow(self):
self.qmainwindow_class_obj.show()
if __name__ == '__main__':
app = QtGui.QApplication([])
systrayicon = SysTrayIcon()
app.exec_()

Resources