PyQt5 app exits on error where PyQt4 app would not - python

I have been developing a scientific application using PyQt4 for a couple of weeks, and decided to switch over to PyQt5. Aside from a few things to iron out one thing is puzzling me, and I'm not sure if its intended behavior or not.
When Using PyQt4:
if I had a python error (AttributeError, FileNotFoundError or whatever) the error message would print out to the python console, but I could continue using the PyQt4 gui application
When Using PyQt5, when I have a python error, the entire app closes on me. Is this a setting, or is this intended behavior? This is potentially disastrous as before if there was a bug, I could save the data I had acquired, but now the application will just close without warning.
Here is an example that demonstrates the behavior. This script opens a widget with a button that activates a file dialog. If a valid file is selected, the code will print the filepointer object to the command line. If no file is selected because the user hits cancel, then that case is not handled and python tries to open a file with path ''. In this both PyQt4 and PyQt5 versions throw the same python error:
FileNotFoundError: [Errno 2] No such file or directory: ''
However, the PyQt4 version will leave the widget open and the user can continue, whereas the PyQt5 version closes, with exit code of 1.
Here is the example code, executed by: "python script.py"
import sys
# from PyQt4 import QtGui as qt
# from PyQt4.QtCore import PYQT_VERSION_STR
from PyQt5 import QtWidgets as qt
from PyQt5.QtCore import PYQT_VERSION_STR
def open_a_file():
fname = qt.QFileDialog.getOpenFileName()
if PYQT_VERSION_STR[0] == '4':
f = open(fname, 'r')
print(f)
else:
f = open(fname[0], 'r')
print(f)
f.close()
if __name__ == '__main__':
app = qt.QApplication(sys.argv)
w = qt.QWidget()
w.resize(250, 150)
w.move(300, 300)
w.setWindowTitle('PyQt 4 v 5')
btn = qt.QPushButton("Open a file", w)
btn.clicked.connect(open_a_file)
w.show()
sys.exit(app.exec_())
Can I use PyQt5, but have it not crash the way that the PyQt4 version does?
Here is my current system information system information:
Windows 7 64-bit
Anaconda, Python 3.5
PyQt4 --> from conda sources
PyQt5 --> using:
conda install --channel https://conda.anaconda.org/m-labs qt5
conda install --channel https://conda.anaconda.org/m-labs pyqt5
both PyQt4 and PyQt5 are installed side by side

The old behavior can be forced by calling this code, which I found after more searching. I'm not sure I understand why this is bad behavior that needed to be deprecated, but this does work.
I submit that this should not be the default behavior, and that properly catching exceptions is the correct way to program, but given the specific purpose of my programming, and my time constraints, I find it useful to have access to as an optional mode, as I can still see the python exception traces printed to the console, and won't lose any unsaved data because of an uncaught exception.
import sys
def my_excepthook(type, value, tback):
# log the exception here
# then call the default handler
sys.__excepthook__(type, value, tback)
sys.excepthook = my_excepthook

Related

PyQt5 MainWindow with flag instantly goes out of scope

I created UI using Qt Designer. Then I converted the ui file to a .py file (pyuic -x) - it works fine if launched directly. Then I tried to subclass my ui in a separate file to implement additional logic. And this is where things start to go wrong. Inheriting from QMainWindow and my Qt Designer file works OK with no issues, as expected. However, the moment I set any WindowFlag for my QMainWindow (any flag - I tried these: StaysOnTop, FramelessWindowHint) and run the file, the window appears and instantly disappears. The program continues to run in a console window, or as a PyCharm process, but the window is gone. It looks to me like it is getting out of scope - but why setting a simple flag would make any difference to the garbage collector? Could someone explain this behaviour?
Minimum code required to reproduce this phenomenon:
from ui import Ui_MainWindow
from PyQt5 import QtCore, QtWidgets, QtGui
import sys
class Logic(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.setupUi(self)
self.show()
# self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
# self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = Logic()
sys.exit(app.exec_())
The window should appear and stay on the screen until one (or more) of the flags are uncommented. I use Python 3.8 (32-bit) with PyQt5. Run environment provided by PyCharm. Windows 10.
From the documentation of setWindowFlags():
Note: This function calls setParent() when changing the flags for a window, causing the widget to be hidden. You must call show() to make the widget visible again..
So, just move self.show() after setting the flags, or call it from outside the __init__ (after the instance is created), which is the most common and suggested way to do so, as it's considered good practice to show a widget only after it has been instanciated.

PyInstaller generated exe file error : qt.qpa.plugin: could not load the qt platform plugin "windows" in "" even though it was found

I have created a program to read certain data from files on a drive, display results on a PyQt5 ui and accept corrections if any from user.
The program worked fine when run as a python file. However, when i converted it into a standalone exe using PyInstaller, it works fine upto the point where the pyqt5 gui needs to be launched. At this point, it stops throwing the following error :
qt.qpa.plugin: Could not load the Qt platform plugin "windows" in "" even though it was found. This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem. Available platform plugins are: minimal, offscreen, windows.
I have read this, this and this but they dont resolve my issue.
The code of the gui is very big but here is the structure :
from PyQt5 import uic, QtWidgets
import sys
import os
#baseUIClass, baseUIWidget = uic.loadUiType('gui.ui')
baseUIClass, baseUIWidget = uic.loadUiType(r'C:\mypath\gui.ui')
class Ui(baseUIClass, baseUIWidget ):
def __init__(self, *args, **kwargs):
baseUIWidget.__init__(self, *args, **kwargs)
self.setupUi(self)
# More code to perform the desired actions
def run(input_variables):
app = QtWidgets.QApplication(sys.argv)
ui = Ui()
ui.show()
# More code to make the Ui perform desired actions
app.exec_()
return(output_variables)
The code was converted to a standalone exe with the following arguments :
pyinstaller --hiddenimport <hidden import> --onefile <python filename>
Would you know how to troubleshoot this please?
Thanks
I ran into the same error message with my compiled application.
To track down the issue, I first stripped down the app to its skeleton with minimal imports, which worked flawlessly when compiled. I then partially added back all imports of my "big" application until the error reappeared.
In the end (for me at least) pandas is the culprit:
Minimal reproducibale examples, this works:
from PyQt5 import QtWidgets
app = QtWidgets.QApplication([])
window = QtWidgets.QMainWindow()
window.show()
app.exec()
This (added pandas import in line 2) throws the error you describe:
from PyQt5 import QtWidgets
import pandas as pd # import after pyqt5
app = QtWidgets.QApplication([])
window = QtWidgets.QMainWindow()
window.show()
app.exec()
However, when first importing pandas and then importing PyQt 5, my compiled version works again:
import pandas as pd # import before pyqt5
from PyQt5 import QtWidgets
app = QtWidgets.QApplication([])
window = QtWidgets.QMainWindow()
window.show()
app.exec()
So, in my case the solution was to track down the "erroneous import", fiddle with the import order and get lucky (I am far too unexperienced to even try to understand why the import order leads to this error)
If you are not using pandas, maybe the whole "strip down to skeleton and start importing piece by piece"-approach will help you to further clarify the root cause of the error.
If you are using pandas and the order switch-up did not help, there is another thread which describes which tries to deal with pandas compiling issues.

does not show icons

I just installed Python3 (3.5.2) and Pyqt5 (5.8.2) and I am following this tutorial to learn and make a GUI: http://zetcode.com/gui/pyqt5/firstprograms/
I'm trying to run the 2nd example but program is returning an error (which also happened on the 1st one, but since it had no image i took no notice) which is the following:
QApplication: invalid style override passed, ignoring it.
No XVisualInfo for format QSurfaceFormat(version 2.0, options QFlags<QSurfaceFormat::FormatOption>(), depthBufferSize -1, redBufferSize 1, greenBufferSize 1, blueBufferSize 1, alphaBufferSize -1, stencilBufferSize -1, samples -1, swapBehavior QSurfaceFormat::SwapBehavior(SingleBuffer), swapInterval 1, profile QSurfaceFormat::OpenGLContextProfile(NoProfile))
Falling back to using screens root_visual.
What is the meaning of this? Am i missing some packages?
I installed pyqt first with this command:
sudo -H pip3 install PyQt5
but Python3 was not acknowledging its existence so i searched the apt ubuntu repos and installed with:
sudo apt install python3-PyQt5
I also tried to reference the image by full path /foo/bar/image.png and nothing
What is the problem?
EDIT #1
The code that i am using is from example 2:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
ZetCode PyQt5 tutorial
This example shows an icon
in the titlebar of the window.
author: Jan Bodnar
website: zetcode.com
last edited: January 2015
"""
import sys
import os
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QIcon
base_dir = os.path.dirname(os.path.abspath(__file__))
os.chdir(base_dir)
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 300, 220)
self.setWindowTitle('Icon')
self.setWindowIcon(QIcon('image.png'))
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
After your post i reinstalled all my packages. The error is slightly different but the result is the same:
python3 example_02.py
QApplication: invalid style override passed, ignoring it.
Screencapture:
Notice that you are having no icons at all for all applications, not just for the PyQt icon example. This is because by default, certain environments turn off the icons in the titlebar. You have to enable them.
For instance in Xfce Desktop Environment, we can use the xfce4-settings-editor tool. In Settings/Settings Editor select xfwm4.
Find the show_app_icon option and check it. Change a theme back and forth to see the changes; they are not visible right away.
After this, you will see the icon in the titlebar of the PyQt5 example.
As for the warning; it is a recent thing and it has to do something
with the incopatibilities between Qt and GTK theming. I have not found
a solution to remove the warning so far.
So first off, you have no errors in your code. That's more akin to a warning but not even. What the following line is telling you
QApplication: invalid style override passed, ignoring it
is that your style option is invalid. If that were an error your script wouldn't run at all.
What I see right off the bat is this, you never supply a path to your image.
Now if the image is in the same root directory as the script then it should recognize said image without a path. But if you're attempting to do what I think you are it wouldn't work like that anyway. I think you're trying to create a launcher icon as well as a title bar icon, which typically goes hand in hand.
It appears to me that you've added it to Atom as some form of resource file. In which case most Ide's create a path for that file. Sometimes it's a path, other times a local url. QT its self does both when working with the QT creator.
I've never used Atom so I can't tell you how that works.
What I can say is this. you're using Linux which means .ico files are useless. I told you before linux doesn't handle icon files the same way windows does. This is most likely your problem.
So I sugesst you take a look at this
https://askubuntu.com/questions/476981/how-do-i-make-a-desktop-icon-to-launch-a-program
After you read that take a look at this if you have to https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Using_a_text_editor
Both of those links explain how to create a launcher icon for your program.
The following link will explain how to set the icon on the menu bar (title bar) in your program.
PyQt4 set windows taskbar icon
I hope this helps you out!
I study PyQt5 from author who give this question,also I have this problem that my icons can't show,I try some ways to catch it,that's what I do,hope it works!
First, it's important that you should use absolute path of the icons,for example:
self.setWindowIcon(QIcon("F:/Workspace/PyQT5-Study/images/web.png"))
but this not a good idea,so you can use second way like this:
from PyQt5.QtCore import QFileInfo
# ...
def initUI(self):
# ...
root = QFileInfo(__file__).absolutePath()
self.setWindowIcon(QIcon(root+'/images/web.png'))
# or
# import os
# current_dir = os.path.dirname(os.path.realpath(__file__))
# self.setWindowIcon(QIcon(os.path.join(current_dir, 'images/web.png')))
# ...
Last, if your icons also can't show, you should check this icon, if it's a legal icon.
In short, the normal images are unlimited so more, they can store many images and transform easily, but the icons have sure size,color kind,and more important,the icons have transparency, that means you can see the background, they have frame(not always straight). So you can use the web online tools to transform your image and try again,that really help me!
Also you should check the icon's source format, ensure you never change it, like .jpg to .png,and other. This will produce problem!
Wish you can solve the problem!
On windows be sure to use a real .ico file and a full path
iconpath = os.path.join(os.getcwd(),'qtlearning','assets','python.ico')
self.setWindowIcon(QIcon(iconpath))
I faced the exact same problem.
First things first. There is no setWindowIcon() method under QWidget or QMainWindow classes, in fact. you should be trying to set the QIcon at the Application level as follows.
app = QApplication(sys.argv)
app.setWindowIcon(QtGui.QIcon('home.png'))
Second, the icon thus created using this code does not reflect on the title of the window, instead it will reflect as an application icon as shown in the image below. the home.png
" icon for Application" in Ubuntu and not the " icon over the Window Title"
Finally, the path does not really matter, it can be an absolute path or a relative path, the system will consider either.
i just provided the full path of icon as simple as that

Need file dialog for code running in Enthought Canopy

The common regular python file dialog from Tk crashes under Enthought Canopy.
What is the recommended way to get a file dialog for Canopy users?
The code below works fine for regular python:
import Tkinter, tkFileDialog
root = Tkinter.Tk()
root.withdraw()
file_path = tkFileDialog.askopenfilename()
Error msg when run under Canopy is:
2014-12-30 11:22:52.809 Python[51980:d0f] -[QNSApplication _setup:]: unrecognized selector sent to instance 0x108657b70
Depends on what GUI backend you are using in your program. If your program also uses TK elsewhere, then follow the instructions in the link that Warren provided. If all you need is this dialog (and similar), Chuck's suggestion is probably easiest (especially since Qt is the default backend for IPython kernel that Canopy uses). I'm no Qt guru but I think you can simplify Chuck's suggestion to:
from PySide import QtGui
fname, _ = QtGui.QFileDialog.getOpenFileName(None, 'Choose file','.')
See http://srinikom.github.io/pyside-docs/PySide/QtGui/QFileDialog.html
For me, the easy alternative is to use Qt.
fname, _ = QtGui.QFileDialog.getOpenFileName(self.view, 'Open file','.')

PySide program closes instantly

I'm trying to learn PySide for a project I'm working on. I'm working through the Zetcode tutorials, but from the very beginning I'm running problems. I am writing and running my code through Enthought's Canopy. When I run the code from the command line it works fine. This question may be related to my issue, however no answer is given there.
When I use the simplest code from the tutorial
import sys
from PySide import QtGui
wid = QtGui.QWidget()
wid.resize(250, 150)
wid.setWindowTitle('Simple')
wid.show()
everything runs correctly. The next example does more or less the same, except from an OOP perspective.
import sys
from PySide import QtGui
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Icon')
self.setWindowIcon(QtGui.QIcon('web.png'))
self.show()
def main():
ex = Example()
if __name__ == '__main__':
main()
When run the program flashes (I can see the window appear for a brief second) and then closes. Raising an exception before the end of main() will keep the window on the screen.
TL;DR
Why does putting the program in a class make it not work?
The difference between the two examples, is that first one keeps a reference to the widget as a global variable, whilst the second creates a local variable that gets garbage-collected when it goes out of scope (i.e. when the function returns).
The simplest way to fix this, is to make the ex variable global, like this:
def main():
global ex
ex = Example()
or you could just get rid of the main function, and simply do:
if __name__ == '__main__':
ex = Example()
The difference between running in and out of Canopy is that Canopy uses IPython QTConsole running, by default, in pylab mode with a QT GUI backend. The nice thing about this (and one of the many geniuses of ipython) is that you can have a live interaction between the command prompt and your GUI).
I suspect that you are bumping into pylab. A sophisticated program like Matplotlib can figure out whether the GUI event loop was already started, and adapt accordingly. But for your purpose, you probably just want to disable pylab mode, so that the IPython in Canopy acts more like a generic python. To do this, disable Pylab mode from the Canopy Preference menu (Python tab).

Categories

Resources