Properly update restart GUI from another thread PyQT - python

So i have an process which has its own thread and writes(appends) to an output.txt. Also i have a GUI which reads from this output.txt. I want to update the GUI whenever there is new content in the Output.txt.
right now i do this by quiting and re-exec() the GUI. This works but looks awfull.
class _do_scan(QtCore.QThread):
trigger = QtCore.pyqtSignal()
def __init__(self):
QThread.__init__(self)
def run(self):
self.do_scan()
def do_scan():
#when found smth and written to output.txt
self.trigger.emit()
def main(options = None):
app = QtGui.QApplication(sys.argv)
scan_thread = _do_scan()
scan_thread.start()
scan_thread.trigger.connect(lambda: app.quit())
while scan_thread.isRunning():
window = Window()
window.show()
app.exec_()
window = Window()
window.show()
sys.exit(app.exec_())
Any idea how i can manage it better?
i tried to use
scan_thread.trigger.connect(lambda: window.update())
scan_thread.trigger.connect(lambda: window.repaint())
but none worked
Thanks in advance

Related

Threading a task beside a GUI PyQT4

So i am trying to run a PyQT GUI while another functions is gathering information in the background. If Information is found the GUI should update itself.
I am new in Threading so i googled a lot and found some good HowTo's although it does not work as it should.
when i run the program it just ends itself after 3 s.
Maybe you see some major mistake ive done.
Here is the basic code i am trying to get to run
class scan_Thread(QThread):
def __init__(self, samp_rate, band, speed, ppm, gain, args, prn):
QThread.__init__(self)
self.samp_rate=samp_rate
self.band=band
self.speed=speed
self.ppm=ppm
self.gain=gain
self.args=args
self.prn=prn
def __del__(self):
self.wait()
def run(self):
do_scan(self.samp_rate, self.band, self.speed,
self.ppm, self.gain, self.args, self.prn)
def start_gui():
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
#app.exec_()
#sys.exit()
def main(options = None):
def printfunc(found_list):
for info in sorted(found_list):
print info
get_thread = scan_Thread(options.samp_rate, options.band, options.speed,
options.ppm, options.gain, options.args, printfunc)
get_thread.start()
start_gui()
Thanks!
Many of the objects of the Qt classes and therefore of PyQt need to start some object of type Application (QCoreApplication, QtGuiApplication or QApplication), but only one of these objects must exist.
In your particular case QThread needs it. The previous classes are responsible for generating the necessary loops.
So you should modify your code to the following:
def main(options = None):
app = QtGui.QApplication(sys.argv) // before creating any PyQt object.
def printfunc(found_list):
for info in sorted(found_list):
print info
get_thread = scan_Thread(options.samp_rate, options.band, options.speed,
options.ppm, options.gain, options.args, printfunc)
get_thread.start()
window = Window()
window.show()
sys.exit(app.exec_())

Open window application in current window

I want to open a game application replacing the menu window.
So I have a game application which I can start with:
subprocess.call(["mygameprogram", "argument one"])
This opens up another window, but I want to replace the qt window with the game window without closing the menu window.
This is my MainWindow class:
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initMenu()
self.show()
def initMenu(self):
# load ui file
uic.loadUi("somefile.ui", self)
# add pushbutton
btn = QPushButton()
# add click listener
btn.clicked.connect(self.startLevel)
# add button to layout
self.layout_buttons.addWidget(btn)
def startLevel(self):
# open game, put the right code in here :D
pass
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = MainWindow()
sys.exit(app.exec_())
Is there any solution for that? And if not, what should I do instead?
Thanks in advance

interactive python - keeping console interactive with a GUI mainloop

I am wondering how one would create a GUI application, and interact with it from the console that started it.
As an example, I would like to create a GUI in PyQt and work with it from the console. This could be for testing settings without restarting the app, but in larger projects also for calling functions etc.
Here is a simple example using PyQt:
import sys
from PyQt4 import QtGui
def main():
app = QtGui.QApplication(sys.argv)
w = QtGui.QWidget()
w.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
when this is run with python -i example.py the console is blocked as long as the main-loop is executed.
How can I call w.resize(100,100) while the GUI is running?
ops, posted wrong answer before
there is a post in Stack about that
Execute Python code from within PyQt event loop
The following example uses the code module to run a console in the command prompt (be sure to run the script from the command line). Subclassing QThread provides a route by which the console can be run in a separate thread from that of the main GUI and enables some interaction with it. The stub example below should be easy enough to incorporate into a larger packaged PyQt program.
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import threading #used only to id the active thread
import code
import sys
class Worker(QThread): #Subclass QThread and re-define run()
signal = pyqtSignal()
def __init__(self):
super().__init__()
def raise_sys_exit(self): #more gracefully exit the console
print('(Deactivated Console)')
raise SystemExit
def setup_console(self,global_dict):
console_exit = {'exit': self.raise_sys_exit}
self.console = code.InteractiveConsole(locals=dict(global_dict,**console_exit))
def run(self):
try:
print('worker', threading.get_ident())
self.console.interact()
except SystemExit:
self.signal.emit()
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args,**kwargs)
self.data = [1,2,3,4] #some data we might want to look at
layout = QVBoxLayout()
self.b = QPushButton("Interact")
self.b.clicked.connect(self.b_clicked)
layout.addWidget(self.b)
w = QWidget()
w.setLayout(layout)
self.setCentralWidget(w)
self.worker = Worker()
self.worker.signal.connect(self.finished)
def finished(self):
self.b.setEnabled(True)
def b_clicked(self):
print('main',threading.get_ident())
self.worker.setup_console(globals()) #pass the global variables to the worker
self.worker.start()
self.b.setEnabled(False) #disable the GUI button until console is exited
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
The easiest way is to use IPython:
ipython --gui=qt4
See ipython --help or the online documentation for more options (e.g. gtk, tk, etc).

Does closing a GUI in PyQt4 destroy its children Qobjects by default

I'm trying to make a GUI that used QTimer to create a state machine, but when ever I close the GUI window the timer continues. I think I'm properly making the object that creates my Qtimer a child of the GUI but with the behavior I'm seeing it doesn't seem like it. Here is some code
class Ui_Form(QtGui.QWidget):
def __init__(self):
super(Ui_Form, self).__init__()
self.backEnd = BackEnd(self)
self.backEnd.start()
class BackEnd(QtCore.QObject):
def __init__(self,parent=None):
super(BackEnd,self).__init__(parent)
self.setParent(parent)
self.timer = QtCore.QTimer()
self.timer.setSingleShot(True)
QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.timerHandler)
def timerHandler(self):
print "Im here"
self.timer.start(1000)
def start(self):
self.timer.start(1000)
def stop(self):
self.timer.stop()
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
Form = QtGui.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
Form.show()
sys.exit(app.exec_())
Timer does not continue when I close GUI window, it works fine, as desired... anyway, try to override close event for your Ui_Form like this:
def closeEvent(self):
self.backEnd.stop()
I hope that helps.
Also, I've changed your main like this:
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
ui = Ui_Form()
ui.show()
sys.exit(app.exec_())
in your case it might be that Form = QtGui.QWidget() stays alive after you close GUI window. So try that modification first.

How to call multiple Dialogs in PyQt?

I have a main dialog and on that dialog there is a button. When the button is clicked, I want to open an another dialog.
Main Dialog code (Function which is called when the button is clicked in the main dialog):
def add_host(self):
x=add_host.Ui_Dialog1()
x.main()
default function:
if __name__ == "__main__":
import sys
global app
app = QtGui.QApplication(sys.argv)
Dialog = QtGui.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
Secondary dialog (add_host.py) code snapshot:
def main(self):
app1 = QtGui.QApplication(sys.argv)
Dialog1 = QtGui.QDialog()
ui1 = Ui_Dialog1()
ui1.setupUi1(Dialog1)
Dialog1.show()
sys.exit(app.exec_())
So when I run the code, it opens the secondary dialog but when I close it, it just freezes, and I get this error message:
File "testbot.py", line 175, in add_host
x.main()
File "/home/ppp/ppp/add_host.py", line 74, in main
sys.exit(app.exec_())
NameError: global name 'app' is not defined
Which does make sense, but I have no idea how to resolve it. I try several combinations without success, including adding and deleting app.exec_().
You cannot create multiple QApplications inside of the same script and thread. You are only supposed to have one...
This should be more like:
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
Dialog = QtGui.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
No global app. Although you should be doing your setupUI from within the class of your dialog.
Then when you want to show another dialog from with your app...say main(), you just create it and call show()
Here is a really basic example:
class Dialog(QDialog)
def __init__(self, parent):
super(Dialog, self).__init__(parent)
self.otherDialog = QDialog(parent=self)
self.otherDialog.show()
if __name__ == "__main__":
app = QApplication([])
dialog = Dialog()
dialog.show()
app.exec_()
You create a single QApplication and start its event loop by calling exec_(). From that point on, your main application is free to create more QWidgets. You never create another QApplication again at this point.
Also, I dont understand this part of your code:
def add_host(self):
x=add_host.Ui_Dialog1()
x.main()
The fact that you are calling a main() method on your UI object makes me think you are modifying the UI file and adding functionality to it, which you should not be doing. That ui file is subject to be overwritten every time you make changes in QT Designer and save out a new one. You should only be importing it and using its setupUI() method to apply it to your own custom classes.
A note about organization of your modules
When you are designing a PyQT application, you will always have a single entry point that will be called to start your app. This is the single and only location that should be creating your QApp and starting the event loop, and is usually done with in a if __name__ == "__main__" block to ensure its only done when its the main script. It should not be done within methods of your objects. For all your other modules where you define other Dialog, Widgets, etc, these should simply be classes that you import. As long as you have a running QApp, you are free to create and show these widgets.
Your code sample is a bit confusing - I don't understand why you have two mains, etc - anyway, maybe it's just a typo in add_host.py (app1.exec_() instead of app.exec_())
def main(self):
app1 = QtGui.QApplication(sys.argv)
...
sys.exit(app1.exec_())

Categories