def wrap_image(image: ImageView) -> QScrollArea: """Wraps an image in a scrollable and resizable container.""" area = QScrollArea() area.setWidget(image) area.setWidgetResizable(True) area.setAlignment(Qt.AlignCenter) return area
def _widgets(self): splitter = QSplitter() # -- Left left_splitter = QSplitter(Qt.Vertical) splitter.addWidget(left_splitter) # Top left filetree = FileTree(self._root_path, self._on_filetree_selection_changed) left_splitter.addWidget(filetree) # Bottom left tagging = Tagging() left_splitter.addWidget(tagging) # -- Right image = ImageDisplay() # Wrap it in a resizable scroll area area = QScrollArea() area.setWidget(image) area.setWidgetResizable(True) area.setAlignment(Qt.AlignCenter) splitter.addWidget(area) # A slight hack to split width equally splitter.setSizes([100000, 100000]) return splitter, filetree, tagging, image
class ResultBlockViewWidget(QMainWindow): # Конструктор def __init__(self, block_name, result, parent=None): super(ResultBlockViewWidget, self).__init__(parent) self.setWindowTitle(f'Результаты выполнения блока \'{block_name}\'') self.setWindowModality(Qt.ApplicationModal) self.setMinimumWidth(640) self.central_widget = QWidget() self.scroll = QScrollArea() self.layout = QVBoxLayout(self.central_widget) self.init_ui(result) # Метод инициализации UI def init_ui(self, result): self.scroll.setAlignment(Qt.AlignCenter) self.layout.setAlignment(Qt.AlignTop) self.setCentralWidget(self.central_widget) self.layout.addWidget(self.scroll) widget = QWidget() layout = QVBoxLayout(widget) for i in range(0, len(result)): result_label = QLabel(f'Команда №{i + 1}: \'{result[i][1].strip()}\'.') result_label.setAlignment(Qt.AlignCenter) if result[i][0] == 0: result_label.setStyleSheet('background-color: ForestGreen;') else: result_label.setStyleSheet('background-color: OrangeRed;') layout.addWidget(result_label) self.scroll.setWidget(widget)
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() openmc.capi.init(['-c']) self.setWindowTitle('OpenMC Plot Explorer') self.restored = False self.pixmap = None self.zoom = 100 self.model = PlotModel() self.updateRelativeBases() self.restoreModelSettings() self.cellsModel = DomainTableModel(self.model.activeView.cells) self.materialsModel = DomainTableModel(self.model.activeView.materials) # Create viewing area self.frame = QScrollArea(self) self.frame.setAlignment(QtCore.Qt.AlignCenter) self.frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.setCentralWidget(self.frame) # Create plot image self.plotIm = PlotImage(self.model, self.frame, self) self.frame.setWidget(self.plotIm) # Dock self.dock = OptionsDock(self.model, FM, self) self.dock.setObjectName("OptionsDock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dock) # Color Dialog self.colorDialog = ColorDialog(self.model, FM, self) self.colorDialog.hide() # Restore Window Settings self.restoreWindowSettings() # Create menubar self.createMenuBar() # Status Bar self.coord_label = QLabel() self.statusBar().addPermanentWidget(self.coord_label) self.coord_label.hide() # Load Plot self.statusBar().showMessage('Generating Plot...') self.dock.updateDock() self.colorDialog.updateDialogValues() if self.restored: self.showCurrentView() else: # Timer allows GUI to render before plot finishes loading QtCore.QTimer.singleShot(0, self.model.generatePlot) QtCore.QTimer.singleShot(0, self.showCurrentView) # Create and update menus: def createMenuBar(self): self.mainMenu = self.menuBar() # File Menu self.saveImageAction = QAction("&Save Image As...", self) self.saveImageAction.setShortcut("Ctrl+Shift+S") self.saveImageAction.setToolTip('Save plot image') self.saveImageAction.setStatusTip('Save plot image') self.saveImageAction.triggered.connect(self.saveImage) self.saveViewAction = QAction("Save &View Settings...", self) self.saveViewAction.setShortcut(QtGui.QKeySequence.Save) self.saveViewAction.setStatusTip('Save current view settings') self.saveViewAction.triggered.connect(self.saveView) self.openAction = QAction("&Open View Settings...", self) self.openAction.setShortcut(QtGui.QKeySequence.Open) self.openAction.setToolTip('Open saved view settings') self.openAction.setStatusTip('Open saved view settings') self.openAction.triggered.connect(self.openView) self.quitAction = QAction("&Quit", self) self.quitAction.setShortcut(QtGui.QKeySequence.Quit) self.quitAction.setToolTip('Quit OpenMC Plot Explorer') self.quitAction.setStatusTip('Quit OpenMC Plot Explorer') self.quitAction.triggered.connect(self.close) self.fileMenu = self.mainMenu.addMenu('&File') self.fileMenu.addAction(self.saveImageAction) self.fileMenu.addSeparator() self.fileMenu.addAction(self.saveViewAction) self.fileMenu.addAction(self.openAction) self.fileMenu.addSeparator() self.fileMenu.addAction(self.quitAction) # Edit Menu self.applyAction = QAction("&Apply Changes", self) self.applyAction.setShortcut("Shift+Return") self.applyAction.setToolTip('Generate new view with changes applied') self.applyAction.setStatusTip('Generate new view with changes applied') self.applyAction.triggered.connect(self.applyChanges) self.undoAction = QAction('&Undo', self) self.undoAction.setShortcut(QtGui.QKeySequence.Undo) self.undoAction.setToolTip('Undo') self.undoAction.setStatusTip('Undo last plot view change') self.undoAction.setDisabled(True) self.undoAction.triggered.connect(self.undo) self.redoAction = QAction('&Redo', self) self.redoAction.setDisabled(True) self.redoAction.setToolTip('Redo') self.redoAction.setStatusTip('Redo last plot view change') self.redoAction.setShortcut(QtGui.QKeySequence.Redo) self.redoAction.triggered.connect(self.redo) self.restoreAction = QAction("&Restore Default Plot", self) self.restoreAction.setShortcut("Ctrl+R") self.restoreAction.setToolTip('Restore to default plot view') self.restoreAction.setStatusTip('Restore to default plot view') self.restoreAction.triggered.connect(self.restoreDefault) self.editMenu = self.mainMenu.addMenu('&Edit') self.editMenu.addAction(self.applyAction) self.editMenu.addSeparator() self.editMenu.addAction(self.undoAction) self.editMenu.addAction(self.redoAction) self.editMenu.addSeparator() self.editMenu.addAction(self.restoreAction) self.editMenu.addSeparator() self.editMenu.aboutToShow.connect(self.updateEditMenu) # Edit -> Basis Menu self.xyAction = QAction('&xy ', self) self.xyAction.setCheckable(True) self.xyAction.setShortcut('Alt+X') self.xyAction.setToolTip('Change to xy basis') self.xyAction.setStatusTip('Change to xy basis') self.xyAction.triggered.connect( lambda: self.editBasis('xy', apply=True)) self.xzAction = QAction('x&z ', self) self.xzAction.setCheckable(True) self.xzAction.setShortcut('Alt+Z') self.xzAction.setToolTip('Change to xz basis') self.xzAction.setStatusTip('Change to xz basis') self.xzAction.triggered.connect( lambda: self.editBasis('xz', apply=True)) self.yzAction = QAction('&yz ', self) self.yzAction.setCheckable(True) self.yzAction.setShortcut('Alt+Y') self.yzAction.setToolTip('Change to yz basis') self.yzAction.setStatusTip('Change to yz basis') self.yzAction.triggered.connect( lambda: self.editBasis('yz', apply=True)) self.basisMenu = self.editMenu.addMenu('&Basis') self.basisMenu.addAction(self.xyAction) self.basisMenu.addAction(self.xzAction) self.basisMenu.addAction(self.yzAction) self.basisMenu.aboutToShow.connect(self.updateBasisMenu) # Edit -> Color By Menu self.cellAction = QAction('&Cell', self) self.cellAction.setCheckable(True) self.cellAction.setShortcut('Alt+C') self.cellAction.setToolTip('Color by cell') self.cellAction.setStatusTip('Color plot by cell') self.cellAction.triggered.connect( lambda: self.editColorBy('cell', apply=True)) self.materialAction = QAction('&Material', self) self.materialAction.setCheckable(True) self.materialAction.setShortcut('Alt+M') self.materialAction.setToolTip('Color by material') self.materialAction.setStatusTip('Color plot by material') self.materialAction.triggered.connect( lambda: self.editColorBy('material', apply=True)) self.colorbyMenu = self.editMenu.addMenu('&Color By') self.colorbyMenu.addAction(self.cellAction) self.colorbyMenu.addAction(self.materialAction) self.colorbyMenu.aboutToShow.connect(self.updateColorbyMenu) self.editMenu.addSeparator() self.maskingAction = QAction('Enable &Masking', self) self.maskingAction.setShortcut('Ctrl+M') self.maskingAction.setCheckable(True) self.maskingAction.setToolTip('Toggle masking') self.maskingAction.setStatusTip('Toggle whether masking is enabled') self.maskingAction.triggered[bool].connect( lambda bool=bool: self.toggleMasking(bool, apply=True)) self.editMenu.addAction(self.maskingAction) self.highlightingAct = QAction('Enable High&lighting', self) self.highlightingAct.setShortcut('Ctrl+L') self.highlightingAct.setCheckable(True) self.highlightingAct.setToolTip('Toggle highlighting') self.highlightingAct.setStatusTip( 'Toggle whether highlighting is enabled') self.highlightingAct.triggered[bool].connect( lambda bool=bool: self.toggleHighlighting(bool, apply=True)) self.editMenu.addAction(self.highlightingAct) # View Menu self.dockAction = QAction('Hide &Dock', self) self.dockAction.setShortcut("Ctrl+D") self.dockAction.setToolTip('Toggle dock visibility') self.dockAction.setStatusTip('Toggle dock visibility') self.dockAction.triggered.connect(self.toggleDockView) self.zoomAction = QAction('&Zoom...', self) self.zoomAction.setShortcut('Alt+Shift+Z') self.zoomAction.setToolTip('Edit zoom factor') self.zoomAction.setStatusTip('Edit zoom factor') self.zoomAction.triggered.connect(self.editZoomAct) self.viewMenu = self.mainMenu.addMenu('&View') self.viewMenu.addAction(self.dockAction) self.viewMenu.addSeparator() self.viewMenu.addAction(self.zoomAction) self.viewMenu.aboutToShow.connect(self.updateViewMenu) # Window Menu self.mainWindowAction = QAction('&Main Window', self) self.mainWindowAction.setShortcut('Alt+W') self.mainWindowAction.setCheckable(True) self.mainWindowAction.setToolTip('Bring main window to front') self.mainWindowAction.setStatusTip('Bring main window to front') self.mainWindowAction.triggered.connect(self.showMainWindow) self.colorDialogAction = QAction('Color &Options', self) self.colorDialogAction.setShortcut('Alt+D') self.colorDialogAction.setCheckable(True) self.colorDialogAction.setToolTip('Bring Color Dialog to front') self.colorDialogAction.setStatusTip('Bring Color Dialog to front') self.colorDialogAction.triggered.connect(self.showColorDialog) self.windowMenu = self.mainMenu.addMenu('&Window') self.windowMenu.addAction(self.mainWindowAction) self.windowMenu.addAction(self.colorDialogAction) self.windowMenu.aboutToShow.connect(self.updateWindowMenu) def updateEditMenu(self): changed = self.model.currentView != self.model.defaultView self.restoreAction.setDisabled(not changed) self.maskingAction.setChecked(self.model.currentView.masking) self.highlightingAct.setChecked(self.model.currentView.highlighting) self.undoAction.setText(f'&Undo ({len(self.model.previousViews)})') self.redoAction.setText(f'&Redo ({len(self.model.subsequentViews)})') def updateBasisMenu(self): self.xyAction.setChecked(self.model.currentView.basis == 'xy') self.xzAction.setChecked(self.model.currentView.basis == 'xz') self.yzAction.setChecked(self.model.currentView.basis == 'yz') def updateColorbyMenu(self): cv = self.model.currentView self.cellAction.setChecked(cv.colorby == 'cell') self.materialAction.setChecked(cv.colorby == 'material') def updateViewMenu(self): if self.dock.isVisible(): self.dockAction.setText('Hide &Dock') else: self.dockAction.setText('Show &Dock') def updateWindowMenu(self): self.colorDialogAction.setChecked(self.colorDialog.isActiveWindow()) self.mainWindowAction.setChecked(self.isActiveWindow()) # Menu and shared methods: def saveImage(self): filename, ext = QFileDialog.getSaveFileName(self, "Save Plot Image", "untitled", "Images (*.png *.ppm)") if filename: if "." not in filename: filename += ".png" self.plotIm.figure.savefig(filename, transparent=True) self.statusBar().showMessage('Plot Image Saved', 5000) def saveView(self): filename, ext = QFileDialog.getSaveFileName(self, "Save View Settings", "untitled", "View Settings (*.pltvw)") if filename: if "." not in filename: filename += ".pltvw" saved = { 'default': self.model.defaultView, 'current': self.model.currentView } with open(filename, 'wb') as file: pickle.dump(saved, file) def openView(self): filename, ext = QFileDialog.getOpenFileName(self, "Open View Settings", ".", "*.pltvw") if filename: try: with open(filename, 'rb') as file: saved = pickle.load(file) except Exception: message = 'Error loading plot settings' saved = {'default': None, 'current': None} if saved['default'] == self.model.defaultView: self.model.activeView = saved['current'] self.dock.updateDock() self.applyChanges() message = f'{filename} settings loaded' else: message = 'Error loading plot settings. Incompatible model.' self.statusBar().showMessage(message, 5000) def applyChanges(self): if self.model.activeView != self.model.currentView: self.statusBar().showMessage('Generating Plot...') QApplication.processEvents() self.model.storeCurrent() self.model.subsequentViews = [] self.model.generatePlot() self.resetModels() self.showCurrentView() else: self.statusBar().showMessage('No changes to apply.', 3000) def undo(self): self.statusBar().showMessage('Generating Plot...') QApplication.processEvents() self.model.undo() self.resetModels() self.showCurrentView() self.dock.updateDock() self.colorDialog.updateDialogValues() if not self.model.previousViews: self.undoAction.setDisabled(True) self.redoAction.setDisabled(False) def redo(self): self.statusBar().showMessage('Generating Plot...') QApplication.processEvents() self.model.redo() self.resetModels() self.showCurrentView() self.dock.updateDock() self.colorDialog.updateDialogValues() if not self.model.subsequentViews: self.redoAction.setDisabled(True) self.undoAction.setDisabled(False) def restoreDefault(self): if self.model.currentView != self.model.defaultView: self.statusBar().showMessage('Generating Plot...') QApplication.processEvents() self.model.storeCurrent() self.model.activeView = copy.deepcopy(self.model.defaultView) self.model.generatePlot() self.resetModels() self.showCurrentView() self.dock.updateDock() self.colorDialog.updateDialogValues() self.model.subsequentViews = [] def editBasis(self, basis, apply=False): self.model.activeView.basis = basis self.dock.updateBasis() if apply: self.applyChanges() def editColorBy(self, domain_kind, apply=False): self.model.activeView.colorby = domain_kind self.dock.updateColorBy() self.colorDialog.updateColorBy() if apply: self.applyChanges() def toggleMasking(self, state, apply=False): self.model.activeView.masking = bool(state) self.colorDialog.updateMasking() if apply: self.applyChanges() def toggleHighlighting(self, state, apply=False): self.model.activeView.highlighting = bool(state) self.colorDialog.updateHighlighting() if apply: self.applyChanges() def toggleDockView(self): if self.dock.isVisible(): self.dock.hide() if not self.isMaximized() and not self.dock.isFloating(): self.resize(self.width() - self.dock.width(), self.height()) else: self.dock.setVisible(True) if not self.isMaximized() and not self.dock.isFloating(): self.resize(self.width() + self.dock.width(), self.height()) self.resizePixmap() self.showMainWindow() def editZoomAct(self): percent, ok = QInputDialog.getInt(self, "Edit Zoom", "Zoom Percent:", self.dock.zoomBox.value(), 25, 2000) if ok: self.dock.zoomBox.setValue(percent) def editZoom(self, value): self.zoom = value self.resizePixmap() self.dock.zoomBox.setValue(value) def showMainWindow(self): self.raise_() self.activateWindow() def showColorDialog(self): self.colorDialog.show() self.colorDialog.raise_() self.colorDialog.activateWindow() # Dock methods: def editSingleOrigin(self, value, dimension): self.model.activeView.origin[dimension] = value def editPlotAlpha(self, value): self.model.activeView.plotAlpha = value self.dock.updatePlotAlpha() def editWidth(self, value): self.model.activeView.width = value self.onRatioChange() self.dock.updateWidth() def editHeight(self, value): self.model.activeView.height = value self.onRatioChange() self.dock.updateHeight() def toggleAspectLock(self, state): self.model.activeView.aspectLock = bool(state) self.onRatioChange() self.dock.updateAspectLock() def editVRes(self, value): self.model.activeView.v_res = value self.dock.updateVRes() def editHRes(self, value): self.model.activeView.h_res = value self.onRatioChange() self.dock.updateHRes() # Color dialog methods: def editMaskingColor(self): current_color = self.model.activeView.maskBackground dlg = QColorDialog(self) dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color)) if dlg.exec_(): new_color = dlg.currentColor().getRgb()[:3] self.model.activeView.maskBackground = new_color self.colorDialog.updateMaskingColor() def editHighlightColor(self): current_color = self.model.activeView.highlightBackground dlg = QColorDialog(self) dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color)) if dlg.exec_(): new_color = dlg.currentColor().getRgb()[:3] self.model.activeView.highlightBackground = new_color self.colorDialog.updateHighlightColor() def editAlpha(self, value): self.model.activeView.highlightAlpha = value def editSeed(self, value): self.model.activeView.highlightSeed = value def editBackgroundColor(self, apply=False): current_color = self.model.activeView.plotBackground dlg = QColorDialog(self) dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color)) if dlg.exec_(): new_color = dlg.currentColor().getRgb()[:3] self.model.activeView.plotBackground = new_color self.colorDialog.updateBackgroundColor() if apply: self.applyChanges() # Plot image methods def editPlotOrigin(self, xOr, yOr, zOr=None, apply=False): if zOr != None: self.model.activeView.origin = [xOr, yOr, zOr] else: origin = [None, None, None] origin[self.xBasis] = xOr origin[self.yBasis] = yOr origin[self.zBasis] = self.model.activeView.origin[self.zBasis] self.model.activeView.origin = origin self.dock.updateOrigin() if apply: self.applyChanges() def revertDockControls(self): self.dock.revertToCurrent() def editDomainColor(self, kind, id): if kind == 'Cell': domain = self.model.activeView.cells else: domain = self.model.activeView.materials current_color = domain[id].color dlg = QColorDialog(self) if isinstance(current_color, tuple): dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color)) elif isinstance(current_color, str): current_color = openmc.plots._SVG_COLORS[current_color] dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color)) if dlg.exec_(): new_color = dlg.currentColor().getRgb()[:3] domain[id].color = new_color self.applyChanges() def toggleDomainMask(self, state, kind, id): if kind == 'Cell': domain = self.model.activeView.cells else: domain = self.model.activeView.materials domain[id].masked = bool(state) self.applyChanges() def toggleDomainHighlight(self, state, kind, id): if kind == 'Cell': domain = self.model.activeView.cells else: domain = self.model.activeView.materials domain[id].highlighted = bool(state) self.applyChanges() # Helper methods: def restoreWindowSettings(self): settings = QtCore.QSettings() self.resize(settings.value("mainWindow/Size", QtCore.QSize(800, 600))) self.move( settings.value("mainWindow/Position", QtCore.QPoint(100, 100))) self.restoreState(settings.value("mainWindow/State")) self.colorDialog.resize( settings.value("colorDialog/Size", QtCore.QSize(400, 500))) self.colorDialog.move( settings.value("colorDialog/Position", QtCore.QPoint(600, 200))) self.colorDialog.setVisible( bool(settings.value("colorDialog/Visible", 0))) def restoreModelSettings(self): if os.path.isfile("plot_settings.pkl"): with open('plot_settings.pkl', 'rb') as file: model = pickle.load(file) if model.defaultView == self.model.defaultView: self.model.currentView = model.currentView self.model.activeView = copy.deepcopy(model.currentView) self.model.previousViews = model.previousViews self.model.subsequentViews = model.subsequentViews if os.path.isfile('plot_ids.binary') \ and os.path.isfile('plot.ppm'): self.restored = True def resetModels(self): self.cellsModel = DomainTableModel(self.model.activeView.cells) self.materialsModel = DomainTableModel(self.model.activeView.materials) self.cellsModel.beginResetModel() self.cellsModel.endResetModel() self.materialsModel.beginResetModel() self.materialsModel.endResetModel() self.colorDialog.updateDomainTabs() def showCurrentView(self): self.resizePixmap() self.updateScale() self.updateRelativeBases() if self.model.previousViews: self.undoAction.setDisabled(False) if self.model.subsequentViews: self.redoAction.setDisabled(False) else: self.redoAction.setDisabled(True) self.statusBar().showMessage('Done', 1000) self.adjustWindow() def updateScale(self): cv = self.model.currentView self.scale = (cv.h_res / cv.width, cv.v_res / cv.height) def updateRelativeBases(self): cv = self.model.currentView self.xBasis = 0 if cv.basis[0] == 'x' else 1 self.yBasis = 1 if cv.basis[1] == 'y' else 2 self.zBasis = 3 - (self.xBasis + self.yBasis) def adjustWindow(self): self.screen = app.desktop().screenGeometry() self.setMaximumSize(self.screen.width(), self.screen.height()) def onRatioChange(self): av = self.model.activeView if av.aspectLock: ratio = av.width / max(av.height, .001) av.v_res = int(av.h_res / ratio) self.dock.updateVRes() def showCoords(self, xPlotPos, yPlotPos): cv = self.model.currentView if cv.basis == 'xy': coords = (f"({round(xPlotPos, 2)}, {round(yPlotPos, 2)}, " f"{round(cv.origin[2], 2)})") elif cv.basis == 'xz': coords = (f"({round(xPlotPos, 2)}, {round(cv.origin[1], 2)}, " f"{round(yPlotPos, 2)})") else: coords = (f"({round(cv.origin[0], 2)}, {round(xPlotPos, 2)}, " f"{round(yPlotPos, 2)})") self.coord_label.setText(f'{coords}') def resizePixmap(self): z = self.zoom / 100. self.plotIm.setPixmap(self.frame.width() * z, self.frame.height() * z) self.plotIm.adjustSize() def moveEvent(self, event): self.adjustWindow() def resizeEvent(self, event): if self.pixmap: self.adjustWindow() self.updateScale() def closeEvent(self, event): settings = QtCore.QSettings() settings.setValue("mainWindow/Size", self.size()) settings.setValue("mainWindow/Position", self.pos()) settings.setValue("mainWindow/State", self.saveState()) settings.setValue("colorDialog/Size", self.colorDialog.size()) settings.setValue("colorDialog/Position", self.colorDialog.pos()) visible = int(self.colorDialog.isVisible()) settings.setValue("colorDialog/Visible", visible) if len(self.model.previousViews) > 10: self.model.previousViews = self.model.previousViews[-10:] if len(self.model.subsequentViews) > 10: self.model.subsequentViews = self.model.subsequentViews[-10:] with open('plot_settings.pkl', 'wb') as file: pickle.dump(self.model, file)
class SlideShow(QObject): current_index_changed = Signal(int) clicked = Signal() key_pressed = Signal(QEvent) def __init__(self, parent, base_widget, is_animated=True): QObject.__init__(self, parent) self._base_widget = base_widget # has to be stacked widget self._is_animated = is_animated self._slides_count = self._base_widget.count() self._scroll_area = QScrollArea(parent) self._scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self._scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self._scroll_area.setFrameShape(QFrame.NoFrame) self._scroll_area.mouseReleaseEvent = self._on_mouse_release_event self._scroll_area.keyPressEvent = self._on_key_pressed self._slide_width = None self._current_index = 0 self._is_moving = False self._orig_resize_event = self._base_widget.resizeEvent self._base_widget.resizeEvent = self._resizeEvent self._animation_time = 300 self._animation_steps = 50 def _construct_ribbon(self): self._ribbon = QWidget() self._layout = QHBoxLayout() self._ribbon.setLayout(self._layout) x = 0 for i in range(self._slides_count): self._base_widget.setCurrentIndex(i) widget = self._base_widget.currentWidget() if widget: new_widget = self._grab(widget) self._layout.addWidget(new_widget) x += self._slide_width def _grab(self, widget): new_widget = QLabel() pixmap = widget.grab() new_widget.setPixmap(pixmap) return new_widget def _resizeEvent(self, *args, **kwargs): self._orig_resize_event(*args, **kwargs) if not self._slide_width: self._scroll_area.setGeometry(self._base_widget.geometry()) self._slide_width = self._base_widget.widget(0).width() QTimer.singleShot(50, self._show) def _show(self): self._construct_ribbon() self._scroll_area.setWidget(self._ribbon) self._scroll_area.setAlignment(Qt.AlignCenter) self._scroll_area.show() self._scroll_area.setFocus() def _on_mouse_release_event(self, ev): self.clicked.emit() def _on_key_pressed(self, ev): self.key_pressed.emit(ev) def setAnimated(self, is_animated, animation_time=None, animation_steps=None): self._is_animated = is_animated if animation_time: self._animation_time = animation_time if animation_steps: self._animation_steps = animation_steps def is_moving(self): return self._is_moving def setCurrentIndex(self, new_index): new_index = max(new_index, 0) new_index = min(new_index, self._slides_count - 1) if new_index == self._current_index or self._is_moving: return is_animated = self._is_animated and \ abs(self._current_index - new_index) == 1 self._move(new_index, is_animated) def _move(self, new_index, is_animated): self._is_moving = True source_x = self._current_index * self._slide_width target_x = new_index * self._slide_width if not is_animated: dx = target_x - source_x self._ribbon.scroll(-dx, 0) self._finish_moving(new_index) else: animation_interval = self._animation_time // self._animation_steps dx = (target_x - source_x) // self._animation_steps self._move_animated(source_x, target_x, dx, animation_interval, new_index) def _move_animated(self, source_x, target_x, dx, animation_interval, new_index): if target_x == source_x: self._finish_moving(new_index) return if target_x > source_x: dx = min(dx, target_x - source_x) else: dx = -min(-dx, source_x - target_x) self._ribbon.scroll(-dx, 0) source_x += dx QTimer.singleShot( animation_interval, lambda: self._move_animated( source_x, target_x, dx, animation_interval, new_index)) def _finish_moving(self, new_index): self._current_index = new_index self.current_index_changed.emit(self._current_index) self._is_moving = False def widget(self): return self._scroll_area
class LayersSelectorWidget(QWidget): ''' LayerChoiceWidget class provide widget plugin for picking layers. ''' def __init__(self): super().__init__() filter = QLineEdit() filter.setPlaceholderText("filter") names = [ 'Core Layers', 'Convolution Layers', 'Pooling Layers', 'Recurrent Layers', 'Preprocessing Layers', 'Attention Layers', 'Reshaping Layers', 'Locally-Connected Layers' ] layers = [['Dense', 'Activation', 'Embedding', 'Masking', 'Lambda'], [ 'Conv1D', 'Conv2D', 'Conv3D', 'SeparableConv1D', 'SeparableConv2D', 'DepthwiseConv2D', 'Conv2DTranspose', 'Conv3Dtranspose' ], [ 'MaxPooling1D', 'MaxPooling2D', 'MaxPooling3D', 'AveragePooling1D', 'AveragePooling2D', 'AveragePooling3D', 'GlobalMaxPooling1D', 'GlobalMaxPooling2D', 'GlobalMaxPooling3D', 'GlobalAveragePooling1D', 'GlobalAveragePooling2D', 'GlobalAveragePooling3D' ], [ 'LSTM', 'GRU', 'SimpleRNN', 'TimeDistributed', 'BiDirectional', 'ConvLSTM2D' ], ['TextToVector', 'Normalization'], ['Attention', 'AdditiveAttention'], [ 'Reshape', 'Flatten', 'Cropping1D', 'Cropping2D', 'Cropping3D', 'UpSampling1D', 'UpSampling2D', 'UpSampling3D', 'ZeroPadding1D', 'ZeroPadding2D', 'ZeroPadding3D' ], ['LocallyConnected1D', 'LocallyConnected2D']] self.main_layout = QVBoxLayout() self.main_layout.addWidget(filter) for i in range(len(names)): if i > 1: self.main_layout.addWidget( LayersList(names[i], layers[i], filter, False)) else: self.main_layout.addWidget( LayersList(names[i], layers[i], filter)) self.main_layout.setSpacing(0) self.main_layout.setAlignment(Qt.AlignTop) self.main_layout.setMargin(0) self.main_layout.setSpacing(0) self.main_layout.setContentsMargins(0, 0, 0, 0) self.scroll_area = QScrollArea() names = QWidget() names.setLayout(self.main_layout) self.scroll_area.setWidget(names) self.main_layout = QVBoxLayout() self.main_layout.setAlignment(Qt.AlignTop) self.main_layout.setMargin(0) self.main_layout.setSpacing(0) self.main_layout.setContentsMargins(0, 0, 0, 0) self.scroll_area.setAlignment(Qt.AlignTop) self.scroll_area.setWidgetResizable(True) self.main_layout.addWidget(self.scroll_area) self.setLayout(self.main_layout) del (names) del (layers) self.set_styling() def set_styling(self): self.setStyleSheet(''' background-color:aliceblue; ''')
class Window(QWidget): def __init__(self): super().__init__() self.setWindowTitle('image-viewer') self.setGeometry(200, 200, 800, 600) self.image_path = 'F:\\browser-test\\test-dir\\4.jpg' self.cont_zoomed = None self.create_layout() self.show() def keyPressEvent(self, event): if event.key() == QtCore.Qt.Key_BracketLeft: self.zoom('in') event.accept() elif event.key() == QtCore.Qt.Key_BracketRight: self.zoom('out') event.accept() elif event.key() == QtCore.Qt.Key_Q: self.close() return super().keyPressEvent(event) def zoom(self, dire): if self.cont_zoomed: ratio = self.cont_zoomed else: ratio = self.content if dire == 'in': self.cont_zoomed = self.content.scaled(ratio.width() * 0.75, ratio.height() * 0.75, QtCore.Qt.KeepAspectRatio) elif dire == 'out': self.cont_zoomed = self.content.scaled(ratio.width() * 1.25, ratio.height() * 1.25, QtCore.Qt.KeepAspectRatio) self.image.setPixmap(self.cont_zoomed) def create_layout(self): self.image = QLabel() self.content = QPixmap(self.image_path) # FIXME: reset on resize self.image.setPixmap(self.content) self.label = QLabel() self.label.setText('image name probably') self.image_scroll = QScrollArea() self.image_scroll.setWidget(self.image) self.image_scroll.setAlignment(QtCore.Qt.AlignCenter) vbox = QVBoxLayout() vbox.addWidget(self.image_scroll) vbox.addWidget(self.label) # remove padding & margin vbox.setSpacing(0) vbox.setContentsMargins(0, 0, 0, 0) self.setLayout(vbox) def set_image(self, img): '''Change displayed image with the input from the main window. img -- path to image file ''' self.image_path = img self.content = QPixmap(self.image_path) self.image.setPixmap(self.content) self.label.setText(self.image_path) def resizeEvent(self, event): # increase image width in scroll area to fit into it self.image.setFixedWidth( self.width() - self.image_scroll.verticalScrollBar().width() - 2) return super().resizeEvent(event)
class ResultModuleViewWidget(QMainWindow): # Конструктор def __init__(self, module_name, result, module_success, message, parent=None): super(ResultModuleViewWidget, self).__init__(parent) self.module_name = module_name self.module_success = module_success self.result = result self.message = message self.setWindowTitle(f'Результаты выполнения модуля \'{module_name}\'') self.setWindowModality(Qt.ApplicationModal) self.setMinimumWidth(640) self.central_widget = QWidget() self.scroll = QScrollArea() self.layout = QVBoxLayout(self.central_widget) self.init_ui(result, module_success) # Метод инициализации UI def init_ui(self, result, module_success): self.layout.addWidget(self.scroll) self.layout.setAlignment(Qt.AlignTop) self.setCentralWidget(self.central_widget) widget = QWidget() main_layout = QVBoxLayout(widget) for i in range(0, len(result)): block_widget = QWidget() layout = QVBoxLayout(block_widget) block_name_label = QLabel(result[i][-1]) block_name_label.setAlignment(Qt.AlignCenter) block_name_label.setStyleSheet('font-weight: bold;') layout.addWidget(block_name_label) for j in range(0, len(result[i]) - 1): command_result_label = QLabel( f'Команда №{j + 1}: \'{result[i][j][1].strip()}\'.') command_result_label.setAlignment(Qt.AlignCenter) if result[i][j][0] == 0: command_result_label.setStyleSheet( 'background-color: ForestGreen;') else: command_result_label.setStyleSheet( 'background-color: OrangeRed;') layout.addWidget(command_result_label) main_layout.addWidget(block_widget) module_result_label = QLabel() if module_success == 'True': module_result_label.setText('Модуль выполнился успешно.') module_result_label.setStyleSheet( 'color: ForestGreen; font-weight: bold;') elif module_success == 'False': module_result_label.setText('Модуль завершился неудачно.') module_result_label.setStyleSheet('color: Red; font-weight: bold;') elif module_success == 'Error': module_result_label.setText('В проверочном выражении ошибка.') module_result_label.setStyleSheet( 'color: OrangeRed; font-weight: bold;') module_result_label.setAlignment(Qt.AlignCenter) main_layout.addWidget(module_result_label) button = QPushButton('Сгенерировать отчёт') button.clicked.connect(self.start_report_generation) main_layout.addWidget(button) self.scroll.setAlignment(Qt.AlignCenter) self.scroll.setWidget(widget) # Слот, обрабатывающий запрос пользователя на генерацию отчёта (нажатие соответствующей кнопки) @Slot() def start_report_generation(self): generate_report(self.module_name, self.module_success, self.result, self.message, self)
class MainWindow(QMainWindow): def __init__(self, font=QtGui.QFontMetrics(QtGui.QFont()), screen_size=QtCore.QSize()): super().__init__() self.screen = screen_size self.font_metric = font self.setWindowTitle('OpenMC Plot Explorer') def loadGui(self): self.pixmap = None self.zoom = 100 self.loadModel() # Create viewing area self.frame = QScrollArea(self) cw = QWidget() self.frame.setCornerWidget(cw) self.frame.setAlignment(QtCore.Qt.AlignCenter) self.frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.setCentralWidget(self.frame) # connect pinch gesture (OSX) self.grabGesture(QtCore.Qt.PinchGesture) # Create plot image self.plotIm = PlotImage(self.model, self.frame, self) self.frame.setWidget(self.plotIm) # Dock self.dock = DomainDock(self.model, self.font_metric, self) self.dock.setObjectName("Domain Options Dock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dock) # Tally Dock self.tallyDock = TallyDock(self.model, self.font_metric, self) self.tallyDock.update() self.tallyDock.setObjectName("Tally Options Dock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.tallyDock) # Color DialogtallyDock self.colorDialog = ColorDialog(self.model, self.font_metric, self) self.colorDialog.hide() # Tools self.exportDataDialog = ExportDataDialog(self.model, self.font_metric, self) # Restore Window Settings self.restoreWindowSettings() # Create menubar self.createMenuBar() self.updateEditMenu() # Status Bar self.coord_label = QLabel() self.statusBar().addPermanentWidget(self.coord_label) self.coord_label.hide() # Keyboard overlay self.shortcutOverlay = ShortcutsOverlay(self) self.shortcutOverlay.hide() # Load Plot self.statusBar().showMessage('Generating Plot...') self.dock.updateDock() self.tallyDock.update() self.colorDialog.updateDialogValues() self.statusBar().showMessage('') # Timer allows GUI to render before plot finishes loading QtCore.QTimer.singleShot(0, self.plotIm.generatePixmap) QtCore.QTimer.singleShot(0, self.showCurrentView) def event(self, event): # use pinch event to update zoom if isinstance(event, QGestureEvent): pinch = event.gesture(QtCore.Qt.PinchGesture) self.editZoom(self.zoom * pinch.scaleFactor()) if isinstance(event, QKeyEvent) and hasattr(self, "shortcutOverlay"): self.shortcutOverlay.event(event) return super().event(event) def show(self): super().show() self.plotIm._resize() def toggleShortcuts(self): if self.shortcutOverlay.isVisible(): self.shortcutOverlay.close() else: self.shortcutOverlay.move(0, 0) self.shortcutOverlay.resize(self.width(), self.height()) self.shortcutOverlay.show() # Create and update menus: def createMenuBar(self): self.mainMenu = self.menuBar() # File Menu self.reloadModelAction = QAction("&Reload model...", self) self.reloadModelAction.setShortcut("Ctrl+Shift+R") self.reloadModelAction.setToolTip("Reload current model") self.reloadModelAction.setStatusTip("Reload current model") reload_connector = partial(self.loadModel, reload=True) self.reloadModelAction.triggered.connect(reload_connector) self.saveImageAction = QAction("&Save Image As...", self) self.saveImageAction.setShortcut("Ctrl+Shift+S") self.saveImageAction.setToolTip('Save plot image') self.saveImageAction.setStatusTip('Save plot image') self.saveImageAction.triggered.connect(self.saveImage) self.saveViewAction = QAction("Save &View...", self) self.saveViewAction.setShortcut(QtGui.QKeySequence.Save) self.saveViewAction.setStatusTip('Save current view settings') self.saveViewAction.triggered.connect(self.saveView) self.openAction = QAction("&Open View...", self) self.openAction.setShortcut(QtGui.QKeySequence.Open) self.openAction.setToolTip('Open saved view settings') self.openAction.setStatusTip('Open saved view settings') self.openAction.triggered.connect(self.openView) self.quitAction = QAction("&Quit", self) self.quitAction.setShortcut(QtGui.QKeySequence.Quit) self.quitAction.setToolTip('Quit OpenMC Plot Explorer') self.quitAction.setStatusTip('Quit OpenMC Plot Explorer') self.quitAction.triggered.connect(self.close) self.exportDataAction = QAction('E&xport...', self) self.exportDataAction.setToolTip('Export model and tally data VTK') self.setStatusTip('Export current model and tally data to VTK') self.exportDataAction.triggered.connect(self.exportTallyData) if not _HAVE_VTK: self.exportDataAction.setEnabled(False) self.exportDataAction.setToolTip( "Disabled: VTK Python module is not installed") self.fileMenu = self.mainMenu.addMenu('&File') self.fileMenu.addAction(self.reloadModelAction) self.fileMenu.addAction(self.saveImageAction) self.fileMenu.addAction(self.exportDataAction) self.fileMenu.addSeparator() self.fileMenu.addAction(self.saveViewAction) self.fileMenu.addAction(self.openAction) self.fileMenu.addSeparator() self.fileMenu.addAction(self.quitAction) # Data Menu self.openStatePointAction = QAction("&Open statepoint...", self) self.openStatePointAction.setToolTip('Open statepoint file') self.openStatePointAction.triggered.connect(self.openStatePoint) self.dataMenu = self.mainMenu.addMenu('D&ata') self.dataMenu.addAction(self.openStatePointAction) self.updateDataMenu() # Edit Menu self.applyAction = QAction("&Apply Changes", self) self.applyAction.setShortcut("Ctrl+Return") self.applyAction.setToolTip('Generate new view with changes applied') self.applyAction.setStatusTip('Generate new view with changes applied') self.applyAction.triggered.connect(self.applyChanges) self.undoAction = QAction('&Undo', self) self.undoAction.setShortcut(QtGui.QKeySequence.Undo) self.undoAction.setToolTip('Undo') self.undoAction.setStatusTip('Undo last plot view change') self.undoAction.setDisabled(True) self.undoAction.triggered.connect(self.undo) self.redoAction = QAction('&Redo', self) self.redoAction.setDisabled(True) self.redoAction.setToolTip('Redo') self.redoAction.setStatusTip('Redo last plot view change') self.redoAction.setShortcut(QtGui.QKeySequence.Redo) self.redoAction.triggered.connect(self.redo) self.restoreAction = QAction("&Restore Default Plot", self) self.restoreAction.setShortcut("Ctrl+R") self.restoreAction.setToolTip('Restore to default plot view') self.restoreAction.setStatusTip('Restore to default plot view') self.restoreAction.triggered.connect(self.restoreDefault) self.editMenu = self.mainMenu.addMenu('&Edit') self.editMenu.addAction(self.applyAction) self.editMenu.addSeparator() self.editMenu.addAction(self.undoAction) self.editMenu.addAction(self.redoAction) self.editMenu.addSeparator() self.editMenu.addAction(self.restoreAction) self.editMenu.addSeparator() self.editMenu.aboutToShow.connect(self.updateEditMenu) # Edit -> Basis Menu self.xyAction = QAction('&xy ', self) self.xyAction.setCheckable(True) self.xyAction.setShortcut('Alt+X') self.xyAction.setToolTip('Change to xy basis') self.xyAction.setStatusTip('Change to xy basis') xy_connector = partial(self.editBasis, 'xy', apply=True) self.xyAction.triggered.connect(xy_connector) self.xzAction = QAction('x&z ', self) self.xzAction.setCheckable(True) self.xzAction.setShortcut('Alt+Z') self.xzAction.setToolTip('Change to xz basis') self.xzAction.setStatusTip('Change to xz basis') xz_connector = partial(self.editBasis, 'xz', apply=True) self.xzAction.triggered.connect(xz_connector) self.yzAction = QAction('&yz ', self) self.yzAction.setCheckable(True) self.yzAction.setShortcut('Alt+Y') self.yzAction.setToolTip('Change to yz basis') self.yzAction.setStatusTip('Change to yz basis') yz_connector = partial(self.editBasis, 'yz', apply=True) self.yzAction.triggered.connect(yz_connector) self.basisMenu = self.editMenu.addMenu('&Basis') self.basisMenu.addAction(self.xyAction) self.basisMenu.addAction(self.xzAction) self.basisMenu.addAction(self.yzAction) self.basisMenu.aboutToShow.connect(self.updateBasisMenu) # Edit -> Color By Menu self.cellAction = QAction('&Cell', self) self.cellAction.setCheckable(True) self.cellAction.setShortcut('Alt+C') self.cellAction.setToolTip('Color by cell') self.cellAction.setStatusTip('Color plot by cell') cell_connector = partial(self.editColorBy, 'cell', apply=True) self.cellAction.triggered.connect(cell_connector) self.materialAction = QAction('&Material', self) self.materialAction.setCheckable(True) self.materialAction.setShortcut('Alt+M') self.materialAction.setToolTip('Color by material') self.materialAction.setStatusTip('Color plot by material') material_connector = partial(self.editColorBy, 'material', apply=True) self.materialAction.triggered.connect(material_connector) self.temperatureAction = QAction('&Temperature', self) self.temperatureAction.setCheckable(True) self.temperatureAction.setShortcut('Alt+T') self.temperatureAction.setToolTip('Color by temperature') self.temperatureAction.setStatusTip('Color plot by temperature') temp_connector = partial(self.editColorBy, 'temperature', apply=True) self.temperatureAction.triggered.connect(temp_connector) self.densityAction = QAction('&Density', self) self.densityAction.setCheckable(True) self.densityAction.setShortcut('Alt+D') self.densityAction.setToolTip('Color by density') self.densityAction.setStatusTip('Color plot by density') density_connector = partial(self.editColorBy, 'density', apply=True) self.densityAction.triggered.connect(density_connector) self.colorbyMenu = self.editMenu.addMenu('&Color By') self.colorbyMenu.addAction(self.cellAction) self.colorbyMenu.addAction(self.materialAction) self.colorbyMenu.addAction(self.temperatureAction) self.colorbyMenu.addAction(self.densityAction) self.colorbyMenu.aboutToShow.connect(self.updateColorbyMenu) self.editMenu.addSeparator() # Edit -> Other Options self.maskingAction = QAction('Enable &Masking', self) self.maskingAction.setShortcut('Ctrl+M') self.maskingAction.setCheckable(True) self.maskingAction.setToolTip('Toggle masking') self.maskingAction.setStatusTip('Toggle whether masking is enabled') masking_connector = partial(self.toggleMasking, apply=True) self.maskingAction.toggled.connect(masking_connector) self.editMenu.addAction(self.maskingAction) self.highlightingAct = QAction('Enable High&lighting', self) self.highlightingAct.setShortcut('Ctrl+L') self.highlightingAct.setCheckable(True) self.highlightingAct.setToolTip('Toggle highlighting') self.highlightingAct.setStatusTip('Toggle whether ' 'highlighting is enabled') highlight_connector = partial(self.toggleHighlighting, apply=True) self.highlightingAct.toggled.connect(highlight_connector) self.editMenu.addAction(self.highlightingAct) self.overlapAct = QAction('Enable Overlap Coloring', self) self.overlapAct.setShortcut('Ctrl+P') self.overlapAct.setCheckable(True) self.overlapAct.setToolTip('Toggle overlapping regions') self.overlapAct.setStatusTip('Toggle display of overlapping ' 'regions when enabled') overlap_connector = partial(self.toggleOverlaps, apply=True) self.overlapAct.toggled.connect(overlap_connector) self.editMenu.addAction(self.overlapAct) self.outlineAct = QAction('Enable Domain Outlines', self) self.outlineAct.setShortcut('Ctrl+U') self.outlineAct.setCheckable(True) self.outlineAct.setToolTip('Display Cell/Material Boundaries') self.outlineAct.setStatusTip('Toggle display of domain ' 'outlines when enabled') outline_connector = partial(self.toggleOutlines, apply=True) self.outlineAct.toggled.connect(outline_connector) self.editMenu.addAction(self.outlineAct) # View Menu self.dockAction = QAction('Hide &Dock', self) self.dockAction.setShortcut("Ctrl+D") self.dockAction.setToolTip('Toggle dock visibility') self.dockAction.setStatusTip('Toggle dock visibility') self.dockAction.triggered.connect(self.toggleDockView) self.tallyDockAction = QAction('Tally &Dock', self) self.tallyDockAction.setShortcut("Ctrl+T") self.tallyDockAction.setToolTip('Toggle tally dock visibility') self.tallyDockAction.setStatusTip('Toggle tally dock visibility') self.tallyDockAction.triggered.connect(self.toggleTallyDockView) self.zoomAction = QAction('&Zoom...', self) self.zoomAction.setShortcut('Alt+Shift+Z') self.zoomAction.setToolTip('Edit zoom factor') self.zoomAction.setStatusTip('Edit zoom factor') self.zoomAction.triggered.connect(self.editZoomAct) self.viewMenu = self.mainMenu.addMenu('&View') self.viewMenu.addAction(self.dockAction) self.viewMenu.addAction(self.tallyDockAction) self.viewMenu.addSeparator() self.viewMenu.addAction(self.zoomAction) self.viewMenu.aboutToShow.connect(self.updateViewMenu) # Window Menu self.mainWindowAction = QAction('&Main Window', self) self.mainWindowAction.setCheckable(True) self.mainWindowAction.setToolTip('Bring main window to front') self.mainWindowAction.setStatusTip('Bring main window to front') self.mainWindowAction.triggered.connect(self.showMainWindow) self.colorDialogAction = QAction('Color &Options', self) self.colorDialogAction.setCheckable(True) self.colorDialogAction.setToolTip('Bring Color Dialog to front') self.colorDialogAction.setStatusTip('Bring Color Dialog to front') self.colorDialogAction.triggered.connect(self.showColorDialog) # Keyboard Shortcuts Overlay self.keyboardShortcutsAction = QAction("&Keyboard Shortcuts...", self) self.keyboardShortcutsAction.setShortcut("?") self.keyboardShortcutsAction.setToolTip("Display Keyboard Shortcuts") self.keyboardShortcutsAction.setStatusTip("Display Keyboard Shortcuts") self.keyboardShortcutsAction.triggered.connect(self.toggleShortcuts) self.windowMenu = self.mainMenu.addMenu('&Window') self.windowMenu.addAction(self.mainWindowAction) self.windowMenu.addAction(self.colorDialogAction) self.windowMenu.addAction(self.keyboardShortcutsAction) self.windowMenu.aboutToShow.connect(self.updateWindowMenu) def updateEditMenu(self): changed = self.model.currentView != self.model.defaultView self.restoreAction.setDisabled(not changed) self.maskingAction.setChecked(self.model.currentView.masking) self.highlightingAct.setChecked(self.model.currentView.highlighting) self.outlineAct.setChecked(self.model.currentView.outlines) num_previous_views = len(self.model.previousViews) self.undoAction.setText('&Undo ({})'.format(num_previous_views)) num_subsequent_views = len(self.model.subsequentViews) self.redoAction.setText('&Redo ({})'.format(num_subsequent_views)) def updateBasisMenu(self): self.xyAction.setChecked(self.model.currentView.basis == 'xy') self.xzAction.setChecked(self.model.currentView.basis == 'xz') self.yzAction.setChecked(self.model.currentView.basis == 'yz') def updateColorbyMenu(self): cv = self.model.currentView self.cellAction.setChecked(cv.colorby == 'cell') self.materialAction.setChecked(cv.colorby == 'material') self.temperatureAction.setChecked(cv.colorby == 'temperature') self.densityAction.setChecked(cv.colorby == 'density') def updateViewMenu(self): if self.dock.isVisible(): self.dockAction.setText('Hide &Dock') else: self.dockAction.setText('Show &Dock') def updateWindowMenu(self): self.colorDialogAction.setChecked(self.colorDialog.isActiveWindow()) self.mainWindowAction.setChecked(self.isActiveWindow()) # Menu and shared methods def loadModel(self, reload=False): if reload: self.resetModels() else: # create new plot model self.model = PlotModel() self.restoreModelSettings() # update plot and model settings self.updateRelativeBases() self.cellsModel = DomainTableModel(self.model.activeView.cells) self.materialsModel = DomainTableModel(self.model.activeView.materials) if reload: loader_thread = Thread(target=_openmcReload) loader_thread.start() while loader_thread.is_alive(): self.statusBar().showMessage("Reloading model...") QApplication.processEvents() self.plotIm.model = self.model self.applyChanges() def saveImage(self): filename, ext = QFileDialog.getSaveFileName(self, "Save Plot Image", "untitled", "Images (*.png)") if filename: if "." not in filename: filename += ".png" self.plotIm.figure.savefig(filename, transparent=True) self.statusBar().showMessage('Plot Image Saved', 5000) def saveView(self): filename, ext = QFileDialog.getSaveFileName(self, "Save View Settings", "untitled", "View Settings (*.pltvw)") if filename: if "." not in filename: filename += ".pltvw" saved = { 'version': self.model.version, 'current': self.model.currentView } with open(filename, 'wb') as file: pickle.dump(saved, file) def openView(self): filename, ext = QFileDialog.getOpenFileName(self, "Open View Settings", ".", "*.pltvw") if filename: try: with open(filename, 'rb') as file: saved = pickle.load(file) except Exception: message = 'Error loading plot settings' saved = {'version': None, 'current': None} if saved['version'] == self.model.version: self.model.activeView = saved['current'] self.dock.updateDock() self.colorDialog.updateDialogValues() self.applyChanges() message = '{} settings loaded'.format(filename) else: message = 'Error loading plot settings. Incompatible model.' self.statusBar().showMessage(message, 5000) def openStatePoint(self): # check for an alread-open statepoint if self.model.statepoint: msg_box = QMessageBox() msg_box.setText("Please close the current statepoint file before " "opening a new one.") msg_box.setIcon(QMessageBox.Information) msg_box.setStandardButtons(QMessageBox.Ok) msg_box.exec_() return filename, ext = QFileDialog.getOpenFileName(self, "Open StatePoint", ".", "statepoint*.h5") if filename: try: self.model.openStatePoint(filename) message = 'Opened statepoint file: {}' except (FileNotFoundError, OSError): message = 'Error opening statepoint file: {}' msg_box = QMessageBox() msg = "Could open statepoint file: \n\n {} \n" msg_box.setText(msg.format(filename)) msg_box.setIcon(QMessageBox.Warning) msg_box.setStandardButtons(QMessageBox.Ok) msg_box.exec_() finally: self.statusBar().showMessage(message.format(filename), 5000) self.updateDataMenu() self.tallyDock.update() def closeStatePoint(self): # remove the statepoint object and update the data menu filename = self.model.statepoint.filename self.model.statepoint = None self.model.currentView.selectedTally = None self.model.activeView.selectedTally = None msg = "Closed statepoint file {}".format(filename) self.statusBar().showMessage(msg) self.updateDataMenu() self.tallyDock.selectTally() self.tallyDock.update() self.plotIm.updatePixmap() def updateDataMenu(self): if self.model.statepoint: self.closeStatePointAction = QAction("&Close statepoint", self) self.closeStatePointAction.setToolTip("Close current statepoint") self.closeStatePointAction.triggered.connect(self.closeStatePoint) self.dataMenu.addAction(self.closeStatePointAction) elif hasattr(self, "closeStatePointAction"): self.dataMenu.removeAction(self.closeStatePointAction) def applyChanges(self): if self.model.activeView != self.model.currentView: self.statusBar().showMessage('Generating Plot...') QApplication.processEvents() self.model.storeCurrent() self.model.subsequentViews = [] self.plotIm.generatePixmap() self.resetModels() self.showCurrentView() self.statusBar().showMessage('') else: self.statusBar().showMessage('No changes to apply.', 3000) def undo(self): self.statusBar().showMessage('Generating Plot...') QApplication.processEvents() self.model.undo() self.resetModels() self.showCurrentView() self.dock.updateDock() self.colorDialog.updateDialogValues() if not self.model.previousViews: self.undoAction.setDisabled(True) self.redoAction.setDisabled(False) self.statusBar().showMessage('') def redo(self): self.statusBar().showMessage('Generating Plot...') QApplication.processEvents() self.model.redo() self.resetModels() self.showCurrentView() self.dock.updateDock() self.colorDialog.updateDialogValues() if not self.model.subsequentViews: self.redoAction.setDisabled(True) self.undoAction.setDisabled(False) self.statusBar().showMessage('') def restoreDefault(self): if self.model.currentView != self.model.defaultView: self.statusBar().showMessage('Generating Plot...') QApplication.processEvents() self.model.storeCurrent() self.model.activeView.adopt_plotbase(self.model.defaultView) self.plotIm.generatePixmap() self.resetModels() self.showCurrentView() self.dock.updateDock() self.colorDialog.updateDialogValues() self.model.subsequentViews = [] self.statusBar().showMessage('') def editBasis(self, basis, apply=False): self.model.activeView.basis = basis self.dock.updateBasis() if apply: self.applyChanges() def editColorBy(self, domain_kind, apply=False): self.model.activeView.colorby = domain_kind self.dock.updateColorBy() self.colorDialog.updateColorBy() if apply: self.applyChanges() def toggleOverlaps(self, state, apply=False): self.model.activeView.color_overlaps = bool(state) self.colorDialog.updateOverlap() if apply: self.applyChanges() def editColorMap(self, colormap_name, property_type, apply=False): self.model.activeView.colormaps[property_type] = colormap_name self.plotIm.updateColorMap(colormap_name, property_type) self.colorDialog.updateColorMaps() if apply: self.applyChanges() def editColorbarMin(self, min_val, property_type, apply=False): av = self.model.activeView current = av.user_minmax[property_type] av.user_minmax[property_type] = (min_val, current[1]) self.colorDialog.updateColorMinMax() self.plotIm.updateColorMinMax(property_type) if apply: self.applyChanges() def editColorbarMax(self, max_val, property_type, apply=False): av = self.model.activeView current = av.user_minmax[property_type] av.user_minmax[property_type] = (current[0], max_val) self.colorDialog.updateColorMinMax() self.plotIm.updateColorMinMax(property_type) if apply: self.applyChanges() def toggleColorbarScale(self, state, property, apply=False): av = self.model.activeView av.color_scale_log[property] = bool(state) # temporary, should be resolved diferently in the future cv = self.model.currentView cv.color_scale_log[property] = bool(state) self.plotIm.updateColorbarScale() if apply: self.applyChanges() def toggleUserMinMax(self, state, property): av = self.model.activeView av.use_custom_minmax[property] = bool(state) if av.user_minmax[property] == (0.0, 0.0): av.user_minmax[property] = copy.copy(av.data_minmax[property]) self.plotIm.updateColorMinMax('temperature') self.plotIm.updateColorMinMax('density') self.colorDialog.updateColorMinMax() def toggleDataIndicatorCheckBox(self, state, property, apply=False): av = self.model.activeView av.data_indicator_enabled[property] = bool(state) cv = self.model.currentView cv.data_indicator_enabled[property] = bool(state) self.plotIm.updateDataIndicatorVisibility() if apply: self.applyChanges() def toggleMasking(self, state, apply=False): self.model.activeView.masking = bool(state) self.colorDialog.updateMasking() if apply: self.applyChanges() def toggleHighlighting(self, state, apply=False): self.model.activeView.highlighting = bool(state) self.colorDialog.updateHighlighting() if apply: self.applyChanges() def toggleDockView(self): if self.dock.isVisible(): self.dock.hide() if not self.isMaximized() and not self.dock.isFloating(): self.resize(self.width() - self.dock.width(), self.height()) else: self.dock.setVisible(True) if not self.isMaximized() and not self.dock.isFloating(): self.resize(self.width() + self.dock.width(), self.height()) self.resizePixmap() self.showMainWindow() def toggleTallyDockView(self): if self.tallyDock.isVisible(): self.tallyDock.hide() if not self.isMaximized() and not self.tallyDock.isFloating(): self.resize(self.width() - self.tallyDock.width(), self.height()) else: self.tallyDock.setVisible(True) if not self.isMaximized() and not self.tallyDock.isFloating(): self.resize(self.width() + self.tallyDock.width(), self.height()) self.resizePixmap() self.showMainWindow() def editZoomAct(self): percent, ok = QInputDialog.getInt(self, "Edit Zoom", "Zoom Percent:", self.dock.zoomBox.value(), 25, 2000) if ok: self.dock.zoomBox.setValue(percent) def editZoom(self, value): self.zoom = value self.resizePixmap() self.dock.zoomBox.setValue(value) def showMainWindow(self): self.raise_() self.activateWindow() def showColorDialog(self): self.colorDialog.show() self.colorDialog.raise_() self.colorDialog.activateWindow() def showExportDialog(self): self.exportDataDialog.show() self.exportDataDialog.raise_() self.exportDataDialog.activateWindow() # Dock methods: def editSingleOrigin(self, value, dimension): self.model.activeView.origin[dimension] = value def editPlotAlpha(self, value): self.model.activeView.domainAlpha = value def editPlotVisibility(self, value): self.model.activeView.domainVisible = bool(value) def toggleOutlines(self, value, apply=False): self.model.activeView.outlines = bool(value) self.dock.updateOutlines() if apply: self.applyChanges() def editWidth(self, value): self.model.activeView.width = value self.onRatioChange() self.dock.updateWidth() def editHeight(self, value): self.model.activeView.height = value self.onRatioChange() self.dock.updateHeight() def toggleAspectLock(self, state): self.model.activeView.aspectLock = bool(state) self.onRatioChange() self.dock.updateAspectLock() def editVRes(self, value): self.model.activeView.v_res = value self.dock.updateVRes() def editHRes(self, value): self.model.activeView.h_res = value self.onRatioChange() self.dock.updateHRes() # Color dialog methods: def editMaskingColor(self): current_color = self.model.activeView.maskBackground dlg = QColorDialog(self) dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color)) if dlg.exec_(): new_color = dlg.currentColor().getRgb()[:3] self.model.activeView.maskBackground = new_color self.colorDialog.updateMaskingColor() def editHighlightColor(self): current_color = self.model.activeView.highlightBackground dlg = QColorDialog(self) dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color)) if dlg.exec_(): new_color = dlg.currentColor().getRgb()[:3] self.model.activeView.highlightBackground = new_color self.colorDialog.updateHighlightColor() def editAlpha(self, value): self.model.activeView.highlightAlpha = value def editSeed(self, value): self.model.activeView.highlightSeed = value def editOverlapColor(self, apply=False): current_color = self.model.activeView.overlap_color dlg = QColorDialog(self) dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color)) if dlg.exec_(): new_color = dlg.currentColor().getRgb()[:3] self.model.activeView.overlap_color = new_color self.colorDialog.updateOverlapColor() if apply: self.applyChanges() def editBackgroundColor(self, apply=False): current_color = self.model.activeView.domainBackground dlg = QColorDialog(self) dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color)) if dlg.exec_(): new_color = dlg.currentColor().getRgb()[:3] self.model.activeView.domainBackground = new_color self.colorDialog.updateBackgroundColor() if apply: self.applyChanges() def resetColors(self): self.model.resetColors() self.colorDialog.updateDialogValues() self.applyChanges() # Tally dock methods def editSelectedTally(self, event): av = self.model.activeView if event is None or event == "None" or event == "": av.selectedTally = None else: av.selectedTally = int(event.split()[1]) self.tallyDock.selectTally(event) def editTallyValue(self, event): av = self.model.activeView av.tallyValue = event def updateScores(self, state): self.tallyDock.updateScores() def updateNuclides(self, state): self.tallyDock.updateNuclides() def toggleTallyVisibility(self, state, apply=False): av = self.model.activeView av.tallyDataVisible = bool(state) if apply: self.applyChanges() def toggleTallyLogScale(self, state, apply=False): av = self.model.activeView av.tallyDataLogScale = bool(state) if apply: self.applyChanges() def toggleTallyMaskZero(self, state): av = self.model.activeView av.tallyMaskZeroValues = bool(state) def editTallyAlpha(self, value, apply=False): av = self.model.activeView av.tallyDataAlpha = value if apply: self.applyChanges() def toggleTallyContours(self, state): av = self.model.activeView av.tallyContours = bool(state) def editTallyContourLevels(self, value): av = self.model.activeView av.tallyContourLevels = value def toggleTallyDataIndicator(self, state, apply=False): av = self.model.activeView av.tallyDataIndicator = bool(state) if apply: self.applyChanges() def toggleTallyDataClip(self, state): av = self.model.activeView av.clipTallyData = bool(state) def toggleTallyDataUserMinMax(self, state, apply=False): av = self.model.activeView av.tallyDataUserMinMax = bool(state) self.tallyDock.tallyColorForm.setMinMaxEnabled(bool(state)) if apply: self.applyChanges() def editTallyDataMin(self, value, apply=False): av = self.model.activeView av.tallyDataMin = value if apply: self.applyChanges() def editTallyDataMax(self, value, apply=False): av = self.model.activeView av.tallyDataMax = value if apply: self.applyChanges() def editTallyDataColormap(self, cmap, apply=False): av = self.model.activeView av.tallyDataColormap = cmap if apply: self.applyChanges() def updateTallyMinMax(self): self.tallyDock.updateMinMax() # Plot image methods def editPlotOrigin(self, xOr, yOr, zOr=None, apply=False): if zOr is not None: self.model.activeView.origin = [xOr, yOr, zOr] else: origin = [None, None, None] origin[self.xBasis] = xOr origin[self.yBasis] = yOr origin[self.zBasis] = self.model.activeView.origin[self.zBasis] self.model.activeView.origin = origin self.dock.updateOrigin() if apply: self.applyChanges() def revertDockControls(self): self.dock.revertToCurrent() def editDomainColor(self, kind, id): if kind == 'Cell': domain = self.model.activeView.cells else: domain = self.model.activeView.materials current_color = domain[id].color dlg = QColorDialog(self) if isinstance(current_color, tuple): dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color)) elif isinstance(current_color, str): current_color = openmc.plots._SVG_COLORS[current_color] dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color)) if dlg.exec_(): new_color = dlg.currentColor().getRgb()[:3] domain[id].color = new_color self.applyChanges() def toggleDomainMask(self, state, kind, id): if kind == 'Cell': domain = self.model.activeView.cells else: domain = self.model.activeView.materials domain[id].masked = bool(state) self.applyChanges() def toggleDomainHighlight(self, state, kind, id): if kind == 'Cell': domain = self.model.activeView.cells else: domain = self.model.activeView.materials domain[id].highlight = bool(state) self.applyChanges() # Helper methods: def restoreWindowSettings(self): settings = QtCore.QSettings() self.resize(settings.value("mainWindow/Size", QtCore.QSize(800, 600))) self.move( settings.value("mainWindow/Position", QtCore.QPoint(100, 100))) self.restoreState(settings.value("mainWindow/State")) self.colorDialog.resize( settings.value("colorDialog/Size", QtCore.QSize(400, 500))) self.colorDialog.move( settings.value("colorDialog/Position", QtCore.QPoint(600, 200))) is_visible = settings.value("colorDialog/Visible", 0) # some versions of PySide will return None rather than the default value if is_visible is None: is_visible = False else: is_visible = bool(int(is_visible)) self.colorDialog.setVisible(is_visible) def restoreModelSettings(self): if os.path.isfile("plot_settings.pkl"): with open('plot_settings.pkl', 'rb') as file: model = pickle.load(file) # do not replace model if the version is out of date if model.version != self.model.version: print("WARNING: previous plot settings are for a different " "version of the GUI. They will be ignored.") wrn_msg = "Existing version: {}, Current GUI version: {}" print(wrn_msg.format(model.version, self.model.version)) return try: self.model.statepoint = model.statepoint except OSError: msg_box = QMessageBox() msg = "Could open statepoint file: \n\n {} \n" msg_box.setText(msg.format(self.model.statepoint.filename)) msg_box.setIcon(QMessageBox.Warning) msg_box.setStandardButtons(QMessageBox.Ok) msg_box.exec_() self.model.statepoint = None self.model.currentView = model.currentView self.model.activeView = copy.deepcopy(model.currentView) self.model.previousViews = model.previousViews self.model.subsequentViews = model.subsequentViews def resetModels(self): self.cellsModel = DomainTableModel(self.model.activeView.cells) self.materialsModel = DomainTableModel(self.model.activeView.materials) self.cellsModel.beginResetModel() self.cellsModel.endResetModel() self.materialsModel.beginResetModel() self.materialsModel.endResetModel() self.colorDialog.updateDomainTabs() def showCurrentView(self): self.updateScale() self.updateRelativeBases() self.plotIm.updatePixmap() if self.model.previousViews: self.undoAction.setDisabled(False) if self.model.subsequentViews: self.redoAction.setDisabled(False) else: self.redoAction.setDisabled(True) self.adjustWindow() def updateScale(self): cv = self.model.currentView self.scale = (cv.h_res / cv.width, cv.v_res / cv.height) def updateRelativeBases(self): cv = self.model.currentView self.xBasis = 0 if cv.basis[0] == 'x' else 1 self.yBasis = 1 if cv.basis[1] == 'y' else 2 self.zBasis = 3 - (self.xBasis + self.yBasis) def adjustWindow(self): self.setMaximumSize(self.screen.width(), self.screen.height()) def onRatioChange(self): av = self.model.activeView if av.aspectLock: ratio = av.width / max(av.height, .001) av.v_res = int(av.h_res / ratio) self.dock.updateVRes() def showCoords(self, xPlotPos, yPlotPos): cv = self.model.currentView if cv.basis == 'xy': coords = ("({}, {}, {})".format(round(xPlotPos, 2), round(yPlotPos, 2), round(cv.origin[2], 2))) elif cv.basis == 'xz': coords = ("({}, {}, {})".format(round(xPlotPos, 2), round(cv.origin[1], 2), round(yPlotPos, 2))) else: coords = ("({}, {}, {})".format(round(cv.origin[0], 2), round(xPlotPos, 2), round(yPlotPos, 2))) self.coord_label.setText('{}'.format(coords)) def resizePixmap(self): self.plotIm._resize() self.plotIm.adjustSize() def moveEvent(self, event): self.adjustWindow() def resizeEvent(self, event): self.plotIm._resize() self.adjustWindow() self.updateScale() if self.shortcutOverlay.isVisible(): self.shortcutOverlay.resize(self.width(), self.height()) def closeEvent(self, event): settings = QtCore.QSettings() settings.setValue("mainWindow/Size", self.size()) settings.setValue("mainWindow/Position", self.pos()) settings.setValue("mainWindow/State", self.saveState()) settings.setValue("colorDialog/Size", self.colorDialog.size()) settings.setValue("colorDialog/Position", self.colorDialog.pos()) visible = int(self.colorDialog.isVisible()) settings.setValue("colorDialog/Visible", visible) openmc.lib.finalize() self.saveSettings() def saveSettings(self): if len(self.model.previousViews) > 10: self.model.previousViews = self.model.previousViews[-10:] if len(self.model.subsequentViews) > 10: self.model.subsequentViews = self.model.subsequentViews[-10:] with open('plot_settings.pkl', 'wb') as file: if self.model.statepoint: self.model.statepoint.close() pickle.dump(self.model, file) def exportTallyData(self): # show export tool dialog self.showExportDialog()
class MainWindow(QMainWindow): # Конструктор def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setWindowTitle('ВКР') self.setMinimumSize(800, 600) self.central_widget = QWidget(self) self.layout = QVBoxLayout(self.central_widget) self.modules_cb = QComboBox() self.modules_cb.currentIndexChanged.connect(self.set_module) self.buttons_widget = QWidget() self.scroll = QScrollArea() self.modules = [] self.init_ui() # Метод инициализации UI def init_ui(self): file_menu = self.menuBar().addMenu('Файл') help_menu = self.menuBar().addMenu('Помощь') create_module_action = file_menu.addAction('Создать новый модуль') create_module_action.triggered.connect(self.create_module) add_module_action = file_menu.addAction('Добавить существующий модуль') add_module_action.triggered.connect(self.add_module) close_action = file_menu.addAction('Закрыть программу') close_action.triggered.connect(self.close_program) about_action = help_menu.addAction('О программе') about_action.triggered.connect(self.show_about) system_name = QLabel( f'Операционная система: {QSysInfo.prettyProductName()}', self.central_widget) system_name.setMaximumHeight(self.central_widget.height() * 0.7) system_name.setAlignment(Qt.AlignRight) self.layout.addWidget(system_name) self.layout.addWidget(self.modules_cb) bw_layout = QHBoxLayout(self.buttons_widget) edit_button = QPushButton('Редактировать модуль') edit_button.clicked.connect(self.edit_module) bw_layout.addWidget(edit_button) delete_button = QPushButton('Удалить модуль') delete_button.clicked.connect(self.delete_module) bw_layout.addWidget(delete_button) self.layout.addWidget(self.buttons_widget) self.layout.addWidget(self.scroll) self.setCentralWidget(self.central_widget) self.load_modules() if self.scroll.widget() is None: self.modules_cb.setVisible(False) self.buttons_widget.setVisible(False) self.scroll.setAlignment(Qt.AlignCenter) # Слот, обрабатывающий запрос пользователя на создание нового модуля (нажатие соответствующей кнопки) @Slot() def create_module(self): cmw = CreateModuleWidget(self) cmw.module_created.connect(self.add_created_module) cmw.show() @Slot(str) def add_created_module(self, module_full_name): if module_full_name != '': idx = module_full_name.rfind('/') if idx != -1: module_short_name = module_full_name[idx + 1:] self.check_module(module_full_name, module_short_name) # Слот, обрабатывающий событие изменения модуля @Slot(int) def update_edited_module(self, idx): self.show_module(self.modules[idx]) # Слот, обрабатывающий запрос пользователя на изменение модуля (нажатие соответствующей кнопки) @Slot() def edit_module(self): password, ok = QInputDialog().getText( self, 'Ввод пароля', 'Введите пароль для редактирования модуля:', QLineEdit.Password) if ok: module = self.modules[self.modules_cb.currentIndex()] try: with open(module['full_name'], 'rb') as module_file: crypto_type = module_file.read(3) password_hash = module_file.read(md5().digest_size) if password_hash != md5(password.encode('utf-8')).digest(): raise RuntimeError('Введён неправильный пароль.') if crypto_type == b'aes': content = aes_decrypt(module_file.read()) elif crypto_type == b'xor': content = xor_str(module_file.read()) else: raise RuntimeError( 'Неизвестный тип шифрования файла модуля.') emw = EditModuleWidget(module, crypto_type, password_hash, content, self.modules_cb.currentIndex(), self) emw.edited.connect(self.update_edited_module) emw.show() except IOError: mb = QMessageBox(self) mb.setWindowTitle('Ошибка') mb.setText('При открытии файла модуля возникла ошибка.') mb.show() except (SyntaxError, RuntimeError) as error: mb = QMessageBox(self) mb.setWindowTitle('Ошибка') mb.setText(str(error)) mb.show() # Слот, обрабатывающий запрос пользователя на удаление модуля (нажатие соответствующей кнопки) @Slot() def delete_module(self): try: with open(argv[0].replace('main.py', 'data'), 'rb') as file: data = file.read() data_list = data.decode('utf-8').split('\n')[:-1] for i in range(0, len(data_list)): if data_list[i].find(self.modules[ self.modules_cb.currentIndex()]['full_name']) > -1: data_list[i] = ''.encode('utf-8') else: data_list[i] = (data_list[i] + '\n').encode('utf-8') with open(argv[0].replace('main.py', 'data'), 'wb') as file: file.writelines(data_list) except IOError: mb = QMessageBox(self) mb.setWindowTitle('Ошибка') mb.setText('Не удалось удалить данные о модуле.') mb.show() del self.modules[self.modules_cb.currentIndex()] self.modules_cb.removeItem(self.modules_cb.currentIndex()) # Слот, обрабатывающий изменение выбранного модуля @Slot(int) def set_module(self, index): if index > -1: self.show_module(self.modules[index]) else: self.scroll.widget().setParent(None) self.modules_cb.setVisible(False) self.buttons_widget.setVisible(False) # Слот, обрабатывающий запрос пользователя на показ информации о программе (нажатие соответствующей кнопки) @Slot() def show_about(self): mb = QMessageBox(self) mb.setWindowTitle('О программе') mb.setText( 'Данная программа предназначена для создания, редактирования и выполнения модулей, ' + 'взаимодействующих с операционной системой.') mb.show() # Слот, обрабатывающий запрос пользователя на закрытие программы (выбора соответствующего пункта меню) @Slot() def close_program(self): self.close() # Слот, обрабатывающий запрос пользователя на добавление существующего модуля (выбора соответствующего пункта меню) @Slot() def add_module(self): module_full_name = QFileDialog.getOpenFileName(self, 'Выберите модуль', QDir.homePath(), '*.module')[0] if module_full_name != '': idx = module_full_name.rfind('/') if idx != -1: module_short_name = module_full_name[idx + 1:] self.check_module(module_full_name, module_short_name) # Метод для проверки модуля на корректность перед добавлением def check_module(self, module_full_name, module_short_name): if len(self.modules) == 0: self.modules.append({ 'full_name': module_full_name, 'short_name': module_short_name }) self.modules_cb.setVisible(True) self.buttons_widget.setVisible(True) self.modules_cb.addItem(module_short_name) mb = QMessageBox(self) mb.setWindowTitle('Успешно') mb.setText('Модуль успешно добавлен.') mb.show() self.save_module_data(module_full_name, module_short_name) else: for m in self.modules: if m['full_name'] == module_full_name: mb = QMessageBox(self) mb.setWindowTitle('Ошибка') mb.setText(f"Модуль '{module_short_name}' уже добавлен.") mb.show() return self.modules.append({ 'full_name': module_full_name, 'short_name': module_short_name }) self.modules_cb.addItem(module_short_name) mb = QMessageBox(self) mb.setWindowTitle('Успешно') mb.setText('Модуль успешно добавлен.') mb.show() self.save_module_data(module_full_name, module_short_name) # Метод сохранения данных о добавленных модулях def save_module_data(self, module_full_name, module_short_name): try: with open(argv[0].replace('main.py', 'data'), 'ab') as file: file.write((module_full_name + '|').encode('utf-8')) file.write((module_short_name + '\n').encode('utf-8')) except IOError: mb = QMessageBox(self) mb.setWindowTitle('Ошибка') mb.setText('Не удалось сохранить информацию о добавленном модуле.') mb.show() # Метод отображения модуля def show_module(self, module): try: with open(module['full_name'], 'rb') as module_file: crypto_type = module_file.read(3) password_hash = module_file.read(md5().digest_size) if crypto_type == b'aes': content = aes_decrypt(module_file.read()) elif crypto_type == b'xor': content = xor_str(module_file.read()) else: raise RuntimeError( 'Неизвестный тип шифрования файла модуля.') parsed_data = parse(content) parsed_data['module_name'] = module['short_name'] w = self.scroll.widget() if w is not None: w.setParent(None) mc = ModuleContentWidget(parsed_data, self.scroll) self.scroll.setWidget(mc) except IOError: mb = QMessageBox(self) mb.setWindowTitle('Ошибка') mb.setText('При открытии файла модуля возникла ошибка.') mb.show() except (SyntaxError, RuntimeError) as error: mb = QMessageBox(self) mb.setWindowTitle('Ошибка') mb.setText(str(error)) mb.show() # Метод загрузки данных о добавленных ранее модулях def load_modules(self): try: with open(argv[0].replace('main.py', 'data'), 'rb') as file: data = file.read() str_data_list = data.decode('utf-8').split('\n')[:-1] for m in str_data_list: self.modules.append({ 'full_name': m.split('|')[0], 'short_name': m.split('|')[1] }) self.modules_cb.addItem(self.modules[-1]['short_name']) except IOError: mb = QMessageBox(self) mb.setWindowTitle('Ошибка') mb.setText( 'Не удалось получить информацию о добавленных ранее модулях.') mb.show()