Not much info I've found, but looks like this snippet should works:
import sys
from PySide2.QtWidgets import QApplication, QMenu, QPushButton, QSystemTrayIcon, QWidgetAction
app = QApplication(sys.argv)
menu = QMenu()
button = QPushButton("yoba")
action = QWidgetAction(menu)
action.setDefaultWidget(button)
menu.addAction(action)
menu.addAction("Quit").triggered.connect(sys.exit)
tray = QSystemTrayIcon()
tray.setContextMenu(menu)
tray.show()
sys.exit(app.exec_())
But, I see only Quit item and empty item above, no push button appear. So, the question is "how to add custom widgets to tray menu?"
Ok, looks like this is a bug: https://bugreports.qt.io/browse/QTBUG-26840
Since if call menu.show() instead of tray.show() everything is fine.
Related
I am developing a PyQt5 application which takes an input from the user in a string format and then utilise that variable further in the code.
Problem: The input box code when called from within a while loop (Ideally the box should stay and wait for the input from the user, thereby holding the while loop execution as well), instead it does not stay on the screen, it flashes and disappears in a fraction of seconds when executing the script on windows 10. But when I execute the code snippet mentioned below separately, then this type of problem does not appear.
Code Snippet
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QInputDialog, QLineEdit, QLabel
def call_qt():
app = QApplication(sys.argv)
gui = QWidget()
text, ok = QInputDialog.getText(gui, "User Input",
"""Do you wish to Continue [Y/N]?""")
#print(text, ok)
if ok:
app.exit()
else:
app.exit()
return text
print(call_qt())
I am not able to figure out, What could be the problem with this code snippet. Could you please help me with this? Also, I am new to PyQt5.
Confusion: The same problem does not exist on Ubuntu 18.
The problem with this part is the process handling in windows. Do threading of the QT application and call this thread inside your while loop. This should solve the problem.
from queue import Queue
que = Queue()
def call_qt(out_que):
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QInputDialog, QLineEdit, QLabel
app = QApplication(sys.argv)
gui = QWidget()
text, ok = QInputDialog.getText(gui, "User Input",
"""Do you wish to Continue [Y/N]?""")
#print(text, ok)
if ok:
app.exit()
else:
app.exit()
out_que.put()
while True:
t = Threading.thread(target=call_qt, args=(que,))
t.start()
t.join()
print("text: ",que.get())
same problem should happen on ubuntu. As you hit OK, application terminates itself and you wont be able to see output. Try this code, it prints the result on widget
import sys
from PyQt5.QtWidgets import (QApplication, QWidget, QInputDialog, QVBoxLayout, QLabel)
def call_qt(main_widow):
text, ok = QInputDialog.getText(main_widow, "User Input", "Do you wish to Continue [Y/N]?")
return text, ok
if __name__ == '__main__':
app = QApplication(sys.argv)
main_widow = QWidget()
layout = QVBoxLayout()
label = QLabel()
layout.addWidget(label)
main_widow.setLayout(layout)
main_widow.show()
text, ok = call_qt(main_widow)
# if ok:
# sys.exit()
label.setText(text)
sys.exit(app.exec_())
I would like my application to consist only of a pop-up menu that opens immediately as soon as it is run. I attempted this solution but nothing appears when I run it:
#!/usr/bin/env python3
from PyQt5.QtCore import (Qt, QPoint)
from PyQt5.QtGui import QCursor
from PyQt5.QtWidgets import (QApplication, QMenu, QAction)
def clicked():
print("CLICKED")
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
menu = QMenu()
menu.addAction(QAction("&Click me", triggered=clicked))
menu.exec_(QCursor().pos())
sys.exit(app.exec_())
This will display a simple popup window with a single option, that calls the clicked function on click:
from PySide2.QtGui import QCursor
from PySide2.QtWidgets import QApplication, QMenu
def clicked():
print("CLICKED")
if __name__ == '__main__':
app = QApplication()
menu = QMenu()
menu.addAction("Click me", clicked)
menu.exec_(QCursor().pos())
Or if you want to use QAction still, then move its definition outside:
from PySide2.QtGui import QCursor
from PySide2.QtWidgets import QApplication, QMenu, QAction
def clicked():
print("CLICKED")
if __name__ == '__main__':
app = QApplication()
menu = QMenu()
action = QAction("&Click me", triggered=clicked)
menu.addAction(action)
menu.exec_(QCursor().pos())
As pointed out by ekhumoro in the comment below:
Qt does not take ownership of actions added via addAction. You must
keep an explicit reference to them, otherwise they will get
garbage-collected.
Note I am using PySide2, but it shouldn't change anything.
Okay I am not certain how minimalistic you want this Menu to be but this is a more static menu (aka it sticks around) with more than one option in case you are trying to build some kind of Menu driven Windowing platform or just a Menu of commands. Also it being a class allows it to be importable to whatever you might be developing large scale. Further you can expand the menu by adding additional menu items with different actions and lastly it follows basic pyqt programming methodologies
from sys import exit as sysExit
from PyQt5.QtWidgets import QApplication, QAction, QWidget, QHBoxLayout, QMenuBar
class MainMenu(QWidget):
def __init__(self):
QWidget.__init__(self)
self.setMaximumSize(self.minimumSize())
self.Click1Act = QAction("&Click Me 1", triggered=self.Clicked1)
self.Click2Act = QAction("&Click Me 2", triggered=self.Clicked2)
self.SimpleMenu = QMenuBar()
self.ClickMenu = self.SimpleMenu.addMenu('Clickables')
self.ClickMenu.addAction(self.Click1Act)
self.ClickMenu.addSeparator()
self.ClickMenu.addAction(self.Click2Act)
HBox = QHBoxLayout()
HBox.addWidget(self.SimpleMenu)
self.setLayout(HBox)
def Clicked1(self):
print("CLICKED ONE")
def Clicked2(self):
print("CLICKED TWO")
if __name__ == "__main__":
MainThred = QApplication([])
MainGui = MainMenu()
MainGui.show()
sysExit(MainThred.exec_())
What I want to achieve: if a user clicks outside of the QMainWindow the window should hide.
How I tried to to tackle this problem: find a way to determine if the QMainWindow lost focus, and if so, hide the window using a followup function.
Unfortunately I can not totally grasp how to achieve this.
It can be done using the flag Qt::Popup but than I am not able to give any keyboard input to the widget my QMainWindow contains.
void QApplication::focusChanged(QWidget *old, QWidget *now)
This signal is emitted when the widget that has keyboard focus changed from old to now, i.e., because the user pressed the tab-key, clicked into a widget or changed the active window. Both old and now can be the null-pointer.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class MyWin(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setFocus()
QtWidgets.qApp.focusChanged.connect(self.on_focusChanged)
#QtCore.pyqtSlot("QWidget*", "QWidget*")
def on_focusChanged(self, old, now):
if now == None:
print(f"\nwindow is the active window: {self.isActiveWindow()}")
# window lost focus
# do what you want
self.setWindowState(QtCore.Qt.WindowMinimized)
else: print(f"window is the active window: {self.isActiveWindow()}")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = MyWin()
MainWindow.show()
sys.exit(app.exec_())
I have a small program where I used a line edit for auto-completion. After selecting the text, my cursor goes to end of the text. So how to set my cursor to the starting position?
My code:
import sys
from PyQt4.QtCore import Qt
from PyQt4.QtGui import QApplication, QCompleter, QLineEdit, QStringListModel
def get_data(model):
model.setStringList(["completion_xxxxxxxxxx", "data_yyyyyyyyyy", "goes_ccccccccc", "here"])
if __name__ == "__main__":
app = QApplication(sys.argv)
edit = QLineEdit()
edit.setCursorPosition(0)
completer = QCompleter()
edit.setCompleter(completer)
model = QStringListModel()
completer.setModel(model)
get_data(model)
edit.show()
sys.exit(app.exec_())
But I want to show it like this:
Assuming you want the cursor to move after the completion has finished, you can use the completer's activated signal with a single-shot timer, like this:
completer.activated.connect(
lambda: QTimer.singleShot(0, lambda: edit.home(False)))
I'm a beginner in PyQt. I was trying to create a simple app to try some of the toolkit's many features. My question is, how can I hide the app icon from the taskbar?
I don't want the user to be able to see the icon in taskbar and to minimize it using this icon. Is there any window flags that I can use to achieve this?
This should do the trick:
myApp.setWindowFlags(QtCore.Qt.Tool)
This drove me nuts for days. Complete app code to implement below.
Key bits:
override closeEvent(), enabling it to do either of just hiding window
or true exit
create some facility for user to choose either hide or
exit behavior
don't show() main window on instantiation, just exec_() the App
import sys
from PyQt4.QtGui import QAction, QApplication, QFrame, QIcon, \
QMainWindow, QMenu, QSystemTrayIcon
from PyQt4.QtCore import SIGNAL
class MyApp(QMainWindow):
def __init__(self, parent, title):
super(QMainWindow, self).__init__(parent)
self.exitOnClose = False
exit = QAction(QIcon(), "Exit", self)
self.connect(exit, SIGNAL("triggered()"), self.exitEvent)
self.trayIcon = QSystemTrayIcon(QIcon(), self)
menu = QMenu(self)
menu.addAction(exit)
self.trayIcon.setContextMenu(menu)
self.connect(self.trayIcon, \
SIGNAL("activated(QSystemTrayIcon::ActivationReason)"), \
self.trayIconActivated)
self.trayIcon.show()
self.trayIcon.showMessage("MyApp is running!", "Click to open window\nRight click for menu" )
def trayIconActivated(self, reason):
if reason == QSystemTrayIcon.Context:
self.trayIcon.contextMenu().show()
elif reason == QSystemTrayIcon.Trigger:
self.show()
self.raise_()
def closeEvent(self, event):
if self.exitOnClose:
self.trayIcon.hide()
del self.trayIcon
event.accept()
else:
self.hide()
event.setAccepted(True)
event.ignore()
def exitEvent(self):
self.exitOnClose = True
self.close()
if __name__ == "__main__":
app = QApplication(sys.argv)
myapp = MyApp(None, "My System Tray App")
app.exec_()
Adapted from this thread:
import sys
from PyQt4.QtGui import *
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = QWidget()
mainWindow = QMainWindow(widget)
mainWindow.show()
sys.exit(app.exec_())
I wouldn't recommend trying to hide an application's taskbar presence, especially if the application is visible. If you are only trying to prevent minimizing from the taskbar then you can achieve this by creating your top level widget with the following window flags like this:
QWidget *mainWindow = new QWidget(0, Qt::CustomizeWindowHint
| Qt::WindowTitleHint | Qt::WindowSystemMenuHint
| Qt::WindowCloseButtonHint | Qt::WindowMaximizeButtonHint);
If you don't want a maximize flag, you can leave that one out of the list too.
The various window flags that Qt can use are documented here (Qt::WindowFlags).
If you are on Ubuntu with Unity and want to hide an application's icon from the launcher on the left-hand-side, you will probably need Qt.SplashScreen. This worked for me but I don't remember if I also needed Qt.Tool, which is enough on Windows. For the SplashScreen attempt you may have to reimplement the resize functionality as it disables this feature of a QStatusBar (that has a SizeGrip) for example.
Here is a little example to try out window flags.
Just initialise your main window like this self.setWindowFlags(Qt.ToolTip)