Window is not responding when opened before the mouse.wait function.
If replace the mouse.wait function to another (which doesn't waiting the mouse click), the window will open normally.
import pyautogui, sys, mouse
from PySide2 import QtWidgets
from design import Ui_Form, Ui_Next
def mpos(file):
mouse.wait(button='right', target_types='down')
x,y=pyautogui.position()
file.write(str(x)+'_'+str(y)+'-')
def prog():
with open('prog.txt', 'w') as file:
next()
mpos(file)
next()
mpos(file)
next()
mpos(file)
def menu():
mui.configButton.clicked.connect(prog)
wmenu.show()
def fclose():
wnext.close()
def next():
nui.okButton.clicked.connect(fclose)
wnext.show()
app = QtWidgets.QApplication(sys.argv)
wmenu = QtWidgets.QFrame()
mui = Ui_Form()
mui.setupUi(wmenu)
wnext = QtWidgets.QFrame()
nui = Ui_Next()
nui.setupUi(wnext)
menu()
sys.exit(app.exec_())
The problem is that the wait method blocks the Qt event loop by freezing the GUI. A possible solution is to run it in another thread:
import threading
# ...
def execute_thread():
threading.Thread(target=prog, daemon=True).start()
def menu():
mui.configButton.clicked.connect(execute_thread)
# ...
Related
For my application, I need my lift system to go up as long as the button is pressed and it should stop when I don't press the button.
clicked() function is not functional for this purpose. However pressed() and released() functions also didn't work.
I snipped related section of my code below. My aim is to print "Pressed" text as long as button is pressed
def __init__(self):
manual_button = QPushButton('Lift Button')
manual_button.pressed.connect(press_function)
self.manual_grid.addWidget(manual_button, 0, 1)
def press_function(self):
print('pressed')
Thanks
Just use the pressed and released signals to start/stop a QTimer. Something like...
#!/usr/local/bin/python3
import os
import sys
from PyQt5.QtCore import(QTimer)
from PyQt5.QtWidgets import(QApplication, QPushButton)
def button_pressed(timer):
timer.start(100)
def button_released(timer):
timer.stop()
if __name__ == '__main__':
app = QApplication(sys.argv)
pb = QPushButton("Press")
timer = QTimer()
pb.pressed.connect(lambda checked = False: button_pressed(timer))
pb.released.connect(lambda checked = False: button_released(timer))
timer.timeout.connect(lambda: print('Button Pressed'))
pb.show()
app.exec_()
Using PyQt5, I want to implement a two windows displaying one after another automatically, without the user interacting with any window. Something like this:
While True:
Show Window1
wait 2 seconds
Close Window1
Show Window2
wait 2 seconds
Close Window2
The problem I am having is that the main UI thread is stuck in app.exec_() function, so it cannot implement the opening and closing logic.
import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic
class Win1(QMainWindow):
def __init__(self):
super(Win1, self).__init__()
uic.loadUi('win1.ui', self)
self.show()
class Win2(QMainWindow):
def __init__(self):
super(Win2, self).__init__()
uic.loadUi('win2.ui', self)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
while True:
win = Win1()
time.sleep(1)
win.close()
win = Win2()
time.sleep(1)
win.close()
app.exec_() # <--------- Program blocks here
I would appreciate if someone can share a minimal example for this working without blocking. Or please point to the mechanism that should be used.
If you are going to work with Qt then you should forget about sequential logic but you have to implement the logic using events. For example, in your case you want one window to be shown every time T and another to be hidden, so that can be implemented with a QTimer and a flag:
import sys
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5 import uic
class Win1(QMainWindow):
def __init__(self):
super(Win1, self).__init__()
uic.loadUi('win1.ui', self)
self.show()
class Win2(QMainWindow):
def __init__(self):
super(Win2, self).__init__()
uic.loadUi('win2.ui', self)
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
timer = QTimer()
timer.setProperty("flag", True)
win1 = Win1()
win2 = Win2()
def on_timeout():
flag = timer.property("flag")
if flag:
win1.show()
win2.close()
else:
win2.show()
win1.close()
timer.setProperty("flag", not flag)
timer.timeout.connect(on_timeout)
timer.start(1 * 1000)
on_timeout()
app.exec_()
You should not use while loop or time.sleep since they block the eventloop in which the GUI lives, that is: they freeze the windows
I'm trying to create application which runs block of code every X seconds, which has system tray icon with only "Quit" option. But the problem is that when it get to the tray function, it doesn't read next lines of code, and as a result, "While" loop can't be launched.
Is there any other approach to do that?
import time
import os
import sys
from PySide2 import QtWidgets, QtGui
class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
def __init__(self, icon, parent=None):
QtWidgets.QSystemTrayIcon.__init__(self, icon, parent)
self.setToolTip(f'Wallpy')
menu = QtWidgets.QMenu(parent)
exit_ = menu.addAction("Exit")
exit_.triggered.connect(lambda: sys.exit())
menu.addSeparator()
self.setContextMenu(menu)
def tray():
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
tray_icon = SystemTrayIcon(QtGui.QIcon("tray.ico"), w)
tray_icon.show()
app.exec_()
def loop_function():
print("Nice") # anything executable
tray() # launch tray icon
while True:
loop_function() # executing every minute
time.sleep(60)
Its because, when you used the tray(), your main application started and the GUI main loop is initiated. It runs till your application exits, after which the while loop is executed.
However, if you want the loop to run simultaneously, you should integrate it with Qt's main loop. In Gtk we do this using GLib.add_main_thread and other methods, I don't know about Qt, but you can use this general solution using Threading.
from threading import Thread
import time
import os
import sys
from PySide2 import QtWidgets, QtGui
def loop_function():
print("Nice") # anything executable
def thread_loop():
while True:
loop_function() # executing every minute
time.sleep(60)
class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
def __init__(self, icon, parent=None):
QtWidgets.QSystemTrayIcon.__init__(self, icon, parent)
self.setToolTip(f'Wallpy')
menu = QtWidgets.QMenu(parent)
exit_ = menu.addAction("Exit")
exit_.triggered.connect(lambda: sys.exit())
menu.addSeparator()
self.setContextMenu(menu)
def tray():
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
tray_icon = SystemTrayIcon(QtGui.QIcon("tray.ico"), w)
tray_icon.show()
app.exec_()
my_loop = Thread(target=thread_loop, args=()) # Start the thread with no args
my_loop.start()
tray() # launch tray icon
My app has the following structure:
import tkinter as tk
from threading import Thread
class MyWindow(tk.Frame):
... # constructor, methods etc.
def main():
window = MyWindow()
Thread(target=window.mainloop).start()
... # repeatedly draw stuff on the window, no event handling, no interaction
main()
The app runs perfectly, but if I press the X (close) button, it closes the window, but does not stop the process, and sometimes even throws a TclError.
What is the right way to write an app like this? How to write it in a thread-safe way or without threads?
Main event loop should in main thread, and the drawing thread should in the second thread.
The right way to write this app is like this:
import tkinter as tk
from threading import Thread
class DrawingThread(Thread):
def __init__(wnd):
self.wnd = wnd
self.is_quit = False
def run():
while not self.is_quit:
... # drawing sth on window
def stop():
# to let this thread quit.
self.is_quit = True
class MyWindow(tk.Frame):
... # constructor, methods etc.
self.thread = DrawingThread(self)
self.thread.start()
on_close(self, event):
# stop the drawing thread.
self.thread.stop()
def main():
window = MyWindow()
window.mainloop()
main()
I defined a print function using QPrinter and QDialog. However, when I launch the printer dialog and then press cancel, the entire mainwindow goes into not responding mode. I have tried to do QtGui.QPrintDialog.close() but does not work.
Code:
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui
class QButton(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.button = QtGui.QPushButton('Button', self)
self.name='me'
self.button.clicked.connect(self.calluser)
def calluser(self):
Appli=QtGui.QApplication(sys.argv)
printer= QtGui.QPrinter()
doc=QtGui.QTextDocument("Set local variables in this printing slot." )
dialog = QtGui.QPrintDialog(printer)
dialog.setModal(True)
dialog.setWindowTitle("Print Document" )
if dialog.exec_() == True:
doc.print_(printer)
# dialog.addEnabledOption(QAbstractPrintDialog.PrintSelection)
def demo_QButton():
app = QtGui.QApplication(sys.argv)
tb = QButton()
tb.show()
app.exec_()
if __name__=='__main__':
demo_QButton()
You created a new application in the calluser method. Delete or comment the line:
Appli=QtGui.QApplication(sys.argv)
and try again. I think this time your main window will remain responsive.