Python Pyqt5 QCoreApplication::exec:事件循环已在运行

Python Pyqt5 QCoreApplication::exec:事件循环已在运行,python,pyqt,pyqt5,mayavi,Python,Pyqt,Pyqt5,Mayavi,我有一个主窗口,它有一个按钮,当点击时会打开第二个窗口。第二个窗口包含mayavi绘图。每次单击此按钮,都会显示一个错误 QCoreApplication::exec:事件循环已在运行 我已经研究了许多类似的问题,但我无法解决我的问题 主窗口的代码maingui.py: # Standard library imports import re import sys import string import inspect import platform import importlib impo

我有一个主窗口,它有一个按钮,当点击时会打开第二个窗口。第二个窗口包含mayavi绘图。每次单击此按钮,都会显示一个错误

QCoreApplication::exec:事件循环已在运行

我已经研究了许多类似的问题,但我无法解决我的问题

主窗口的代码maingui.py

# Standard library imports
import re
import sys
import string
import inspect
import platform
import importlib
import ctypes
from os.path import abspath, join, dirname, realpath
from functools import wraps
import inspect
import matplotlib as mpl

# Local imports
from loadhistory.stresscorrection import DnvThicknessStressCorrection

# PyQt5 imports
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox, QListView, QWidget, QGridLayout
from PyQt5.QtGui import QPixmap

# Gui package import
import gui.design
import gui.resources
from gui.inputs import Inputs
from gui.filemanager import Filemanager
from gui.datawrapper import RunThread
from gui.mayaviwindow import MayaviWindow


class MainWindow(QMainWindow, gui.design.Ui_MainWindow):
    '''main window of the gui'''

    def __init__(self):
        QMainWindow.__init__(self)
        super().__init__()

        # Bypass needed to set taskbar icon if on windows
        if "Windows" in platform.system():
            myappid = 'LaboSoete'
            ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)

        self.inputs = Inputs(self)
        self.filemanager = Filemanager(self)
        self.mayaviwindow = MayaviWindow()
        self.setupUi(self)
        self.setWindowTitle("Endurance framework SafeLife")

        # Apply css stylesheet
        sshFile = "gui/stylesheet.css"
        with open(sshFile, "r") as fh:
            self.setStyleSheet(fh.read())

        # Initialize combobox design codes
        self.designcodes = self.inputs.code_dict()
        codes = list(self.designcodes.keys())
        self.design_code_combo.addItems(codes)
        self.design_cat_combo.addItems(self.designcodes[codes[0]])
        self.scrollbar_QComboBox(self.design_code_combo)
        self.scrollbar_QComboBox(self.design_cat_combo)

        # Initialize combobox Damagemodels
        module = importlib.import_module('damagemodels.damagemodels')
        for m in module.__dict__.values():
            if inspect.isclass(m):
                if 'damagemodels.damagemodels.' in str(m):
                    if not inspect.isabstract(m):
                        self.dmgBox.addItem(m.__name__)

        ###### Menubar ######
        self.actionSave.triggered.connect(self.filemanager.save)
        self.actionSave_as.triggered.connect(self.filemanager.save_as)
        self.actionLoad.triggered.connect(self.filemanager.load)
        self.actionOutput.triggered.connect(self.filemanager.change_output_dir)
        self.actionQuit.triggered.connect(self.close)

        ###### Button handeling ######
        self.loadhistory_btn.clicked.connect(self.inputs.lh_browse_file)
        self.odb_btn.clicked.connect(self.inputs.odb_browse_file)
        self.design_code_combo.currentIndexChanged.connect(
            self.inputs.design_combo_currentIndexChanged)
        self.btn_snCustom.clicked.connect(self.inputs.sn_browse_file)
        self.run_btn.clicked.connect(self.run_analysis)
        self.newBtn.clicked.connect(self.filemanager.new)
        self.abaqus_results_btn.clicked.connect(self.filemanager.open_odb_results)
        self.damageNnumber.textChanged.connect(lambda: self.check_numeric_entry(self.damageNnumber))
        self.hss_visualization_btn.clicked.connect(self.mayaviwindow.open_new_window)

        # DNV thickness correction initialization
        self.thicknessFrame.hide()
        self.design_cat_combo.currentIndexChanged.connect(self.show_thickness_correction)
        self.loadhistory_txt.textChanged.connect(self.loadhistory_txt_changed)
        self.radioBtn_snBasquin.toggled.connect(self.show_thickness_correction)
        self.radioBtn_snCustom.toggled.connect(self.show_thickness_correction)
        self.radioBtn_snDesign.toggled.connect(self.show_thickness_correction)
        self.radioBtn_snLog.toggled.connect(self.show_thickness_correction)

        ###### Tab/plot handeling ######

        # Loadhistory plot
        self.tabWidget.setCurrentIndex(0)
        self.loadhistory_txt.textChanged.connect(lambda: self.LhWidget.run(self))
        self.thicknessCorrCheckbox.toggled.connect(lambda: self.LhWidget.run(self))
        self.t_txt.textChanged.connect(lambda: self.LhWidget.run(self))
        self.tref_txt.textChanged.connect(lambda: self.LhWidget.run(self))
        self.k_txt.textChanged.connect(lambda: self.LhWidget.run(self))
        self.mscCheckBox.toggled.connect(lambda: self.LhWidget.run(self))
        self.mscSelectionBox.currentIndexChanged.connect(lambda: self.LhWidget.run(self))


        # Sncurve plot
        self.design_cat_combo.currentIndexChanged.connect(self.inputs.design_cat_combo_change)
        self.design_code_combo.currentIndexChanged.connect(self.inputs.design_combo_currentIndexChanged)
        self.sncurve_txt.textChanged.connect(lambda: self.SnWidget.run(self))
        self.radioBtn_snCustom.clicked.connect(lambda: self.SnWidget.run(self))
        self.radioBtn_snDesign.clicked.connect(lambda: self.SnWidget.run(self))
        self.radioBtn_snBasquin.clicked.connect(self.clear_sntxt_fields)
        self.radioBtn_snLog.clicked.connect(self.clear_sntxt_fields)
        self.Nf_txt.textChanged.connect(lambda: self.SnWidget.run(self))
        self.uts_txt.textChanged.connect(lambda: self.SnWidget.run(self))
        self.m1_txt.textChanged.connect(lambda: self.SnWidget.run(self))
        self.B1_txt.textChanged.connect(lambda: self.SnWidget.run(self))
        self.m2_txt.textChanged.connect(lambda: self.SnWidget.run(self))
        self.B2_txt.textChanged.connect(lambda: self.SnWidget.run(self))

        # HSS handeling
        self.hss_checkbox.toggled.connect(self.show_hss_image)
        self.hss_combobox.currentIndexChanged.connect(self.show_hss_image)
        self.hss_combobox.currentIndexChanged.connect(self.show_hide_hss_spinbox)

        ###### Output related ######
        self.hss_visualization_btn.hide()
        self.hideTab(3)
        self.abaqus_results_btn.hide()
        self.newBtn.hide()
        self.progressBar.hide()


    @staticmethod
    def eval_eq(equation):
        '''
        Check if the string 'equation' only contains allowable characters
        '''
        regex = re.compile(r'(\d+([.]|\*))?\d+(e|[.]|\*)?\d*(e|[.]|\*)?\d*?$')
        if (equation.endswith('e') or equation.endswith('.')) and re.match(regex, equation):
            return eval(equation[:-1])
        elif re.match(regex, equation) and equation.count('e') < 2:
            return eval(equation)
        else:
            raise ValueError(
                'Illegal expression used to define the S-N curve, only e^*'+string.digits+' allowed')

    def check_numeric_entry(self, myQlineEdit):
        '''
        For QlineEdit which can only contain numbers, check whether
        no non-numeric characters are entered
        '''
        if myQlineEdit.text().isdigit() or len(myQlineEdit.text()) < 1:
            return
        else:
            reply = QMessageBox.warning(self, 'TypeError', 'This field only allows for numeric entries')
            if reply == QMessageBox.Ok:
                myQlineEdit.setText(myQlineEdit.text()[:-1])
                return

    def loadhistory_txt_changed(self):
        '''
        If a loadhistory is selected the meanstresscorrection option
        becomes enabled
        '''
        if len(self.loadhistory_txt.text())>0:
            self.mscCheckBox.setEnabled(True)
        else:
            self.mscCheckBox.setDisabled(True)

    def show_thickness_correction(self):
        '''
        Determine whether or not the thickness_correction option should be shown and enabled.
        This is only the case when a DNV SN curve is selected
        '''
        if 'DNV' in self.design_code_combo.currentText() and self.radioBtn_snDesign.isChecked() and len(self.loadhistory_txt.text())>0:
            self.thicknessFrame.show()
            self.thicknessCorrCheckbox.setEnabled(True)
        else:
            self.thicknessFrame.hide()
            self.thicknessCorrCheckbox.setChecked(False)
            self.thicknessCorrCheckbox.setDisabled(True)

    def show_hss_image(self):
        if self.hss_checkbox.isChecked():
            filename = self.hss_combobox.currentText()
            filepath = abspath(join(dirname(realpath(__file__)), 'gui', 'icons', filename))
            pixmap = QPixmap(filepath)
            self.hss_imagelabel.setPixmap(pixmap)
            self.hss_imagelabel.show()
            self.tabWidget.setCurrentIndex(2)
        if not self.hss_checkbox.isChecked():
            self.hss_imagelabel.hide()


    def get_thickness_correction(self):
        '''
        Return a thickness correction object using the values from the
        gui to initialize the object
        '''
        if "DNV" in self.design_code_combo.currentText():
            tref = self.eval_eq(self.tref_txt.text())
            t = self.eval_eq(self.t_txt.text())
            k = self.eval_eq(self.k_txt.text())
            if k >= 1:
                reply = QMessageBox.warning(
                    self, 'ValueError', 'k needs to be less than one, please consult DNV-GL-RP203 for the correct values')
                if reply == QMessageBox.Ok or reply == QMessageBox.Cancel:
                    self.k_txt.clear()
                    return
                else: return
            return DnvThicknessStressCorrection(tref, t, k)

    def show_hide_hss_spinbox(self):
        '''
        hide the hss_spinbox and hss_t_label widgets if a hss method, that does not
        use the plate thickness to determine the extrapolation coords, is selected
        '''
        test = self.hss_combobox.currentText()
        lst = ['1', '2', '3']
        if any(x in test for x in lst):
            self.hss_spinbox.show()
            self.hss_t_label.show()
        else:
            self.hss_t_label.hide()
            self.hss_t_label.show()

    def scrollbar_QComboBox(self, combo):
        '''
        Add a scrollbar to QComboBoxes if the selected text is wider than
        the combobox
        '''
        view = QListView(combo)
        combo.setView(view)
        view.setTextElideMode(Qt.ElideNone)
        view.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)


    def closeEvent(self, event):
        '''
        Handle the event of the user wanting to close the application
        '''
        msgBox = QMessageBox()
        msgBox.setWindowTitle('Exit application?')
        msgBox.setText('Do you want to exit the application?')
        exit_btn = msgBox.addButton('Exit', QMessageBox.YesRole)
        save_exit_btn = msgBox.addButton('Save and Exit', QMessageBox.YesRole)
        cancel_btn = msgBox.addButton('Cancel', QMessageBox.RejectRole)
        msgBox.setEscapeButton(cancel_btn)

        msgBox.exec_()

        if msgBox.clickedButton() == exit_btn:
            event.accept()
        elif msgBox.clickedButton() == save_exit_btn:
            self.filemanager.save()
            event.accept()
        elif msgBox.clickedButton() == cancel_btn:
            event.ignore()



    def start_thread(self, thread):
        '''Pass all MainWindow attributes to the new thread and start the thread'''
        thread.progressBar = self.progressBar
        thread.loadhistory_txt = self.loadhistory_txt
        thread.loadhistory_btn = self.loadhistory_btn
        thread.odb_txt = self.odb_txt
        thread.odb_btn = self.odb_btn
        thread.dmgBox = self.dmgBox
        thread.dmax_box = self.dmax_box
        thread.radioBtn_snCustom = self.radioBtn_snCustom
        thread.radioBtn_snBasquin = self.radioBtn_snBasquin
        thread.radioBtn_snDesign = self.radioBtn_snDesign
        thread.sncurve_txt = self.sncurve_txt
        thread.btn_snCustom = self.btn_snCustom
        thread.design_cat_combo = self.design_cat_combo
        thread.design_code_combo = self.design_code_combo
        thread.mscCheckBox = self.mscCheckBox
        thread.mscSelectionBox = self.mscSelectionBox
        thread.calcLifetimeBox = self.calcLifetimeBox
        thread.calcLifetimeCheckBox = self.calcLifetimeCheckBox
        thread.damageNcheckBox = self.damageNcheckBox
        thread.damageNnumber = self.damageNnumber
        thread.newBtn = self.newBtn
        thread.m1_txt = self.m1_txt
        thread.B1_txt = self.B1_txt
        thread.m2_txt = self.m2_txt
        thread.B2_txt = self.B2_txt
        thread.uts_txt = self.uts_txt
        thread.Nf_txt = self.Nf_txt
        thread.SnWidget = self.SnWidget
        thread.LhWidget = self.LhWidget
        thread.Inputs = self.inputs
        thread.thicknessCorrCheckbox = self.thicknessCorrCheckbox
        thread.k_txt = self.k_txt
        thread.t_txt = self.t_txt
        thread.tref_txt = self.tref_txt
        thread.hss_spinbox = self.hss_spinbox
        thread.hss_combobox = self.hss_combobox
        thread.hss_checkbox = self.hss_combobox
        thread.start()

    def clear_sntxt_fields(self):
        '''Clear all text fields related to SN curve equations'''
        self.Nf_txt.clear()
        self.uts_txt.clear()
        self.m1_txt.clear()
        self.m2_txt.clear()
        self.B1_txt.clear()
        self.B2_txt.clear()

    def initialize(self):
        self.hss_visualization_btn.hide()
        self.run_btn.setDisabled(True)
        self.newBtn.hide()
        self.abaqus_results_btn.hide()
        self.hideTab(3)
        self.output_txt.clear()

    def finished(self):
        if self.hss_checkbox.isChecked():
            self.hss_visualization_btn.show()
        self.run_btn.setEnabled(True)
        self.newBtn.show()
        self.abaqus_results_btn.show()
        self.hide_progressbar()
        self.showTab(3)

    def show_progressbar(self):
        self.progressBar.show()

    def hide_progressbar(self):
        self.progressBar.hide()

    def clear_lhtxt(self):
        self.loadhistory_txt.clear()
        self.loadhistory_txt.setFocus()

    def clear_odbtxt(self):
        self.odb_txt.clear()
        self.odb_txt.setFocus()

    def clear_sncustomtxt(self):
        self.sncurve_txt.clear()
        self.sncurve_txt.setFocus()

    def show_messagebox(self, errortype, msg, methodname):
        reply = QMessageBox.warning(self, errortype, msg)
        if methodname is not "None":
            handle_error = getattr(self, methodname)
        if reply == QMessageBox.Ok:
            if 'handle_error' in locals():
                handle_error()
            return

    def dmg_curve_plot(self, Dplot, nNplot):
        self.DmgWidget.run(self, Dplot, nNplot)

    def hideTab(self, tabIndex):
        self.tabWidget.setTabEnabled(tabIndex, False)

    def showTab(self, tabIndex):
        self.tabWidget.setTabEnabled(tabIndex, True)

    def check_required_inputs(self):
        if "".__eq__(self.loadhistory_txt.text()) or "".__eq__(self.odb_txt.text()) \
            or not self.odb_txt.text().endswith('odb'):
            return False
        if self.radioBtn_snCustom.isChecked() and "".__eq__(self.sncurve_txt.text()):
            return False
        if self.radioBtn_snBasquin.isChecked() or self.radioBtn_snLog.isChecked():
            if ("".__eq__(self.m1_txt.text()) or "".__eq__(self.Nf_txt.text()) or \
               "".__eq__(self.uts_txt.text()) or "".__eq__(self.B1_txt.text())):
                return False
        return True

    def run_analysis(self):

        mpl.pyplot.close(fig="all")

        if self.check_required_inputs() is False:
            self.show_messagebox('IOError', 'Please check all required fields', "None")
            return

        self.run_thread = RunThread(self)
        self.run_thread.initialize.connect(self.initialize)
        self.run_thread.clear_lhtxt.connect(self.clear_lhtxt)
        self.run_thread.clear_odbtxt.connect(self.clear_odbtxt)
        self.run_thread.clear_odbtxt.connect(self.clear_sncustomtxt)
        self.run_thread.show_messagebox.connect(self.show_messagebox)

        self.run_thread.show_progressbar.connect(self.show_progressbar)
        self.run_thread.hide_progressbar.connect(self.hide_progressbar)

        self.run_thread.finished.connect(self.finished)
        self.run_thread.output.connect(self.filemanager.to_output)
        self.run_thread.dmg_curve_plot.connect(self.dmg_curve_plot)
        self.start_thread(self.run_thread)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())
import os
import sys
import mayavi.mlab as mlab
os.environ['ETS_TOOLKIT'] = 'qt4'
from pyface.qt import QtGui, QtCore
from traits.api import HasTraits, Instance, on_trait_change
from traitsui.api import View, Item
from mayavi.core.ui.api import MayaviScene, MlabSceneModel, SceneEditor

class MayaviWindow(QtGui.QMainWindow):
    def open_new_window(self):
        container = QtGui.QWidget()
        container.setWindowTitle("Hot spot stress")
        layout = QtGui.QGridLayout(container)
        mayavi_widget = MayaviQWidget(container)
        layout.addWidget(mayavi_widget, 1, 1)
        container.show()
        self.window = QtGui.QMainWindow()
        self.window.setCentralWidget(container)
        self.window.show()

class Visualization(HasTraits):
    scene = Instance(MlabSceneModel, ())

    @on_trait_change('scene.activated')
    def update_plot(self):   
        self.scene.mlab.test_points3d()

    # the layout of the dialog screated
    view = View(Item('scene', editor=SceneEditor(scene_class=MayaviScene),
                     height=250, width=300, show_label=False),
                resizable=True # We need this to resize with the parent widget
                )
class MayaviQWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        layout = QtGui.QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        self.visualization = Visualization()

        # The edit_traits call will generate the widget to embed.
        self.ui = self.visualization.edit_traits(parent=self,
                                                 kind='subpanel').control
        layout.addWidget(self.ui)
        self.ui.setParent(self)
有人能给我解释一下问题是什么吗

编辑 将类MayaviWindow更改为从QWidget而不是QMainwindow继承并没有解决问题


这个答案有用吗?()似乎您正在调用
app.exec()
,两次。但是你的代码看起来不错。这是你的完整代码吗?@Romha Korev,我在代码中只有一个app.exec()调用。我已经添加了我的“maingui.py”文件的完整代码。我认为你不能有两个
QMainWindow
MayaviWindow
应该继承自
QWidget
,而不是
QMainWindow
。请参阅以供参考。@FelipeLema我已经尝试过了,但没有解决问题(请参阅编辑)。这个答案有用吗?()似乎您正在调用
app.exec()
,两次。但是你的代码看起来不错。这是你的完整代码吗?@Romha Korev,我在代码中只有一个app.exec()调用。我已经添加了我的“maingui.py”文件的完整代码。我认为你不能有两个
QMainWindow
MayaviWindow
应该继承自
QWidget
,而不是
QMainWindow
。请参阅以供参考。@FelipeLema我已经尝试过了,但没有解决问题(请参阅编辑)
class MayaviWindow(QtGui.QWidget):
    def open_new_window(self):
        self.container = QtGui.QWidget()
        self.container.setWindowTitle("Hot spot stress")
        layout = QtGui.QGridLayout(self.container)
        mayavi_widget = MayaviQWidget(self.container)
        layout.addWidget(mayavi_widget, 1, 1)
        self.container.show()