对 PyQt5 应用程序中的崩溃进行故障排除 (QDialog -> QMainWindow)



我目前正在尝试解决我在Python中开发的Qt应用程序时遇到的问题。我只有一个简单的主窗口和一个模式QDialog设置,用于在主窗口上触发菜单操作后收集用户输入。QDialog 的行为符合预期,因为我已经能够确认测试打印在 QDialog 返回"已接受"时执行,但应用程序将在 print 语句之后完全崩溃,没有错误消息。当 QDialog 返回"已拒绝"时,也会发生相同的行为。澄清一下,主窗口显示几秒钟,应用程序崩溃,没有错误消息。我希望该函数在收到下面的 Process 函数的任一结果后将焦点返回到主窗口(它仍然打开以进行操作(。

我还尝试使 QDialog 无模式(使用 show(,并且来自 QDialog 的接受/拒绝函数似乎按预期返回到主窗口,但再次调用启动 QDialog 的函数会使应用程序崩溃。我在这个项目中使用 pyqt 5.9,但我在 pyqt 5.6 中的许多其他项目中使用了与以下代码基本相同的设置,而没有发生这种情况。我正在尝试弄清楚 pyqt 5.9 是否存在任何可能导致此问题的已知问题,或者我的代码中是否存在导致此崩溃发生的错误。我正在考虑回滚到 5.6 以查看是否可以解决此问题,但我觉得可能有一些我误解的东西导致这种情况发生。

我在Windows 10上运行Anaconda提示符(Anaconda 4.8.3,Python 3.7(的代码,因为Qt应用程序在Spyder中反复运行仍然存在问题。我正在使用 Anaconda 附带的 pyqt,并且没有对 pyqt 进行任何额外的 pip 安装。

主窗口代码

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QGridLayout, QHBoxLayout, QVBoxLayout, QAction, QLabel
from PyQt5.QtWidgets import QDialog, QListWidget, QListWidgetItem, QAbstractItemView, QPushButton, QLineEdit, QSpacerItem, QSizePolicy

class FirstWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)

self.title = 'Window 1'
self.left = 350
self.top = 150
self.width = 800
self.height = 500

self.setWindowTitle(self.title)
self.setGeometry(self.left,self.top,self.width,self.height)

widget = QWidget()
self.setCentralWidget(widget)
grid = QGridLayout()
widget.setLayout(grid)

mainMenu = self.menuBar()
mainMenu.setNativeMenuBar(False)
subMenu = mainMenu.addMenu('File')

modifyDB = QAction('Test',self)
subMenu.addAction(modifyDB)
modifyDB.triggered.connect(self.Process)

self.statusBar().showMessage('Ready')
def Process(self):
dialog = DialogWin()
if dialog.exec_() == QDialog.Accepted:
print('test passed')
if __name__ == '__main__':
if not QApplication.instance():
app = QApplication(sys.argv)
else:
app = QApplication.instance()
mainWin = FirstWindow()
mainWin.show()
app.exec_()

对话框代码

class DialogWin(QDialog):
def __init__(self,parent=None):
super(DialogWin,self).__init__(parent)
self.title = 'Database Table Name Selection'
self.left = 350
self.top = 150
self.width = 300
self.height = 300

self.setWindowTitle(self.title)
self.setGeometry(self.left,self.top,self.width,self.height)
vbox = QVBoxLayout()
spacer = QSpacerItem(10,10,QSizePolicy.Expanding,QSizePolicy.Expanding)
self.list_exp = QLabel('Select Existing Table to Overwrite')
vbox.addWidget(self.list_exp)
self.table_list = QListWidget()
self.table_list.setSelectionMode(QAbstractItemView.SingleSelection)
vbox.addWidget(self.table_list)

hbox = QHBoxLayout()
hbox.addItem(spacer)
self.option_exp = QLabel('<span style="font-size:8pt; font-weight:600; color:#aa0000;">OR</span>')
hbox.addWidget(self.option_exp)
hbox.addItem(spacer)
vbox.addLayout(hbox)

self.new_name = QLineEdit(placeholderText='Enter New Source Name')       
vbox.addWidget(self.new_name)
hbox = QHBoxLayout()
self.okButton = QPushButton('OK')
hbox.addWidget(self.okButton)
self.okButton.clicked.connect(self.accept)

self.cancelButton = QPushButton('Cancel')
hbox.addWidget(self.cancelButton)
self.cancelButton.clicked.connect(self.reject)

vbox.addLayout(hbox)
self.setLayout(vbox)
item = QListWidgetItem('No Tables Available...')
item.setFlags(item.flags() ^ Qt.ItemIsSelectable)
self.table_list.addItem(item)

关于这个问题的任何投入都将非常有帮助。我花了很多时间试图了解此设置如何在一个应用程序中为我工作,而不是在另一个应用程序中工作。

解释:

问题是你使用相同的QSpacerItem 2次,当QDialog被关闭时,因为它是一个局部变量,它将被删除,Qt也会消除内部对象,在这种情况下,QSpacerItem 将有一个双重消除,导致"分段错误"。

溶液:

您必须创建 2 个 QSpacerItem:

# ...
hbox = QHBoxLayout()
hbox.addItem(spacer)
self.option_exp = QLabel('OR')
hbox.addWidget(self.option_exp)
hbox.addItem(QSpacerItem(10,10,QSizePolicy.Expanding,QSizePolicy.Expanding))
vbox.addLayout(hbox)
# ...

另一种选择不是使用 QSpacerItem,而是设置拉伸因子:

# ...
hbox = QHBoxLayout()
hbox.addStretch()
self.option_exp = QLabel('OR')
hbox.addWidget(self.option_exp)
hbox.addStretch()
vbox.addLayout(hbox)
# ...

或者不要使用 QHBoxLayout 并通过设置对齐方式将 QLabel 直接设置为 QVBoxLayout:

# ...
self.table_list = QListWidget()
self.table_list.setSelectionMode(QAbstractItemView.SingleSelection)
vbox.addWidget(self.table_list)
self.option_exp = QLabel('OR')
vbox.addWidget(self.option_exp, alignment=Qt.AlignHCenter)

self.new_name = QLineEdit(placeholderText='Enter New Source Name')       
vbox.addWidget(self.new_name)
# ...

最新更新