Currently trying to build a GUI.
Whenever I try to exit the GUI using either the button I created or the exit button on the OS it takes some time and at the end the console shows Restarting kernel... without any other msg.
I am using Spyder with Python 3.9.
BTW I am not using sys.exit() as I saw in some other questions that it was the problem kind of.. I really don't get it..
The code :
class Class_Thread(filex.Classx,QThread):
def run(self):
self.setTerminationEnabled(True)
"""
the code the gui runs
"""
class UI(QMainWindow):
def __init__(self):
super(UI,self).__init__()
#load the UI file
uic.loadUi("test.ui", self)
self.Class_instance = Class_Thread()
#define the widgets
self.start_button = self.findChild(QPushButton,"start_button")
self.reset_button = self.findChild(QPushButton,"reset")
self.exit_button = self.findChild(QPushButton,"exit")
self.start_button.clicked.connect(self.start_check)
self.reset_button.clicked.connect(self.reset_code)
self.exit_button.clicked.connect(QtCore.QCoreApplication.instance().quit)
#show the app
self.show()
def reset_code(self):
self.Class_instance.quit()
self.reset_button.setEnabled(False)
self.start_button.setEnabled(True)
def start_check(self):
self.reset_button.setEnabled(True)
self.start_button.setEnabled(False)
self.CC_Instance.start()
app = QApplication(sys.argv)
UIWindow = UI()
UIWindow.show()
UIWindow.activateWindow()
app.exec_()
Related
I am trying to decouple entirely my GUI from my controller class, and for some reason I can't seem to manage to connect my buttons from outside of my GUI class itself.
Here's a small example of what I mean :
import sys
from PySide6 import QtWidgets
class Gui(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Gui, self).__init__(parent)
layout = QtWidgets.QHBoxLayout(self)
self.button = QtWidgets.QPushButton("Do stuff")
layout.addWidget(self.button)
class Controller(object):
def do_stuff(self):
print("something")
def startup(parent):
ctrl = Controller()
gui = Gui(parent)
gui.button.clicked.connect(ctrl.do_stuff)
return gui
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
dialog = QtWidgets.QDialog()
gui = startup(dialog)
dialog.show()
sys.exit(app.exec_())
I would expect this code, when run, to display a GUI with one push button (which it does), and when pressing the push button, I'd expect the word "something" to get printed. However this doesn't seem to be the case.
I might just be too tired, but I can't find the solution.
What am I missing?
Thanks a lot in advance!
ctrl = None
gui = None
def startup(parent):
global ctrl
global gui
ctrl = Controller()
gui = Gui(parent)
gui.button.clicked.connect(ctrl.do_stuff)
return gui
try this, and it does work. when the variable is in the function, it will be destroyed before the function is finished. the global variable is not a good coding style but is a simple way to figure out your confusion.
I'm trying to make a simple Weather app that also shows the current time. However, after multiple trial and error i am asking for help. I've come to the conclusion that i must commit to threading where the clock is continously run in the background to my PyQt UI. Although, it only freezes and crashes, and i can't understand why. As you can understand i've checked multiple posts already on this issue such as, [1] and [2]. But i'm none the wiser...
This is the minimal reproducible code:
class Clock(QObject):
updated_time = pyqtSignal()
def __init__(self, parent=None):
QObject.__init__(self,parent=parent)
def get_time(self):
#This code is meant to be run continously
#For troubleshooting, ive removed the while-loop momentarily
QThread.sleep(1)
now = datetime.now()
current_time = now.strftime("%H:%M")
self.updated_time.emit()
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.initUI()
def initUI(self):
self.setWindowTitle('WeatherApp')
self.resize(700, 500)
self.clock_label = QLabel(self)
self.clock_label.setText('make me change')
self.show()
thread = QThread()
worker = Clock()
worker.moveToThread(thread)
thread.started.connect(lambda: worker.get_time())
worker.updated_time.connect(self.update_clock())
thread.start()
def update_clock(self):
self.clock_label.setText(current_time)
def main():
app = QApplication(sys.argv)
mw = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The current code creates the window with the clock label taking the value of the intially declard variable, current_time. In the background, the function from the worker (do_work) is running in the background, iterating continously with a 1 second delay. As i understand from post 1, i should not update the UI from a thread, but even with the invokeMethod i am unable to achieve any success.. Shouldn't the problem be as easy as to emit a signal from the function do_work back to the App? I've adding one but i receive the error: "AttributeError: 'QThread' object has no attribute ".
Is it possible to set up a Python script with a PyQt5 GUI such that an active terminal can interact with it?
An example project:
from PyQt5 import QtWidgets from PyQt5.QtCore import pyqtSlot
class Machine:
"""Simpel state machine"""
STATE_IDLE = 'idle'
STATE_OPERATION = 'operation'
def __init__(self):
self.state = self.STATE_IDLE
def get_state(self):
return self.state
def set_state(self, new_state):
self.state = new_state
#pyqtSlot() def on_click():
"""Callback for the PyQt button"""
print('State:', machine.get_state())
if __name__ == '__main__':
# Create machine instance
machine = Machine()
# Set up GUI
app = QtWidgets.QApplication([])
window = QtWidgets.QWidget()
layout = QtWidgets.QVBoxLayout()
label = QtWidgets.QLabel('Hello World!')
button = QtWidgets.QPushButton('Go')
button.clicked.connect(on_click)
layout.addWidget(label)
layout.addWidget(button)
window.setLayout(layout)
window.show()
code = app.exec()
exit(code)
I would like to run this script and to then be able to access the objects from the same terminal. Something like:
$ python main.py
State: idle [< I just pressed the GUI button]
>> machine.set_state(Machine.STATE_OPERATION)
State: operation [< I just pressed the GUI button again]
If I run it like:
python -i main.py
The command line hangs until the application was closed (that's what .exec() does after all), but then I can access machine. Can I make .exec() not hang like this? Maybe run app from a separate thread?
EDIT: I found that thy Pyzo IDE allows you to create a shell with PyQt5 support, which handles the PyQt event loop. So when using the script above with such a Pyzo shell, I can remove code = app.exec() exit(code) because Pyzo will run the event loop and keep the window alive. Now I'd like to do the same across all IDEs.
I've put together some test code to figure out how to launch a simple pyqt Ui_Dialog multiple times during a script. I want launch the window depending on certain conditions as my script is running. The idea is that it is just a popup notification window with different text and the user will click ok. I designed the window in QtDesigner and inherited the generated code in another class:
class MsgWindow(QtGui.QDialog):
def __init__(self,parent=None):
QtGui.QWidget.__init__(self,parent)
self.app = QtGui.QApplication(sys.argv)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
QtCore.QObject.connect(self.ui.OK, QtCore.SIGNAL('clicked()'),self.close)
def AddText(self,text):
""" Method to add text to textEdit box """
self.ui.textEdit.append(text + '\n')
def closeEvent(self, event):
print "Closing the app"
#self.deleteLater()
if __name__=='__main__':
app = QtGui.QApplication(sys.argv)
myapp = MsgWindow()
myapp.show()
sys.exit(app.exec_())
So then my test script just launches the window (user closes it) and repeats. The issue is that after the last close, python crashes (python.exe has stopped working). Here is the test script code:
app = QtGui.QApplication(sys.argv)
dlg = MsgWindow()
for x in range(0,3):
dlg.AddText("This is a test, iteration: %d"%x)
dlg.exec_()
#sys.exit(app.exec_())
time.sleep(2)
What is the correct way to do this without crashing?
Thank you.
Is there a way to restart PyQt application QApplication
I have an app created with pyqt4 and python 2.6 using below code
app = QtGui.QApplication(sys.argv)
i have settings options where i set some settings. Now when i save settings i need to reload the application so that new settings are effected. Without the need of end user to exit and launch the app again.
I had a similar problem and simply used this at the appropriate place:
subprocess.Popen([__file__])
sys.exit(0)
It was a simple application, and didn't need any further arguments.
I explain how I did it :
I create a extra one file main.py which calls my actual main program file dash.py.
And I emits a signal for restarting (my programs auto updates at the closeEvent) so I required to emit a signal for it. This is the snippets hope this will help you.
This one is in my main program file in dash.py
def restart(self):
# create a signal equivalent to "void someSignal(int, QWidget)"
self.emit(QtCore.SIGNAL("RESTARTREQUIRED"), True)
This one in main.py which calls actual program only and restarts the app
import sys
from PyQt4 import QtGui,QtCore
from bin import dash
if __name__ == "__main__":
application = QtGui.QApplication(sys.argv)
uDesk = dash.app()
uDesk.show()
uDesk.actionRestart.triggered.disconnect()
# define restart slot
#QtCore.pyqtSlot()
def restartSlot():
print 'Restarting app'
global uDesk
uDesk.deleteLater()
uDesk = dash.app()
uDesk.show()
uDesk.actionRestart.triggered.disconnect()
uDesk.actionRestart.triggered.connect(restartSlot)
print 'New app started !'
QtCore.QObject.connect(uDesk,
QtCore.SIGNAL("RESTARTREQUIRED"),
restartSlot)
uDesk.actionRestart.triggered.connect(restartSlot)
sys.exit(application.exec_())
Hope this was helpful !!
EDIT: Changing the way to get the application path
You could just start a new process and exit yours, something like this: (CODE NOT TESTED, but based on this answer)
// Restart Application
def restart(self, abort):
// Spawn a new instance of myApplication:
proc = QProcess()
//proc.start(self.applicationFilePath());
import os
proc.start(os.path.abspath(__file__))
self.exit(0);
Code it as a method of your Qapplication or even a function if you don't feel like subclassing
This is how I restart TicTacToe game in PySide (it should be the same in PyQt):
I have a single class - a QWidget class - in which is coded the Tic Tac Toe game. To restart the application I use:
import subprocess
a QPushButton() like so:
self.button = QPushButton("Restart", self)
the connection of the button to Slot:
self.buton.clicked.connect(self.restartGame)
the Slot for this button, like so:
def restartGame(self):
self.close()
subprocess.call("python" + " TicTAcToe.py", shell=True)
All these are in the same - single - class. And what these do: close the active window of the game and create a new one.
How this code looks in the TicTacToe class:
import subprocess
class TicTacToe(QWidget):
def __init__(self):
QWidget.__init__(self)
self.button = QPushButton("Restart", self)
self.buton.clicked.connect(self.restartGame)
def restartGame(self):
self.close()
subprocess.call("python" + " TicTacToe.py", shell=True)
def main():
app = QApplication(sys.argv)
widget = TicTacToe()
widget.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
EDIT
I know this doesn't answer the question (it doesn't restart a QApplication), but I hope this helps those who want to restart their QWidget single class.