У меня есть главное окно, в котором есть кнопка, которая открывает второе окно при нажатии. Это второе окно содержит сюжет майяви. Каждый раз, когда я нажимаю эту кнопку, появляется сообщение об ошибке
QCoreApplication :: exec: цикл обработки событий уже выполняется
Я рассмотрел несколько похожих вопросов по SO, но не могу решить свою проблему.
код главного окна 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_())
код второго окна mayaviwindow.py :
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 не решило проблему
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()