Segmentation fault when exiting PyQT app - python

First, I have tried my best to find a solution to this problem here and other places and I am have a general idea of what the problem is, but it is not clear to me how to solve it.
The basic problem is that I am getting a segmentation fault when I close my app by pressing the standard "x" button.
The most important details (I think) are that I am using MacOS Sierra, python 3.5.2, and pyqt5.
The app I am building is very loosely based on another project (Dioptas), which is a relatively mature project. I am more or less getting started.
When I close the window, the terminal prints out as instructed in MainController.close_event():
> here
> closed
> accepted
> Segmentation fault: 11
I have tried many of the suggestions online and I am fairly sure that this is due to python not closing all of the windows (perhaps due to the order in which they are being closed - QApplication.CloseAllWindows() says they are closed in a random order, for one thing). If anyone has a suggestion or solution I would really appreciate it.
The following is my code:
import sys
import pyqtgraph as pg
import numpy as np
from PIL import Image
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class MainController(QWidget):
def __init__(self):
super().__init__
self.start()
self.create_signals()
def start(self):
self.widget = MainWidget()
self.widget.show()
def create_signals(self):
self.widget.closeEvent = self.close_event
def close_event(self, ev):
print("here")
QApplication.closeAllWindows()
print("closed")
ev.accept()
class MainWidget(QWidget):
def __init__(self, *args, **kwargs):
super(MainWidget, self).__init__(*args, **kwargs)
self.layout = QHBoxLayout()
self.layout.setContentsMargins(2, 2, 2, 2)
self.layout.setSpacing(6)
self.stepFilterDisplayWidget = StepFilterDisplayWidget()
self.stepFilterControlWidget = StepFilterControlWidget()
self.layout.addWidget(self.stepFilterDisplayWidget)
self.layout.addWidget(self.stepFilterControlWidget)
self.setLayout(self.layout)
self.setGeometry(100,100,1000,700)
class StepFilterDisplayWidget(QWidget):
def __init__(self, *args, **kwargs):
super(StepFilterDisplayWidget,self).__init__(*args,**kwargs)
self.layout = QVBoxLayout()
self.setLayout(self.layout)
self.plot = pg.ImageView()
self.layout.addWidget(self.plot)
self.button = QPushButton("Plot", self)
self.button.clicked.connect(self.showImage)
self.layout.addWidget(self.button)
def showImage(self):
im = Image.open('S_15a_crop.tif')
self.data = np.array(im)
self.plot.setImage(self.data)
class StepFilterControlWidget(QWidget):
def __init__(self, *args, **kwargs):
super(StepFilterControlWidget, self).__init__(*args, **kwargs)
if __name__ == "__main__":
app = QApplication(sys.argv)
controller = MainController()
app.exec_()
del app

The problem is about pyqtgraph (which uses PyQt4) and PyQt5 imports. pyqtgraph trying to use something belongs to PyQt4 which was overriden by PyQt5 import. This triggers the segmentation fault.

I was having the same problem - with pyqt5 and python3.10
My app has 3 pyqtgraph widgets:
1 pg.ImageView() created directly in the main application which is a QtWidgets.QMainWindow()
2 pg.PlotWidget() + pg.opengl.GLViewWidget() loaded into the mainwidow application from another class QueryBuilder() which is QWidget
To quit the app I was using a call to qApp.quit() action. When only the pg.ImageView() was loaded - I had no core dump issue. The segfault issue came just after adding the QueryBuilder() code.
Adding, into the quit method, a call to close the QueryBuilder() widget fixed the issue
from querybuilder import QueryBuilder # widgets with pyqtgraph
class MapDisplay():
...
self.querybuilder = QueryBuilder()
...
def quit(self):
self.querybuilder.close()
qApp.quit()

Related

PyQt5 Getting second screen functions to work

how are you doing?
I have been coding for a couple months. I started with Python, now I am trying to learn PyQt5.
I have created two windows using the Designer Tool. I created a subclass for each specific page, so that it wont mess up my software once i make changes in the Designer.
I managed to make my second window open from the first window. It works well. However, nothing works in window 2 when its opened by window 1. However, when i run window 2 by itself, it does not work.
I am sure it is a inheritance problem that I am messing up. It seems my sofware is inheriting the window 2 layout but not its functions.
I have attached the code. Is it possible for someone to help me out? If possible, i would like a brief explanation on how to fix it too. I want to learn so I can teach others as well.
This is my main window:
from nonregusrscreen1 import NonReg
from Main import Ui_MainWindow # needs to import from the main file
from PyQt5 import QtCore, QtGui, QtWidgets #importing PyQt functionality
class mainWin(QtWidgets.QMainWindow, Ui_MainWindow): #mainWin is new subclass. QtWidgets.Whatever the window was / you need to get inheritance from Ui_MainWindow, otherwise you wil lahve to use self.ui.pushbutton....
def __init__(self, *args, **kwargs): #passing arguments from whatever was called
super().__init__(*args, **kwargs)
self.ui = Ui_MainWindow()
self.setupUi(self)
self.pushButton_2.clicked.connect(self.openwindow) # you have to include UI, otherwise it will not work.
def openwindow(self):
self.window = QtWidgets.QDialog()
self.ui = NonReg()
self.ui.setupUi(self.window)
self.window.show()
if __name__ == '__main__':
app = QtWidgets.QApplication([])
w = mainWin()
w.show()
app.exec_()
This is my second window, here you can see the pushbutton_2 function that only works when the file is opened by itself (not opened using the first window)
from nonregusrscreen import Ui_NonRegUserScreen
from PyQt5 import QtCore, QtGui, QtWidgets
class NonReg(QtWidgets.QDialog, Ui_NonRegUserScreen):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.ui = Ui_NonRegUserScreen
self.setupUi(self)
self.pushButton_2.clicked.connect(self.closewindow)
def closewindow(self):
self.window = exit()
if __name__ == '__main__':
app = QtWidgets.QApplication([])
w = NonReg()
w.show()
app.exec_()
Thank you, i truly appreciate your help.

Pyqt5 Crashes without error when i specifically double left click (double right works)

I'm creating this application in Python that talks with Outlook and retrieve some data about the amount of mails in each folder and some other stuff and I'm using PyQt5 to do so.
But some werid thing happened when I assigned a signal to a function:
self.table_widget.itemDoubleClicked.connect(self.some_function)
If I double right-click this item, everything runs just fine. But if I do it with the left-click, it just freezes, and then crashes without any error screen whatsoever (usually if you execute the program, when it crashes you can see some stack on the console behind, right? In this case literally nothing shows up).
I'm not sure if I'm using he signals thing right, so there might be something...?
Anyways, since no error occurred, I tried to put some prints to see where it would crash, but it turns out that the t2 screen loads just fine, and apparently it crashes when the code goes back to the main loop...? I don't know, it's impossible for me to debug that stuff.
I'll try to put here only the essential code so it gets easier to see the mistake, but I can show some details if this is not enough.
EDIT
As requested, I did a minimum reproducible example below, it does crash in the same way:
from PyQt5.QtCore import QDateTime, Qt, QTimer, pyqtSignal
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog, QTableWidgetItem
from PyQt5 import uic
import sys, os
class t0(QMainWindow):
switch_window = pyqtSignal()
def __init__(self):
super(t0, self).__init__()
uic.loadUi(Controller.application_path + r'\UI\t0.ui', self)
#This .ui file has pretty much a button to click
self.btn_ok.clicked.connect(self.onButtonClick1)
def onButtonClick1(self):
self.switch_window.emit()
class t1(QDialog):
switch_window = pyqtSignal()
def __init__(self, parent=None):
super(t1, self).__init__(parent)
uic.loadUi(Controller.application_path + r'\UI\t1.ui', self)
#This .ui file has a QTableWidget
self.tw_indi.setColumnCount(1)
self.tw_indi.setRowCount(1)
self.tw_indi.setItem(0, 0, QTableWidgetItem("*"))
self.tw_indi.itemDoubleClicked.connect(self.direcionar_detalhes)
def direcionar_detalhes(self, item):
self.switch_window.emit()
class t2(QDialog):
switch_window = pyqtSignal(str)
def __init__(self, parent=None):
super(t2, self).__init__(parent)
uic.loadUi(Controller.application_path + r'\UI\t2.ui', self)
#This .ui file is identical as the t1.ui, just some minor changes
class Controller():
controller = None
#questões técnicas do módulo os com pyinstaller
if getattr(sys, 'frozen', False):
application_path = sys.exec_prefix
else:
application_path = os.path.dirname(os.path.abspath(__file__))
tela = None
app = QApplication(sys.argv)
def __init__(self):
Controller.controller = self
self.mostra_carregamento()
sys.exit(Controller.app.exec_())
def mostra_carregamento(self):
self.view = t0()
self.view.switch_window.connect(self.mostra_indicador)
self.view.show()
def mostra_indicador(self):
self.view.close()
self.view = t1()
self.view.switch_window.connect(self.sinal_indicador)
self.view.show()
def sinal_indicador(self):
self.view.close()
self.view = t2()
self.view.show()
if __name__ == '__main__':
control = Controller()
EDIT 2
Here's the link for the ui's:
https://drive.google.com/file/d/1-iFNaWUGtJ4687nTcTFtb7WRKUL37als/view?usp=drivesdk
The problem is not the signal, but when you want to reuse the same variable for a new window, you are eliminating the memory of that object that is still visible and therefore running, generating unreserved memory access. The solution is to use different variable names:
class Controller:
# ...
def mostra_carregamento(self):
self.view0 = t0()
self.view0.switch_window.connect(self.mostra_indicador)
self.view0.show()
def mostra_indicador(self):
self.view0.close()
self.view1 = t1()
self.view1.switch_window.connect(self.sinal_indicador)
self.view1.show()
def sinal_indicador(self):
self.view1.close()
self.view2 = t2()
self.view2.show()

Best way to handle multiple windows Qt4 python

I have got two main-windows which will run all the time and open other windows. Every window has to communicate with each other. All windows are created with qt designer and as I read in another question I should not modify these files, so I tried to make a new class (communicator) to handle all the jobs.
What is the best way to structure a project like this. So how can i communicate best between these windows now, e.g. if I press a button in 'self.mainWindows_images' I want to do something in 'self.mainWindows_classifier'
from classifier import Form as Form_classifier
from cnn_avg import Form as Form_cnn_avg
from images import Form as Form_images
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
class Communicator():
def __init__(self, parent=None):
self.mainWindow_images = Form_images()
self.mainWindow_images.show()
self.mainWindow_classifier = Form_classifier()
self.mainWindow_classifier.show()
def main():
app = QApplication(sys.argv)
app.setStyle('cleanlooks')
comm = Communicator()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
One of the window files, generated by Qt Designer, looks like with the additional -w flag:
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName(_fromUtf8("Form"))
Form.resize(1145, 654)
...
class Form(QtGui.QWidget, Ui_Form):
def __init__(self, parent=None, f=QtCore.Qt.WindowFlags()):
QtGui.QWidget.__init__(self, parent, f)
self.setupUi(self)
I want to do something like this and add the setImage-method to the mainWindow_classifier, becaus as I mentioned I should not modify the generated qt python file:
self.mainWindow_classifier.pushButton.clicked.connect(self.setImage)
def setImage(self):
# change QLabel in self.mainWindow_images

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())

How to connect a signal from the controller in PyQt4? (iOS like MVC structure in PyQt4)

Why doesn't the following example work?
from PyQt4 import QtGui
import sys
class TestView(QtGui.QWidget):
def __init__(self):
super(TestView, self).__init__()
self.initUI()
def initUI(self):
self.btn = QtGui.QPushButton('Button', self)
self.btn.resize(self.btn.sizeHint())
self.btn.move(50, 50)
class TestViewController():
def __init__(self, view):
view.btn.clicked.connect(self.buttonClicked)
view.show()
def buttonClicked(self):
print 'clicked'
def main():
app = QtGui.QApplication(sys.argv)
view = TestView()
TestViewController(view)
app.exec_()
if __name__ == '__main__':
main()
The example is supposed to represent an MVC structure (like the one in Figure 4 -- without the Model) where the controller (TestViewController) receives a reference to the view (TestView) and connects the clicked signal from the view's button view.btn to its function self.buttonClicked.
I'm sure the line view.btn.clicked.connect(self.buttonClicked) is executed but, apparently, it has no effect. Does anyone knows how to solve that?
Update (awful solution):
In the example, if I replace the line
view.btn.clicked.connect(self.buttonClicked)
with
view.clicked = self.clicked
view.btn.clicked.connect(view.clicked)
it works. I'm still not happy with that.
The reason it is not working is because the controller class is being garbage collected before you can ever click anything for it.
When you set view.clicked = self.clicked, what you're actually doing is making one of the objects from the controller persist on the view object so it never gets cleaned up - which isn't really the solution.
If you store your controller to a variable, it will protect it from collection.
So if you change your code above to read:
ctrl = TestViewController(view)
You'll be all set.
That being said - what exactly you are trying to do here, I am not sure...it seems you're trying to setup an MVC system for Qt - but Qt already has a pretty good system for that using the Qt Designer to separate the interface components into UI (view/template) files from controller logic (QWidget subclasses). Again, I don't know what you are trying to do and this may be a dumb down version of it, but I'd recommend making it all one class like so:
from PyQt4 import QtGui
import sys
class TestView(QtGui.QWidget):
def __init__(self):
super(TestView, self).__init__()
self.initUI()
def initUI(self):
self.btn = QtGui.QPushButton('Button', self)
self.btn.resize(self.btn.sizeHint())
self.btn.move(50, 50)
self.btn.clicked.connect(self.buttonClicked)
def buttonClicked(self):
print 'clicked'
def main():
app = QtGui.QApplication(sys.argv)
view = TestView()
view.show()
app.exec_()
if __name__ == '__main__':
main()
Edit: Clarifying the MVC of Qt
So this above example doesn't actually load the ui dynamically and create a controller/view separation. Its a bit hard to show on here. Best to work through some Qt/Designer based examples/tutorials - I have one here http://bitesofcode.blogspot.com/2011/10/introduction-to-designer.html but many can be found online.
The short answer is, your loadUi method can be replace with a PyQt4.uic dynamic load (and there are a number of different ways to set that up) such that your code ultimately reads something like this:
from PyQt4 import QtGui
import PyQt4.uic
import sys
class TestController(QtGui.QWidget):
def __init__(self):
super(TestController, self).__init__()
# load view
uifile = '/path/to/some/widget.ui'
PyQt4.uic.loadUi(uifile, self)
# create connections (assuming there is a widget called 'btn' that is loaded)
self.btn.clicked.connect(self.buttonClicked)
def buttonClicked(self):
print 'clicked'
def main():
app = QtGui.QApplication(sys.argv)
view = TestController()
view.show()
app.exec_()
if __name__ == '__main__':
main()
Edit 2: Storing UI references
If it is easier to visualize this concept, you Can also store a reference to the generated UI object:
from PyQt4 import QtGui
import PyQt4.uic
import sys
class TestController(QtGui.QWidget):
def __init__(self):
super(TestController, self).__init__()
# load a view from an external template
uifile = '/path/to/some/widget.ui'
self.ui = PyQt4.uic.loadUi(uifile, self)
# create connections (assuming there is a widget called 'btn' that is loaded)
self.ui.btn.clicked.connect(self.buttonClicked)
def buttonClicked(self):
print 'clicked'
def main():
app = QtGui.QApplication(sys.argv)
view = TestController()
view.show()
app.exec_()
if __name__ == '__main__':
main()

Categories