how to restart the app with single process? - python

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)

Related

Can't Kill PyQT Window after closing it. Which requires me to restart the kernal

I guess that I am not closing my PyQT5 Window correctly. I am using spyder (3.3.5) which I have installed with anaconda, to program a pyqt5 program. I am using qt creator to design my ui file, which I load using the loadUi function in pyqt package. Everything works fine with the code, until I need to close it. I close the window via the close button (the x button in the top right). The window itself is closed, but it seems like the console (or shell) is stuck, and I can't give it further commands or to re run the program, without having to restart the kernel (to completely close my IDE and re opening it).
I have tried looking for solutions to the problem in the internet, but none seems to work for me. Including changing the IPython Console > Graphics to automatic.
Edit: Also Created an issure:
https://github.com/spyder-ide/spyder/issues/9991
import sys
from PyQt5 import QtWidgets,uic
from PyQt5.QtWidgets import QMainWindow
class Mic_Analysis(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.ui=uic.loadUi("qt_test.ui",self)
...
if __name__ == "__main__":
def run_app():
if not QtWidgets.QApplication.instance():
app = QtWidgets.QApplication(sys.argv)
else:
app=QtWidgets.QApplication.instance()
mainWin=Mic_Analysis()
mainWin.show()
app.exec_()
run_app()
If someone have any suggestion I would be very happy to hear them.
For me, it helped to remove the 'app.exec_()' command.
But then it closes immediatly when running the code. To keep the window open, I needed to return the MainWindow instance to the global scope (or make it a global object). My code looks like this:
from PyQt5 import QtWidgets
import sys
def main():
if not QtWidgets.QApplication.instance():
app = QtWidgets.QApplication(sys.argv)
else:
app = QtWidgets.QApplication.instance()
main = MainWindow()
main.show()
return main
if __name__ == '__main__':
m = main()
Try adding :
app.setQuitOnLastWindowClosed(True)
to your main() function
def main():
app = QApplication(sys.argv)
app.setQuitOnLastWindowClosed(True)
win = MainWindow()
win.show()
sys.exit(app.exec_())
Surprizinglly, for me this works well. No QApplication is needed.
It seems to work in another thread.
from PyQt5 import QtWidgets,uic
class Ui(QtWidgets.QDialog):
def __init__(self):
super().__init__()
uic.loadUi('./test.ui',self)
self.show()
w=Ui()

PyQT exit error in SPYDER

This is PyQT code that I have to be executed in Spyder. The first time, I executed it, it works well. On the second time, it says:
QWidget: Must construct a QApplication before a QPaintDevice "
I searched for solution but nothing worked for me.
from PyQt4 import QtGui, QtCore
import sys
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.button = QtGui.QPushButton('Test', self)
self.button.clicked.connect(self.handleButton)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.button)
def handleButton(self):
print ('Hello World')
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
app.exec_()
#sys.exit(app.exec_())
I even commented sys.exit() which some people proposed. Could someone help me to get rid of this error as I am restarting the kernel every other time to execute.
First, your example is not really minimal. You'll observe, that
from PyQt4 import QtGui
if __name__ == '__main__':
app = QtGui.QApplication([])
w = QtGui.QWidget()
w.show()
app.exec_()
already does the trick.
My guess is that the console in which you let this script run twice is not deleting the QApplication (type app in the console you see the variable is still there).
In the second run, the newly created QApplication interferes with the still existing from the old run. They all run within the same console and it depends a bit on what spyder does when running a file.
To circumvent this delete the app before another run:
del app

PyQt5 Interrupt Close Event from Outside the Main Gui Module

I use Qt Designer to build my GUI's and convert them to py files using pyuic5. My end goal here is to interrupt the user from closing the program when a variable == 1 and present them with an 'are you sure you want to close?' type dialog. If said variable == 0 then just close the program normally.
I have seen lots of examples on how to do this, but all of them require editing the code in the GUI module. I import my gui.py file created by pyuic5 into my main script where I do all my connections to buttons, line edits, etc.. I do this so that at anytime I can update the GUI with Qt Designer and not affect the programs functionality.
Is there a way to do this from my main script that has the GUI module from Qt Designer imported?
Example of how my main script is structured:
import philipsControlGui
import sys
def main():
MainWindow.show()
sys.exit(app.exec_())
def test():
print('test')
# Main window setup
app = philipsControlGui.QtWidgets.QApplication(sys.argv)
MainWindow = philipsControlGui.QtWidgets.QMainWindow()
ui = philipsControlGui.Ui_MainWindow()
ui.setupUi(MainWindow)
# Main window bindings
ui.onButton.clicked.connect(test)
### Can I insert something here to do: if user closes the window... do something else instead?
if __name__ == "__main__":
main()
You should create a subclass from your imported gui so you can reimplement the closeEvent method:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from philipsControlGui import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setUpUi(self)
self.ui.onButton.clicked.connect(self.test)
self._check_close = True
def test(self):
print('test')
self._check_close = not self._check_close
def closeEvent(self, event):
if self._check_close:
result = QtWidgets.QMessageBox.question(
self, 'Confirm Close', 'Are you sure you want to close?',
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
if result == QtWidgets.QMessageBox.Yes:
event.accept()
else:
event.ignore()
def main():
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
If there's a specific 'ExitButton' in your design, you should be able to connect it in the main code and create a pop up dialog. You would have to import the QtCore/QtGui components. I always write my GUI directly (QtDesigner is pain when it comes to these things) so I'm assuming something like this:
from PyQt4.QtGui import *
from PyQt4.QtCore import *
[YOUR CODE]
ui.ExitButton.clicked.connect(Exit)
def Exit():
msg = QMessageBox()
msg.setIcon(QMessageBox.Information)
msg.setText("Are you sure you want to close this window?")
msg.setWindowTitle("MessageBox demo")
msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
msg.buttonClicked.connect(msgbtn)
retval = msg.exec_()
print "value of pressed message box button:", retval

Is my threading proper ? if yes then why code is not working?

I am creating an alarm clock in python using PyQt4 and in that I am using LCD display widget, which display current updating time. For that I am using threading. But I am new to it so the problem is I have no clue how to debug that thing.
This is my code
import sys
from PyQt4 import QtGui, uic
import time
import os
from threading import Thread
class MyWindow(QtGui.QMainWindow):
def __init__(self):
super(MyWindow, self).__init__()
uic.loadUi('AlarmClock_UI.ui', self)
self.show()
self.comboBox.setCurrentIndex(0)
self.comboBox.currentIndexChanged.connect(self.getSelection)
self.lineEdit.setText('Please select the reminder type')
timeThread = Thread(target = self.showTime())
timeThread.start()
def getSelection(self):
if self.comboBox.currentIndex() == 1:
self.lineEdit.setText('Select the alarm time of your choice')
elif self.comboBox.currentIndex() == 2:
self.lineEdit.setText('Use those dials to adjust hour and minutes')
else:
self.lineEdit.setText('Please select the reminder type')
def showTime(self):
showTime = time.strftime('%H:%M:%S')
self.lcdNumber.display(showTime)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = MyWindow()
sys.exit(app.exec_())
I tried while loop in showTime() function then it was not even loading GUI just running in the background.
Thanks :)
As has been said elsewhere, you do not need to use threading for this, as a simple timer will do. Here is a basic demo script:
import sys
from PyQt4 import QtCore, QtGui
class Clock(QtGui.QLCDNumber):
def __init__(self):
super(Clock, self).__init__(8)
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.showTime)
self.timer.start(1000)
self.showTime()
def showTime(self):
time = QtCore.QTime.currentTime()
self.display(time.toString('hh:mm:ss'))
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Clock()
window.setWindowTitle('Clock')
window.setGeometry(500, 100, 400, 100)
window.show()
sys.exit(app.exec_())
Qt does not support doing GUI operations in threads other than the main thread. So when you call self.lcddisplay.display(showTime) from within the context of your spawned thread, that is an error and Qt will not work correctly.
As tdelaney suggested in his comment, the best way to handle this sort of thing is to use a QTimer to emit a signal at the appropriate intervals, and update your lcddisplay in the slot that signal is connected to.
(if you insist on using threads, however, e.g. as a learning exercise, then your spawned thread would need to send a message to the main thread to tell the main thread to do the display update, rather than trying to do the update itself)

How to Restart PyQt4 Application

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.

Categories

Resources