I'm Working with PySide, and seeking a way to restart my Qt app. Does this depends on python, or it has to be controlled by Qt?
BY ROSTYSLAV'S SUGGESTION BELLOW :
class MyAppMainWindow(QMainWindow):
def __init__(self):
self.EXIT_CODE_REBOOT = -15123123
exit_code = self.EXIT_CODE_REBOOT
def slotReboot(self):
print "Performing application reboot.."
qApp.exit( self.EXIT_CODE_REBOOT )
def main():
currentExitCode = 0
app = QApplication(sys.argv)
ex = MyAppMainWindow()
while currentExitCode == ex.EXIT_CODE_REBOOT :
currentExitCode = app.exec_()
return currentExitCode
if __name__ == '__main__':
main()
Obviously I didn't fully understand. Pleas help.
There's a nice way presented by Qt Wiki on how to make your application restartable.
The approach is based on recreation of QApplication instance and not killing current process.
It can be easily adopted to PySide like the next snippet shows:
EXIT_CODE_REBOOT = -15123123 # you can use any unique value here
exit_code = EXIT_CODE_REBOOT # Just for making cycle run for the first time
while exit_code == EXIT_CODE_REBOOT:
exit_code = 0 # error code - no errors happened
app = QApplication(sys.argv)
...
exit_code = app.exec()
You just need to setup proper exit code through the API presenteed by QApplication before finishing your app. The you can hook up new configuration or whatever you need when new application instance is created.
The topic is quite old, but i see there is no proper solution provided. So here it is (based on what Rostyslav Dzinko suggested):
EXIT_CODE_REBOOT = -11231351
from PySide import QtGui, QtCore
import sys
class MyApp(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MyApp, self).__init__(parent)
def restart (self):
#DO stuff before restarting here
return QtCore.QCoreApplication.exit( EXIT_CODE_REBOOT )
def start_app():
exit_code = 0
while True:
try:
app = QtGui.QApplication(sys.argv)
except RuntimeError:
app = QtCore.QCoreApplication.instance()
myap = MyApp()
myap.show()
exit_code = app.exec_()
if exit_code != EXIT_CODE_REBOOT:
break
return exit_code
if __name__ == '__main__':
start_app()
Related
I am getting an issue when trying to open a PyQt window.
The code below is an example of my original code. When I imported the module in import Test and ran test.Start(), I got the following error:
QCoreApplication::exec: The event loop is already running
After some research, I found out it was because I had already already made a QApplication.
test.py....
import sys
def Start():
app = QApplication(sys.argv)
m = myWindow()
m.show()
app.exec_()
class myWindow():....
if __name__ == "__main__":
Start()
So then I read that I could rewrite my code like this and it would fix the error:
test.py....
def Start():
m = myWindow()
m.show()
class myWindow():....
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
Start()
app.exec_()
Now I no longer get the QCoreApplication::exec: The event loop is already running error, but my window closes almost immediately after opening.
You need to keep a reference to the opened window, otherwise it goes out of scope and is garbage collected, which will destroy the underlying C++ object also. Try:
def Start():
m = myWindow()
m.show()
return m
class myWindow():....
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
window = Start()
app.exec_()
You can also do:
def Start():
global m
m = myWindow()
m.show()
class myWindow():....
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
window = Start()
app.exec_()
Use the following code. Your problem is in your imports and using "show" as a name for function as far as I assume. You haven't provided what you have written in your class, so it's difficult to guess. But following code works like a charm. ;-)
Best wishes, good luck!
import sys
from PyQt5 import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
app = QApplication(sys.argv)
def Start():
m = myWindow()
m.showWid()
sys.exit(app.exec())
class myWindow:
def __init__(self):
self.window = QWidget()
self.window.setWindowTitle("Program Title")
self.window.setFixedWidth(600)
self.window.setStyleSheet("background: #18BEBE;")
def showWid(self):
self.window.show()
if __name__ == "__main__":
Start()
I want to restart my app, but I follow the tutorial and add systemtray icon. every time restart the app, the systemtray not disappear, I found the app not really restart by some reason.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MainWindow(QMainWindow):
EXIT_CODE_REBOOT = 122
def __init__(self):
super().__init__()
self.restart_button = QPushButton('restart')
self.restart_button.clicked.connect(self.onRestart)
self.setCentralWidget(self.restart_button)
self.systray = QSystemTrayIcon(self)
icon = self.style().standardIcon(QStyle.SP_TrashIcon)
self.systray.setIcon(icon)
self.systray.show()
def onRestart(self, checked):
QApplication.exit(self.EXIT_CODE_REBOOT)
if __name__ == '__main__':
currentExitCode = MainWindow.EXIT_CODE_REBOOT
while currentExitCode == MainWindow.EXIT_CODE_REBOOT:
app = QApplication(sys.argv)
mainwindow = MainWindow()
mainwindow.show()
currentExitCode = app.exec()
app = None
each time restart the app, the previous system tray always existing, it is like it start an other process, I want the only process and not consuming any resources.
I tried your code and it works fine on Linux, but I also found similar reports (like this) about persistent icon after quit on Windows.
While doing a self.systray.hide() before quitting should be fine enough, I think that deleting the object from Qt's side (not by using del) might be better:
def onRestart(self, checked):
self.systray.deleteLater()
QApplication.exit(self.EXIT_CODE_REBOOT)
We are talking about python 2.7 and PyQt4.
I'm working with an open-source program for the eeg analysis called PyCorder, that received data from a system electrodes-amplifier and plot them in a GUI; we can consider it as a black box for the purposes of this question. I implemented a simple interface with Qt designer. My aim is to run both the PyCorder and my interface at the same time in a way that they can exchange data between them.
Here the lines of the code where my interface is launched:
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
I guess it's common to any interface done with Qt designer;
Following, the PyCorder launching part:
def main(args):
print "Starting PyCorder, please wait ...\n"
setpriority(priority=4)
app = Qt.QApplication(args)
try:
win = None
win = MainWindow()
win.showMaximized()
if ShowConfirmationDialog:
accept = Qt.QMessageBox.warning(None, "PyCorder Disclaimer", ConfirmationText,
"Accept", "Cancel", "", 1)
if accept == 0:
win.usageConfirmed = True
app.exec_()
else:
win.close()
else:
win.usageConfirmed = True
app.exec_()
except Exception as e:
tb = GetExceptionTraceBack()[0]
Qt.QMessageBox.critical(None, "PyCorder", tb + " -> " + str(e))
if win != None:
win.close()
# show the battery disconnection reminder
if ShowBatteryReminder and win and win.usageConfirmed:
DlgBatteryInfo().exec_()
print "PyCorder terminated\n"
if __name__ == '__main__':
main(sys.argv)
Is it sufficient to know just these two parts of the respective codes to answer my question? Is there any toolbox that can be useful to reach my goal?
The best idea comes to my mind is to use multi processing libraries in order to run QT several times. multiprocessing is one of the libraries you can use.
There are a number of ways to do this, but I prefer to use a central "window manager" to acts as the owner and inter-communication hub of the two windows. Below is a sample of that technique that will need to be adapted to your needs. Note that I use Qt5. I tested on Qt5, and then attempted to translate to Qt4 without testing. It should be right, but might need a little tweeking.
from PyQt4 import QtCore, QtGui
class WindowManager(QtCore.QObject):
"""
Inheriting from QObject has benefits.
For instance, the WindowManager can not have pyQtSignal members, if needed
"""
def __init__(self):
super(WindowManager, self).__init__()
self.firstWindow = FirstWindow(self)
self.secondWindow = SecondWindow(self)
self.firstWindow.show()
self.secondWindow.show()
class FirstWindow(QtGui.QMainWindow):
def __init__(self, manager):
super(FirstWindow, self).__init__()
self.manager = manager
self.mainWidget = QtGui.QWidget()
self.setCentralWidget(self.mainWidget)
self.mainLayout = QtGui.QVBoxLayout(self.mainWidget)
self.clickyButton = QtGui.QPushButton("Click me")
self.mainLayout.addWidget(self.clickyButton)
self.clickyButton.clicked.connect(self.clickyButtonClicked)
def clickyButtonClicked(self, checked=None):
self.manager.secondWindow.setMessage("Clicky button clicked")
class SecondWindow(QtGui.QMainWindow):
def __init__(self, manager):
super(SecondWindow, self).__init__()
self.manager = manager
self.mainWidget = QtGui.QWidget()
self.setCentralWidget(self.mainWidget)
self.mainLayout = QtGui.QVBoxLayout(self.mainWidget)
self.messageBox = QtGui.QLabel()
self.mainLayout.addWidget(self.messageBox)
def setMessage(self, message):
self.messageBox.setText(message)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
manager = WindowManager()
sys.exit(app.exec_())
I'm trying to catch the global about to quit signal from my application class which subclasses QApplication. Here is how I attempt to set it up in main.
def cleanUp():
os.system('rosnode kill -a')
sys.exit(0)
## Start Qt event loop
if __name__ == '__main__':
app = Application(sys.argv)
app.aboutToQuit.connect(cleanUp)
app.exec_()
The issue is that this doesn't seem to catch the signal I have apparently connected.
Edit
I'm using PyQtGraph, so preferably is there some way to catch global window closes?
# The main application
class Application(QtGui.QApplication):
def __init__(self, args):
QtGui.QApplication.__init__(self, args)
self.plot = pg.plot(title="UWB")
self.raw_signal = self.plot.plot()
self.filtered_signal = self.plot.plot()
# Start the main loop
self.listen()
You can also override the close event when your QMainWindow is closed. That might be just as useful depending on your use case.
# override exit event
def closeEvent(self, event):
cleanUp()
# close window
event.accept()
Edit: This minimal example works for me; 'closing' is printed when the plot window is closed.
import pyqtgraph as pg
from PyQt4 import QtGui
import sys
# The main application
class Application(QtGui.QApplication):
def __init__(self, args):
QtGui.QApplication.__init__(self, args)
self.plot = pg.plot(title="UWB")
def cleanUp(self):
print 'closing'
## Start Qt event loop
if __name__ == '__main__':
app = Application(sys.argv)
app.aboutToQuit.connect(app.cleanUp)
sys.exit(app.exec_())
How can I use the QProcess.finished() to call a different Python3 script.
Here's the script I call:
#!/usr/bin/python
from PyQt4.QtGui import QApplication
from childcontrolgui import childcontrolgui
def main():
import sys
app = QApplication(sys.argv)
wnd = childcontrolgui()
wnd.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
To call the script I use the code as seen here
def properties(self):
command="python3 ../GUI/main.py"
self.process=QProcess()
self.process.finished.connect(self.onFinished)
self.process.startDetached(command)
def onFinished(self, exitCode, exitStatus):
self.Check_Timer.stop()
self.Logout_Timer.stop()
self.Firstrun=True
self.initControl()
Starting of the process works, the window from main.py is shown, but it seems, finished isn't fired. Nothing happens, when I close the Window from main.py
You can't get a signal when you use startDetached() because you have no object. Use ordinary start() instead.
And don't forget to start QApplication within control script, too.
class Control(QObject):
def properties(self):
self.process=QProcess()
self.process.finished.connect(self.onFinished)
self.process.start('python3', ['../GUI/main.py'])
def onFinished(self, exitCode, exitStatus):
[...]
if __name__ == '__main__':
app = QApplication(sys.argv)
co = Control()
co.properties()
sys.exit(app.exec_())