如何销毁一个 QApplication,然后在不退出 Python 脚本的情况下运行一个新的?

huangapple go评论100阅读模式
英文:

How to destroy a QApplication and then run a new one without exiting the python script?

问题

我想创建一个QApplication,然后使用键盘快捷键退出它。然后Python脚本应该调用另一个QApplication。

我的问题是当第二个QApplication即将运行时,我收到以下错误:

app2 = QApplication()
RuntimeError: 在创建新的QApplication实例之前,请销毁QApplication单例。

我有以下结构:

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

这是Q1,它引起了问题:

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

        # 创建带有声音小部件的窗口布局
        soundboard = qtw.QWidget()
        soundboard.setLayout(qtw.QGridLayout())
        self.setCentralWidget(soundboard)
        sw = SoundWidget()
        soundboard.layout().addWidget(sw)

        # 窗口尺寸
        self.setSizePolicy(qtw.QSizePolicy.Expanding, qtw.QSizePolicy.MinimumExpanding)

        # 代码结束
        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)

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

        # 发送订单按钮
        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_())

这是Q2.py,其中包含第二个QApplication:

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)

        # 退出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)

        # 获取模型
        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_())
英文:

I want to create a QApplication which is then exited using a keyboard shortcut. Then the python script should call another QApplication.

My issues currently is that I get this error when the second QApplication is about to run:

app2 = QApplication()
RuntimeError: Please destroy the QApplication singleton before creating a new QApplication instance.

I have the following structure:

| main.py
| Q1.py
| Q2.py

This is main.py:

import Q1 as record
import Q2 as display

def main():
    record.main()
    display.main()


if __name__ == "__main__":
    main()

This is Q1 which creates the problem:

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

This is Q2.py which has the second QApplication:

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

答案1

得分: 2

以下是您要翻译的内容:

As noted in the comments a Qt application can only and should have a QApplication (you might not follow this rule but nothing guarantees that it works correctly) so you will have to restructure your code.

Assuming that you want the Q1 window to be first and when that window is closed then the Q2 window opens that does not imply at any time that you have to use several QApplication. The idea is to know when a window is closed and to be notified of it, to know when a window is closed then you must override the closeEvent method of the window and to make the notification you must send a signal.

Considering the above, the solution is:

├── 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_())
英文:

As noted in the comments a Qt application can only and should have a QApplication (you might not follow this rule but nothing guarantees that it works correctly) so you will have to restructure your code.

Assuming that you want the Q1 window to be first and when that window is closed then the Q2 window opens that does not imply at any time that you have to use several QApplication. The idea is to know when a window is closed and to be notified of it, to know when a window is closed then you must override the closeEvent method of the window and to make the notification you must send a signal.

Considering the above, the solution is:

├── 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_())

huangapple
  • 本文由 发表于 2020年1月4日 00:04:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/59581668.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定