如何在不退出 python 脚本的情况下销毁一个 QApplication 然后运行一个新的?
Posted
技术标签:
【中文标题】如何在不退出 python 脚本的情况下销毁一个 QApplication 然后运行一个新的?【英文标题】:How to destroy a QApplication and then run a new one without exiting the python script? 【发布时间】:2020-01-03 16:04:30 【问题描述】:我想创建一个 QApplication,然后使用键盘快捷键退出。然后python脚本应该调用另一个QApplication。
我目前的问题是当第二个 QApplication 即将运行时出现此错误:
app2 = QApplication()
RuntimeError: Please destroy the QApplication singleton before creating a new QApplication instance.
我有以下结构:
| main.py
| Q1.py
| Q2.py
这是 main.py:
import Q1 as record
import Q2 as display
def main():
record.main()
display.main()
if __name__ == "__main__":
main()
这是造成问题的第一季度:
import sys
from PySide2 import QtWidgets as qtw
from PySide2 import QtGui as qtg
from PySide2 import QtCore as qtc
from PySide2 import QtMultimedia as qtmm
class MainWindow(qtw.QMainWindow):
def __init__(self):
super().__init__()
#Create Window layout with a sound widget
soundboard = qtw.QWidget()
soundboard.setLayout(qtw.QGridLayout())
self.setCentralWidget(soundboard)
sw = SoundWidget()
soundboard.layout().addWidget(sw)
#Window Dimensions
self.setSizePolicy(qtw.QSizePolicy.Expanding, qtw.QSizePolicy.MinimumExpanding)
# Code ends here
self.show()
class SendOrderButton(qtw.QPushButton):
button_stylesheet = 'background-color: blue; color: white;'
def __init__(self):
super().__init__('Send Order')
self.setSizePolicy(qtw.QSizePolicy.Expanding, qtw.QSizePolicy.Expanding)
self.setStyleSheet(self.button_stylesheet)
#self.clicked.connect(qtc.QCoreApplication.instance().quit)
def press_button(self):
if self.isEnabled():
self.setEnabled(False)
self.setText('Send Order')
else:
self.setEnabled(True)
self.setText('Sent')
class SoundWidget(qtw.QWidget):
def __init__(self):
super().__init__()
self.setLayout(qtw.QGridLayout())
#Send Order Button
self.sendorder_button = SendOrderButton()
self.sendorder_button.setShortcut(qtg.QKeySequence('Tab'))
self.layout().addWidget(self.sendorder_button, 5, 0, 1, 2)
self.sendorder_button.clicked.connect(qtc.QCoreApplication.instance().quit)
def main():
app = qtw.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
这是具有第二个 QApplication 的 Q2.py:
import sys
from PySide2.QtCore import (QAbstractTableModel, Slot)
from PySide2.QtWidgets import (QAction, QApplication, QMainWindow,QWidget)
class MainWindow(QMainWindow):
def __init__(self, widget):
QMainWindow.__init__(self)
# Exit QAction
exit_action = QAction("Exit", self)
exit_action.setShortcut("Ctrl+Q")
exit_action.triggered.connect(self.exit_app)
@Slot()
def exit_app(self, checked):
sys.exit()
class CustomTableModel(QAbstractTableModel):
def __init__(self, data=None):
QAbstractTableModel.__init__(self)
class Widget(QWidget):
def __init__(self):
QWidget.__init__(self)
# Getting the Model
self.model = CustomTableModel()
def main():
app2 = QApplication()
widget = Widget()
window2 = MainWindow(widget)
window2.show()
sys.exit(app2.exec_())
if __name__ == "__main__":
app = QApplication()
widget = Widget()
window = MainWindow(widget)
window.show()
sys.exit(app.exec_())
【问题讨论】:
第二个 QApplication 还用在什么地方?将self.sendorder_button.clicked.connect(qtc.QCoreApplication.instance().quit)
更改为self.sendorder_button.clicked.connect(self.close)
提供真实的minimal reproducible example
只关闭小部件,窗口保持打开状态,脚本不继续。另一个应用程序是从 master.py 调用的,它位于不同的模块中。
如果您需要帮助提供 MRE,您的代码不是。为什么一定要有2个QApplication?
主文件是什么?是第一个代码还是第二个代码还是另一个?,因为您的问题不清楚,请更好地解释自己。
【参考方案1】:
如 cmets 中所述,Qt 应用程序只能并且应该有一个 QApplication(您可能不遵循此规则,但不能保证它可以正常工作),因此您将不得不重组您的代码。
假设您希望 Q1 窗口位于第一个窗口,当该窗口关闭时,Q2 窗口将打开,这并不意味着您在任何时候都必须使用多个 QApplication。这个想法是要知道窗口何时关闭并收到通知,要知道窗口何时关闭,然后您必须重写窗口的 closeEvent 方法并发出通知,您必须发送一个信号。
综合以上情况,解决办法是:
├── main.py
├── Q1.py
└── Q2.py
main.py
import sys
from PySide2 import QtWidgets as qtw
import Q1 as record
import Q2 as display
def main():
app = qtw.QApplication(sys.argv)
w1 = record.get_mainwindow()
w2 = display.get_mainwindow()
w1.closed.connect(w2.show)
w1.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Q1.py
from PySide2 import QtWidgets as qtw
from PySide2 import QtGui as qtg
from PySide2 import QtCore as qtc
class MainWindow(qtw.QMainWindow):
closed = qtc.Signal()
def __init__(self):
super().__init__()
# Create Window layout with a sound widget
soundboard = qtw.QWidget()
soundboard.setLayout(qtw.QGridLayout())
self.setCentralWidget(soundboard)
sw = SoundWidget()
soundboard.layout().addWidget(sw)
# Window Dimensions
self.setSizePolicy(qtw.QSizePolicy.Expanding, qtw.QSizePolicy.MinimumExpanding)
sw.sendorder_button.clicked.connect(self.close)
def closeEvent(self, event):
self.closed.emit()
super().closeEvent(event)
class SendOrderButton(qtw.QPushButton):
button_stylesheet = "background-color: blue; color: white;"
def __init__(self):
super().__init__("Send Order")
self.setSizePolicy(qtw.QSizePolicy.Expanding, qtw.QSizePolicy.Expanding)
self.setStyleSheet(self.button_stylesheet)
def press_button(self):
if self.isEnabled():
self.setEnabled(False)
self.setText("Send Order")
else:
self.setEnabled(True)
self.setText("Sent")
class SoundWidget(qtw.QWidget):
def __init__(self):
super().__init__()
self.setLayout(qtw.QGridLayout())
# Send Order Button
self.sendorder_button = SendOrderButton()
self.sendorder_button.setShortcut(qtg.QKeySequence("Tab"))
self.layout().addWidget(self.sendorder_button, 5, 0, 1, 2)
def get_mainwindow():
window = MainWindow()
return window
if __name__ == "__main__":
import sys
app = qtw.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Q2.py
from PySide2 import QtCore as qtc
from PySide2 import QtWidgets as qtw
class MainWindow(qtw.QMainWindow):
def __init__(self, widget):
super().__init__()
file_menu = self.menuBar().addMenu("&File")
# Exit QAction
exit_action = qtw.QAction("Exit", self)
exit_action.setShortcut("Ctrl+Q")
exit_action.triggered.connect(self.close)
file_menu.addAction(exit_action)
class CustomTableModel(qtc.QAbstractTableModel):
pass
class Widget(qtw.QWidget):
def __init__(self):
super().__init__()
# Getting the Model
self.model = CustomTableModel()
def get_mainwindow():
widget = Widget()
window2 = MainWindow(widget)
return window2
if __name__ == "__main__":
import sys
app = qtw.QApplication()
widget = Widget()
window = MainWindow(widget)
window.show()
sys.exit(app.exec_())
【讨论】:
非常感谢您,这非常有效!补充一点,如果我有想要在两个窗口之间运行的中间功能,那么我可以向这些操作添加信号以创建所需的事件序列吗?以上是关于如何在不退出 python 脚本的情况下销毁一个 QApplication 然后运行一个新的?的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用子进程的情况下从 python 自动化脚本中运行 python 'sdist' 命令?
如何在不使用 tkinter 打开控制台窗口的情况下运行 Python 脚本?
编写 Azure Devops / TFS API 脚本时 - 有没有办法在不退出的情况下处理“Get Repo 不存在”错误响应?