Python exiting unexpectedly while closing GUI application - python

I am trying to write a simple menu driven GUI program.
Following are the environment:
PyQt5 ver.5.10.1
Python 3.6.4
Mac OS Sierra
PyQt5 was installed using pip3.
Here is the code I am using:
from PyQt5.QtWidgets import (QMainWindow, QApplication,
QWidget, QPushButton, QAction)
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot
class myApp(QMainWindow):
def __init__(self):
super().__init__()
self.title = 'Some App'
self.left = 10
self.top = 10
self.width = 480
self.height = 260
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.statusBar()
pkMenuBar = self.menuBar()
mnuFile = pkMenuBar.addMenu("File")
mnuFile.addAction("Create New")
mnuQuit = QAction(QIcon("ico1.png"), " Quit", self)
mnuQuit.setShortcut("Ctrl+Q")
mnuQuit.setStatusTip("Quit Application")
mnuFile.addAction(mnuQuit)
mnuFile.triggered[QAction].connect(self.triggerAct)
self.show()
def triggerAct(self, x):
if x.text() == "Create New":
print("Trigger Create New...")
elif x.text() == " Quit":
mnuQuit.triggered.connect(self.close)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
ex = myApp()
sys.exit(app.exec_())
On executing the code (using IDLE) the GUI loads and the menu items (Actions) are also working as expected.
When the menu item "Quit" is called the app closes as well as the python icon (from the system tray). But after about 5-10 seconds I keep getting a message saying "Python quit unexpectedly".
I have been trying to figure out the problem using possible solns. by following leads on the net (like sys.exit(), app.quit() ) but every time I face the same result.
I have coding experience on ABAP/4 and VB.Net but this is very early stages for me so far as GUI coding on Python/PyQt is concerned.
Will appreciate if a lead is provided so that I may progress in this new endeavor of mine.
Thanks

The problem is really simple: mnuQuit is a variable not a member of the class so it can not be accessed by other methods of the class, plus I see it unnecessary to use that line of code, just call close():
def triggerAct(self, x):
if x.text() == "Create New":
print("Trigger Create New...")
elif x.text() == " Quit":
self.close()
# mnuQuit.triggered.connect(self.close)
It is not appropriate to call exit() within the GUI because the GUI has to free memory and if you call exit() it does not give you the time to do it. with close() the GUI closes correctly.

def triggerAct(self, x):
if x.text() == "Create New":
print("Trigger Create New...")
elif x.text() == " Quit":
exit()
I think exit() will work fine in your case.

Related

With PyQt5, implement two windows looping forever automatically

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

Python crashes when I try to open a custom imported PyQt5 window class

I am a bit of a rookie when it comes to Python, and even more so with PyQt5. With that said, I am not sure how to move forward with the error I am getting, and I am hoping someone can give me some wisdom here.
I am trying to connect an external test PyQt5 window script file to my main GUI structure. I have made a simple drop down menu GUI with a button that is supposed to run the external script that will open another window. I am trying to execute it with this command: test_dropButton.action.triggered.connect(testWindowButton)
I keep getting an interesting error that seems to hint that Python is crashing as I get this error:
Process finished with exit code -1073740791 (0xC0000409) and from my research this means that I could be doing a number of things from trying to call a function that does not exist, to PyQt5 not throwing an exception correctly. I am unsure if it is because my custom window script does not have a function that simply calls the window to show on the screen, however my init method should be doing that when the class is called, or did I just goof and forget I need a constructor first?
I have also seen explanations of this error as a threading issue in which trying to run an external script can cause Python to crash due to threading issues. Perhaps I need to multi thread the external python script?
Either way, can someone explain to me the above error, and tell me exactly what is going on, and why it might be crashing?
Here is my code:
#This is a snippet of my main GUI structure
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon
import TrainHelloWorld as hi
mainMenu = self.menuBar()
trainMenu = mainMenu.addMenu('Test')
testWindowButton = hi.Greeting()
test_dropButton = QAction('test', self)
test_dropButton.setShortcut('Ctrl+T')
test_dropButton.setStatusTip('Test the button')
test_dropButton.action.triggered.connect(testWindowButton.show())
trainMenu.addAction(test_dropButton) # add test button to dropdown menu
Here is the imported script:
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon
import sys
class Greeting(QMainWindow):
def __init__(self):
super().__init__()
self.title = 'Dummy Hello'
self.left = 10
self.top = 10
self.width = 640
self.height = 400
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
greetingLabel = QLabel()
greetingLabel.setText("You called a Python function in a QAction menu, YOU DID IT!")
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Greeting()
sys.exit(app.exec_())
I expect the program to open a single main window with a drop down menu with a single menu labeled "test" with a button names "test" that runs an imported script that opens another window.
Try it:
main.py
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon
import TrainHelloWorld as hi
class MyMainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('MyMainWindow')
mainMenu = self.menuBar()
trainMenu = mainMenu.addMenu('Test')
self.testWindowButton = hi.Greeting()
test_dropButton = QAction('test', self)
test_dropButton.setShortcut('Ctrl+T')
test_dropButton.setStatusTip('Test the button')
# test_dropButton.action.triggered.connect(testWindowButton.show())
# ------ --
test_dropButton.triggered.connect(self.testWindowButton.show) # - `.action`, - `()`
trainMenu.addAction(test_dropButton) # add test button to dropdown menu
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MyMainWindow()
ex.show()
sys.exit(app.exec_())
TrainHelloWorld.py
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon
class Greeting(QMainWindow):
def __init__(self):
super().__init__()
self.title = 'Dummy Hello'
self.left = 520
self.top = 280
self.width = 640
self.height = 400
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
greetingLabel = QLabel(self) # + self
greetingLabel.setGeometry(170, 200, 300, 50) # +++
greetingLabel.setText("You called a Python function in a QAction menu, YOU DID IT!")
# --- self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Greeting()
ex.show()
sys.exit(app.exec_())

Move QtWidgets.QtWidget using mouse

I want to move a QtWidgets.QtWidget using the mouse (not a QPushButton, QLabel etc.). I've searched everywhere on the web, but couldn't find an answer for this. mousePressEvent seemed to be the way, but it doesn't work.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_hGUI(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
def setupUi(self, hGUI):
hGUI.setObjectName("hGUI")
hGUI.resize(161, 172)
hGUI.setMinimumSize(QtCore.QSize(200, 200))
hGUI.setMaximumSize(QtCore.QSize(200, 200))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
hGUI = QtWidgets.QWidget()
ui = Ui_hGUI()
ui.setupUi(hGUI)
hGUI.show()
sys.exit(app.exec_())
I'm using Python 3.5, I'm creating the GUI using Qt Designer, then translate it to python code.
Edit: I'm trying to move a borderless windows by click on it.
That's a really simple question sir,
Let's say you just have to have an variable that holds the position of your widget and interact with it according to your needs.
This position variable let's call it "oldPos".
Now inside your mouse press you update this position.
By the last but not least, you relate your "oldPos" and your mouseMove actual position and move your widget.
Wallahhhh, here we have a beautiful and simple movable widget by mouse events.
Here is the simplest example.
from PyQt5.QtWidgets import QWidget
class MyMovableWidget(QWidget):
"""WToolBar is a personalized toolbar."""
homeAction = None
oldPos = QPoint()
def __init__(self):
super().__init__()
def mousePressEvent(self, evt):
"""Select the toolbar."""
self.oldPos = evt.globalPos()
def mouseMoveEvent(self, evt):
"""Move the toolbar with mouse iteration."""
delta = QPoint(evt.globalPos() - self.oldPos)
self.move(self.x() + delta.x(), self.y() + delta.y())
self.oldPos = evt.globalPos()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
coolWidget = MyMovableWidget()
coolWidget.show()
sys.exit(app.exec_())
So simple isn't it? :D
I managed to make it work, thanks to #bnaecker for telling me that the code actually creates two widgets, I've replaced some stuff in my code. Basically, just edit the code generated when you translate the .ui to .py so it would only create one widget.
The most changes happened here:
if __name__ == "__main__":
import sys
sys.excepthook = excepthook
app = QtWidgets.QApplication(sys.argv)
hGUI = QtWidgets.QWidget(flags=QtCore.Qt.FramelessWindowHint)
ui = Ui_hGUI()
ui.setupUi(hGUI)
hGUI.show()
sys.exit(app.exec_())
Edited to this:
if __name__ == "__main__":
sys.excepthook = excepthook
app = QtWidgets.QApplication(sys.argv)
hGUI = Ui_hGUI()
sys.exit(app.exec_())
Add self.show() at the end of retranslateUi(self), replace every "hGUI" in the code with "self" or delete it if it's an argument (except for controls like buttons and labels).
Here are both codes, non-working one vs. working one: https://gist.github.com/anonymous/0707b4fef11ae4b31cf56dc78dd3af80
Note: In the new code, the app is called "VirtualMemories".

How to remember last geometry of PyQt application?

I am using PyQt5 5.5.1 (64-bit) with Python 3.4.0 (64-bit) on Windows 8.1
64-bit.
I am having trouble restoring the position and size (geometry) of my
very simple PyQt app.
Here is minimal working application:
import sys
from PyQt5.QtWidgets import QApplication, QWidget
class myApp(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
view = myApp()
sys.exit(app.exec())
What I read online is that this is the default behavior and we need to
use QSettings to save and retrieve settings from Windows registry,
which is stored in
\\HKEY_CURRENT_USER\Software\{CompanyName}\{AppName}\
Here are some of the links I read.
I could have followed those tutorials but those tutorials/docs were
written for C++ users.
C++ is not my glass of beer, and converting those codes are impossible to me.
Related:
QSettings(): How to save to current working directory
This should do.
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtCore import QSettings, QPoint, QSize
class myApp(QWidget):
def __init__(self):
super(myApp, self).__init__()
self.settings = QSettings( 'My company', 'myApp')
# Initial window size/pos last saved. Use default values for first time
self.resize(self.settings.value("size", QSize(270, 225)))
self.move(self.settings.value("pos", QPoint(50, 50)))
def closeEvent(self, e):
# Write window size and position to config file
self.settings.setValue("size", self.size())
self.settings.setValue("pos", self.pos())
e.accept()
if __name__ == '__main__':
app = QApplication(sys.argv)
frame = myApp()
frame.show()
app.exec_()
I simplified this example: QSettings(): How to save to current working directory
Similar to #Valentin's response, because I feel settings are being written to registry, which will be issue for cross compatiblity. Here is the relevant startEvent() and closeEvent() for the job.
def startEvent()
self.settings = QSettings(QSettings.IniFormat,QSettings.SystemScope, '__MyBiz', '__settings')
self.settings.setFallbacksEnabled(False) # File only, not registry or or.
# setPath() to try to save to current working directory
self.settings.setPath(QSettings.IniFormat,QSettings.SystemScope, './__settings.ini')
# Initial window size/pos last saved
self.resize(self.settings.value("size", QSize(270, 225)))
self.move(self.settings.value("pos", QPoint(50, 50)))
self.tab = QWidget()
def closeEvent(self, e):
# Write window size and position to config file
self.settings.setValue("size", self.size())
self.settings.setValue("pos", self.pos())
startEvent() should be initiated at startup and closeEvent() should be taken care before quitting the main window.
You should indeed use QSetting for this.
All the Qt examples have been converted to Python. They are included in the source packages of PyQt (or PySide), which you can download here
You can also look online in the github repo, particularly in application.py of mainwindows example.
def readSettings(self):
settings = QSettings("Trolltech", "Application Example")
pos = settings.value("pos", QPoint(200, 200))
size = settings.value("size", QSize(400, 400))
self.resize(size)
self.move(pos)
def writeSettings(self):
settings = QSettings("Trolltech", "Application Example")
settings.setValue("pos", self.pos())
settings.setValue("size", self.size())
Fire writeSettings() before quitting and initiate readSettings() on startup.
In my case I use .ini files to store settings (language, default user, ...). the same code works on both Debian and Windows.
An example:
from PySide.QtCore import QSettings
self.settings = QSettings('settings.ini', QSettings.IniFormat)
...
self.settings.setValue('size', self.size())

My python script turn off touchpad and power button why?

I use KDE on Manjaro linux. I have this script in python to turn off touchpad:
#!/usr/bin/python
import sys
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication
from PyQt5.QtCore import QCoreApplication
from subprocess import call
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
qbtn = QPushButton('On', self)
qbtn.clicked.connect(self.handleButtonOn)
qbtn.resize(qbtn.sizeHint())
qbtn.move(25, 50)
qbtn = QPushButton('Off', self)
qbtn.clicked.connect(self.handleButtonOff)
qbtn.resize(qbtn.sizeHint())
qbtn.move(125, 50)
self.setGeometry(300, 300, 250, 100)
self.setWindowTitle('Touchpad On/Off')
self.show()
def handleButtonOn(self, event):
print ('On')
call(["synclient", "touchpadoff=0"])
call(["notify-send", "Your touchpad is set to ON"])
self.destroy()
def handleButtonOff(self, event):
print ('Off')
call(["synclient", "touchpadoff=1"])
call(["notify-send", "Your touchpad is set to OFF"])
self.destroy()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
It's works almost perfect (turn off my touchpad) but when I start script it's turn off my power button so I can't turn off computer by this button.
There is a problem with Yakuake too, can't write in this terminal. Finally i've start some other terminal for example "konsole" and turn off computer by shutdown command.
I'm new in python. How to make this work OK. I need turn off my touchpad, I use external mouse.
I can't reproduce your issue with power button, but I found out that self.destroy() is causing your script to freeze in some corrupted-not-responding-to-SIGINT state. Replacing self.destroy() with self.close() makes it work on my machine.
Please try replacing self.destroy() with self.close().

Categories