class App(QMainWindow): def __init__(self, parent=None): super(App, self).__init__(parent) self.title = "DndTool" self.width, self.height = 1280, 720 self.x, self.y = 100, 100 self.mdi = QMdiArea() self.menu = self.menuBar() self.status = self.statusBar() windows_menu = self.menu.addMenu('Windows') windows_menu.addAction("Players") windows_menu.addAction("Debug") windows_menu.triggered.connect(self.open_windows) self.setWindowTitle(self.title) self.setGeometry(self.x, self.y, self.width, self.height) self.setCentralWidget(self.mdi) self.show() def open_windows(self, action): if action.text() == "Players": sub = PlayersSubWindow() self.mdi.addSubWindow(sub) sub.show() elif action.text() == "Debug": print( [window.windowTitle() for window in self.mdi.subWindowList()])
class SubWin(QMainWindow): count = 0 def __init__(self): super().__init__() self.initUI() def initUI(self): self.mdi = QMdiArea() self.setCentralWidget(self.mdi) self.toolBar = QToolBar() self.addToolBar(self.toolBar) self.toolBar.addAction("新建") self.toolBar.addAction("级联") self.toolBar.addAction("平铺") self.toolBar.addAction("关闭全部") self.toolBar.addAction("关闭活动窗口") self.toolBar.addAction("测试") self.toolBar.actionTriggered[QAction].connect(self.windowaction) bar = self.menuBar() file = bar.addMenu("File") # 添加子菜单 file.addAction("新建") file.addAction("级联") file.addAction("平铺") file.triggered[QAction].connect(self.windowaction) self.setWindowTitle("MDI Demo") #self.showFullScreen() #全屏显示 self.showMaximized() #窗口最大化 #self.showNormal() #正常显示 # self.setGeometry(QDesktopWidget().screenGeometry()) def windowaction(self, q): type = q.text() print("Triggered : %s" % type) if type == "新建": # 子窗口增加一个 self.count = self.count + 1 # 实例化多文档界面对象 sub = QMdiSubWindow() # 向sub内部添加控件 sub.setWidget(QTextEdit()) sub.setWindowTitle("subWindow %d" % self.count) self.mdi.addSubWindow(sub) sub.show() #sub.hide() elif type == "级联": self.mdi.cascadeSubWindows() elif type == "平铺": self.mdi.tileSubWindows() elif type == "关闭全部": self.mdi.closeAllSubWindows() elif type == "关闭活动窗口": self.mdi.closeActiveSubWindow() elif type == "测试": lst = self.mdi.subWindowList() print(lst) def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft())
def tile_subwindows(mdi: QtWidgets.QMdiArea, except_type: Type = type(None)): """Tile all subwindows of an MDI area, except for objects of 'except_type'.""" # Hide windows to keep them from being tiled: windows_hidden = list() # type: List[QtWidgets.QMdiSubWindow] for window in mdi.subWindowList(): if type(window) == except_type: windows_hidden.append(window) window.hide() mdi.tileSubWindows() # Show hidden windows again: for window in windows_hidden: window.show() # Move all tiled windows above the excluded ones: for window in mdi.subWindowList(): if window not in windows_hidden: mdi.setActiveSubWindow(window)
def close_subwindows(mdi: QtWidgets.QMdiArea, except_type: Type = type(None)): """Close all subwindows of an MDI area, except for objects of 'except_type'.""" result_button = QtWidgets.QMessageBox.question( mdi, "Close ALL plot windows?", "Really close ALL plot windows?", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.Yes) if result_button != QtWidgets.QMessageBox.Yes: return for subwindow in mdi.subWindowList(): if type(subwindow) is not except_type: subwindow.close()
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.mdi = QMdiArea() self.setCentralWidget(self.mdi) fileNewAction = self.createAction("&New", self.fileNew, QKeySequence.New, "filenew", "Create a text file") fileOpenAction = self.createAction("&Open...", self.fileOpen, QKeySequence.Open, "fileopen", "Open an existing text file") fileSaveAction = self.createAction("&Save", self.fileSave, QKeySequence.Save, "filesave", "Save the text") fileSaveAsAction = self.createAction( "Save &As...", self.fileSaveAs, icon="filesaveas", tip="Save the text using a new filename") fileSaveAllAction = self.createAction("Save A&ll", self.fileSaveAll, "filesave", tip="Save all the files") fileQuitAction = self.createAction("&Quit", self.close, "Ctrl+Q", "filequit", "Close the application") editCopyAction = self.createAction("&Copy", self.editCopy, QKeySequence.Copy, "editcopy", "Copy text to the clipboard") editCutAction = self.createAction("Cu&t", self.editCut, QKeySequence.Cut, "editcut", "Cut text to the clipboard") editPasteAction = self.createAction("&Paste", self.editPaste, QKeySequence.Paste, "editpaste", "Paste in the clipboard's text") self.windowNextAction = self.createAction( "&Next", self.mdi.activateNextSubWindow, QKeySequence.NextChild) self.windowPrevAction = self.createAction( "&Previous", self.mdi.activatePreviousSubWindow, QKeySequence.PreviousChild) self.windowCascadeAction = self.createAction( "Casca&de", self.mdi.cascadeSubWindows) self.windowTileAction = self.createAction("&Tile", self.mdi.tileSubWindows) self.windowRestoreAction = self.createAction("&Restore All", self.windowRestoreAll) self.windowMinimizeAction = self.createAction("&Iconize All", self.windowMinimizeAll) #self.windowArrangeIconsAction = self.createAction( # "&Arrange Icons", self.mdi.arrangeIcons) self.windowArrangeIconsAction = self.createAction( "&Arrange Icons", self.windowMinimizeAll) self.windowCloseAction = self.createAction( "&Close", self.mdi.closeActiveSubWindow, QKeySequence.Close) self.windowMapper = QSignalMapper(self) self.windowMapper.mapped[QWidget].connect(self.mdi.setActiveSubWindow) fileMenu = self.menuBar().addMenu("&File") self.addActions( fileMenu, (fileNewAction, fileOpenAction, fileSaveAction, fileSaveAsAction, fileSaveAllAction, None, fileQuitAction)) editMenu = self.menuBar().addMenu("&Edit") self.addActions(editMenu, (editCopyAction, editCutAction, editPasteAction)) self.windowMenu = self.menuBar().addMenu("&Window") self.windowMenu.aboutToShow.connect(self.updateWindowMenu) fileToolbar = self.addToolBar("File") fileToolbar.setObjectName("FileToolbar") self.addActions(fileToolbar, (fileNewAction, fileOpenAction, fileSaveAction)) editToolbar = self.addToolBar("Edit") editToolbar.setObjectName("EditToolbar") self.addActions(editToolbar, (editCopyAction, editCutAction, editPasteAction)) settings = QSettings() if settings.value("MainWindow/Geometry") or settings.value( "MainWindow/State"): self.restoreGeometry( QByteArray(settings.value("MainWindow/Geometry"))) self.restoreState(QByteArray(settings.value("MainWindow/State"))) status = self.statusBar() status.setSizeGripEnabled(False) status.showMessage("Ready", 5000) self.updateWindowMenu() self.setWindowTitle("Text Editor") QTimer.singleShot(0, self.loadFiles) def createAction(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/{0}.png".format(icon))) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: action.triggered.connect(slot) if checkable: action.setCheckable(True) return action def addActions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def closeEvent(self, event): failures = [] for textEdit in self.mdi.subWindowList(): textEdit = textEdit.widget() if textEdit.isModified(): try: textEdit.save() except IOError as e: failures.append(str(e)) if (failures and QMessageBox.warning( self, "Text Editor -- Save Error", "Failed to save{0}\nQuit anyway?".format( "\n\t".join(failures)), QMessageBox.Yes | QMessageBox.No) == QMessageBox.No): event.ignore() return settings = QSettings() settings.setValue("MainWindow/Geometry", self.saveGeometry()) settings.setValue("MainWindow/State", self.saveState()) files = [] for textEdit in self.mdi.subWindowList(): textEdit = textEdit.widget() if not textEdit.filename.startswith("Unnamed"): files.append(textEdit.filename) settings.setValue("CurrentFiles", files) self.mdi.closeAllSubWindows() def loadFiles(self): if len(sys.argv) > 1: for filename in sys.argv[1:31]: # Load at most 30 files filename = filename if QFileInfo(filename).isFile(): self.loadFile(filename) QApplication.processEvents() else: settings = QSettings() #files = settings.value("CurrentFiles").toStringList() if settings.value("CurrentFiles"): files = settings.value("CurrentFiles") for filename in files: filename = filename if QFile.exists(filename): self.loadFile(filename) QApplication.processEvents() def fileNew(self): textEdit = textedit.TextEdit() self.mdi.addSubWindow(textEdit) textEdit.show() def fileOpen(self): filename, filetype = QFileDialog.getOpenFileName( self, "Text Editor -- Open File") if filename: for textEdit_MSW in self.mdi.subWindowList(): textEdit = textEdit_MSW.widget() if textEdit.filename == filename: self.mdi.setActiveSubWindow(textEdit_MSW) break else: self.loadFile(filename) def loadFile(self, filename): textEdit = textedit.TextEdit(filename) try: textEdit.load() except EnvironmentError as e: QMessageBox.warning(self, "Text Editor -- Load Error", "Failed to load {0}: {1}".format(filename, e)) textEdit.close() del textEdit else: self.mdi.addSubWindow(textEdit) textEdit.show() def fileSave(self): textEdit = self.mdi.activeSubWindow() textEdit = textEdit.widget() if textEdit is None or not isinstance(textEdit, QTextEdit): return True try: textEdit.save() return True except EnvironmentError as e: QMessageBox.warning( self, "Text Editor -- Save Error", "Failed to save {0}: {1}".format(textEdit.filename, e)) return False def fileSaveAs(self): textEdit = self.mdi.activeSubWindow() textEdit = textEdit.widget() if textEdit is None or not isinstance(textEdit, QTextEdit): return filename, filetype = QFileDialog.getSaveFileName( self, "Text Editor -- Save File As", textEdit.filename, "Text files (*.txt *.*)") if filename: textEdit.filename = filename return self.fileSave() return True def fileSaveAll(self): errors = [] for textEdit in self.mdi.subWindowList(): textEdit = textEdit.widget() if textEdit.isModified(): try: textEdit.save() except EnvironmentError as e: errors.append("{0}: {1}".format(textEdit.filename, e)) if errors: QMessageBox.warning( self, "Text Editor -- Save All Error", "Failed to save\n{0}".format("\n".join(errors))) def editCopy(self): textEdit = self.mdi.activeSubWindow() textEdit = textEdit.widget() if textEdit is None or not isinstance(textEdit, QTextEdit): return cursor = textEdit.textCursor() text = cursor.selectedText() if text: clipboard = QApplication.clipboard() clipboard.setText(text) def editCut(self): textEdit = self.mdi.activeSubWindow() textEdit = textEdit.widget() if textEdit is None or not isinstance(textEdit, QTextEdit): return cursor = textEdit.textCursor() text = cursor.selectedText() if text: cursor.removeSelectedText() clipboard = QApplication.clipboard() clipboard.setText(text) def editPaste(self): textEdit = self.mdi.activeSubWindow() textEdit = textEdit.widget() if textEdit is None or not isinstance(textEdit, QTextEdit): return clipboard = QApplication.clipboard() textEdit.insertPlainText(clipboard.text()) def windowRestoreAll(self): for textEdit in self.mdi.subWindowList(): textEdit = textEdit.widget() textEdit.showNormal() def windowMinimizeAll(self): for textEdit in self.mdi.subWindowList(): textEdit = textEdit.widget() textEdit.showMinimized() def updateWindowMenu(self): self.windowMenu.clear() self.addActions( self.windowMenu, (self.windowNextAction, self.windowPrevAction, self.windowCascadeAction, self.windowTileAction, self.windowRestoreAction, self.windowMinimizeAction, self.windowArrangeIconsAction, None, self.windowCloseAction)) textEdits = self.mdi.subWindowList() if not textEdits: return self.windowMenu.addSeparator() i = 1 menu = self.windowMenu for textEdit_MSW in textEdits: textEdit = textEdit_MSW.widget() title = textEdit.windowTitle() if i == 10: self.windowMenu.addSeparator() menu = menu.addMenu("&More") accel = "" if i < 10: accel = "&{0} ".format(i) elif i < 36: accel = "&{0} ".format(chr(i + ord("@") - 9)) action = menu.addAction("{0}{1}".format(accel, title)) self.windowMapper.setMapping(action, textEdit_MSW) action.triggered.connect(self.windowMapper.map) i += 1
class MainWindow(QMainWindow): """This create the main window of the application""" def __init__(self): super(MainWindow, self).__init__() self.ports = serial.listports() self.port = None # remove close & maximize window buttons #self.setWindowFlags(Qt.CustomizeWindowHint|Qt.WindowMinimizeButtonHint) self.setMinimumSize(850, 450) self.mdiArea = QMdiArea() self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setCentralWidget(self.mdiArea) self.mdiArea.subWindowActivated.connect(self.updateMenus) self.mdiArea.setViewMode(QMdiArea.TabbedView) self.windowMapper = QSignalMapper(self) self.windowMapper.mapped[QWidget].connect(self.setActiveSubWindow) self.child = None self.createActions() self.createMenus() self.createStatusBar() self.updateMenus() self.readSettings() self.setWindowTitle("VISCAM") mytoolbar = QToolBar() ports_menu = QComboBox() ports_menu.addItem('Output Port') ports_menu.insertSeparator(1) for port in self.ports: ports_menu.addItem(port) self.ports_menu = ports_menu ports_menu.currentTextChanged.connect(self.setActivePort) mytoolbar.addWidget(ports_menu) mytoolbar.addSeparator() mytoolbar.setMovable(False) mytoolbar.setFixedHeight(60) self.addToolBar(Qt.TopToolBarArea, mytoolbar) def closeEvent(self, scenario): self.mdiArea.closeAllSubWindows() if self.mdiArea.currentSubWindow(): scenario.ignore() else: self.writeSettings() scenario.accept() def about(self): QMessageBox.about( self, "About Viscam", "<b>Viscam</b> controls and manage your video camera through VISCA protocol." "This release is an alpha version. Don't use it in production !!") def updateMenus(self): hasCamera = (self.activeCamera() is not None) self.nextAct.setEnabled(hasCamera) self.previousAct.setEnabled(hasCamera) self.separatorAct.setVisible(hasCamera) def updatePortMenu(self): self.PortMenu.clear() for i, port in enumerate(self.ports): text = "%d %s" % (i + 1, port) if i < 9: text = '&' + text action = self.PortMenu.addAction(text) action.setCheckable(True) if port == self.port: action.setChecked(True) action.triggered.connect(self.setActivePort) def updateWindowMenu(self): self.windowMenu.clear() self.windowMenu.addAction(self.nextAct) self.windowMenu.addAction(self.previousAct) self.windowMenu.addAction(self.separatorAct) windows = self.mdiArea.subWindowList() self.separatorAct.setVisible(len(windows) != 0) for i, window in enumerate(windows): child = window.widget() text = "%d %s" % (i + 1, child.userFriendlyCurrentFile()) if i < 9: text = '&' + text action = self.windowMenu.addAction(text) action.setCheckable(True) action.setChecked(child is self.activeCamera()) action.triggered.connect(self.windowMapper.map) self.windowMapper.setMapping(action, window) def createCamera(self): child = Camera(serial) self.mdiArea.addSubWindow(child) child.newFile() self.child = child return child def createActions(self): self.exitAct = QAction( "E&xit", self, shortcut=QKeySequence.Quit, statusTip="Exit the application", triggered=QApplication.instance().closeAllWindows) self.closeAct = QAction("Cl&ose", self, statusTip="Close the active window", triggered=self.mdiArea.closeActiveSubWindow) self.closeAllAct = QAction("Close &All", self, statusTip="Close all the windows", triggered=self.mdiArea.closeAllSubWindows) self.nextAct = QAction("Ne&xt", self, shortcut=QKeySequence.NextChild, statusTip="Move the focus to the next window", triggered=self.mdiArea.activateNextSubWindow) self.previousAct = QAction( "Pre&vious", self, shortcut=QKeySequence.PreviousChild, statusTip="Move the focus to the previous window", triggered=self.mdiArea.activatePreviousSubWindow) self.separatorAct = QAction(self) self.separatorAct.setSeparator(True) self.aboutAct = QAction("&About", self, statusTip="Show the application's About box", triggered=self.about) def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addAction(self.exitAct) self.PortMenu = self.menuBar().addMenu("&Ports") self.updatePortMenu() self.PortMenu.aboutToShow.connect(self.updatePortMenu) self.windowMenu = self.menuBar().addMenu("&Window") self.updateWindowMenu() self.windowMenu.aboutToShow.connect(self.updateWindowMenu) self.menuBar().addSeparator() self.helpMenu = self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.aboutAct) def createStatusBar(self): self.statusBar().showMessage("Ready") def readSettings(self): settings = QSettings('Pixel Stereo', 'viscam') port = settings.value('port') pos = settings.value('pos', QPoint(200, 200)) size = settings.value('size', QSize(1000, 650)) self.move(pos) self.resize(size) def writeSettings(self): settings = QSettings('Pixel Stereo', 'viscam') settings.setValue('port', self.port) settings.setValue('pos', self.pos()) settings.setValue('size', self.size()) def activeCamera(self): activeSubWindow = self.mdiArea.activeSubWindow() if activeSubWindow: return activeSubWindow.widget() else: return None def findCamera(self, fileName): canonicalFilePath = QFileInfo(fileName).canonicalFilePath() for window in self.mdiArea.subWindowList(): if window.widget().currentFile() == canonicalFilePath: return window return None def setActiveSubWindow(self, window): if window: self.mdiArea.setActiveSubWindow(window) def setActivePort(self): self.port = self.ports_menu.currentText().encode('utf-8') self.updatePortMenu() serial.open(portname=self.port) viscams = _cmd_adress_set(serial) _if_clear(serial) for v in viscams: v = self.createCamera()
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.mdi = QMdiArea() self.setCentralWidget(self.mdi) fileNewAction = self.createAction("&New", self.fileNew, QKeySequence.New, "filenew", "Create a text file") fileOpenAction = self.createAction("&Open...", self.fileOpen, QKeySequence.Open, "fileopen", "Open an existing text file") fileToolbar = self.addToolBar("File") fileToolbar.setObjectName("FileToolbar") self.addActions(fileToolbar, (fileNewAction, fileOpenAction)) def createAction(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/{0}.png".format(icon))) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: action.triggered.connect(slot) if checkable: action.setCheckable(True) return action def addActions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) #@profile def fileNew(self): try: print( u'openSystemConfig内存使用:', round( psutil.Process(getpid()).memory_info().rss / 1024 / 1024, 4)) #print(u'memory_info:', psutil.Process(getpid()).memory_info()) #print(u'memory_info:', psutil.Process(getpid()).memory_full_info()) objgraph.show_growth(shortnames=False) #templist = objgraph.by_type('QIcon') #print('objgraph.by_type:', templist) #if len(templist) >= 1: # objgraph.show_backrefs(templist[-1], filename='obj.png') # textEdit = textedit.TextEdit() #self.systemConfigWindow = Ui_QSystemConfigWindow() #a = sys.getrefcount(self.systemConfigWindow) #self.mdi.addSubWindow(self.systemConfigWindow).show() #self.mdi.closeActiveSubWindow() #self.systemConfigWindow.systemConfigInfoSignal.connect(self.setSystemConfigInfo) #self.systemConfigWindow.pushbuttonOKOnActivated() self.taskConfigWindow = Ui_QTaskConfigWindow() self.mdi.addSubWindow(self.taskConfigWindow).show() #self.mdi.closeActiveSubWindow() #self.systemConfigWindow = None #self.taskConfigWindow = None #templist = None ''' sleep(5) self.taskConfigWindow = Ui_QTaskConfigWindow() self.mdi.addSubWindow(self.taskConfigWindow).show() self.taskConfigWindow.systemConfigInfo = self.systemConfigInfo # textEdit.close() sleep(5) for win_temp in self.mdi.subWindowList(): win_temp_widget = win_temp.widget() if (win_temp_widget is not None) and (isinstance(win_temp_widget, Ui_QTaskConfigWindow)): self.mdi.setActiveSubWindow(win_temp) self.mdi.closeActiveSubWindow() elif (win_temp_widget is not None) and (isinstance(win_temp_widget, Ui_QSystemConfigWindow)): self.mdi.setActiveSubWindow(win_temp) #self.mdi.removeSubWindow(self.systemConfigWindow) self.mdi.closeActiveSubWindow() #self.mdi.removeSubWindow(self.systemConfigWindow) #b = sys.getrefcount(self.systemConfigWindow) win_temp = None win_temp_widget = None self.systemConfigInfo = None self.systemConfigWindow = None self.taskConfigWindow = None ''' except Exception as e: print(print_exc()) def fileOpen(self): #self.mdi.closeActiveSubWindow() #self.taskConfigWindow = Ui_QTaskConfigWindow() #self.mdi.addSubWindow(self.taskConfigWindow).show() #self.taskConfigWindow.systemConfigInfo = self.systemConfigInfo self.fileSave() def fileSave(self): for win_temp in self.mdi.subWindowList(): win_temp_widget = win_temp.widget() if (win_temp_widget is not None) and (isinstance( win_temp_widget, Ui_QTaskConfigWindow)): self.mdi.setActiveSubWindow(win_temp) self.mdi.closeActiveSubWindow() elif (win_temp_widget is not None) and (isinstance( win_temp_widget, Ui_QSystemConfigWindow)): self.mdi.setActiveSubWindow(win_temp) # self.mdi.removeSubWindow(self.systemConfigWindow) self.mdi.closeActiveSubWindow() # self.mdi.removeSubWindow(self.systemConfigWindow) # b = sys.getrefcount(self.systemConfigWindow) #win_temp = None #win_temp_widget = None self.systemConfigInfo = None self.systemConfigWindow = None self.taskConfigWindow = None
class CalculatorWindow(NodeEditorWindow): """Class representing the MainWindow of the application. Instance Attributes: name_company and name_product - used to register the settings """ def initUI(self): """UI is composed with """ # variable for QSettings self.name_company = 'Michelin' self.name_product = 'Calculator NodeEditor' # Load filesheets self.stylesheet_filename = os.path.join(os.path.dirname(__file__), 'qss/nodeeditor.qss') loadStylessheets( os.path.join(os.path.dirname(__file__), 'qss/nodeeditor-dark.qss'), self.stylesheet_filename) self.empty_icon = QIcon(".") if DEBUG: print('Registered Node') pp(CALC_NODES) # Instantiate the MultiDocument Area self.mdiArea = QMdiArea() self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdiArea.setViewMode(QMdiArea.TabbedView) self.mdiArea.setTabsClosable(True) self.setCentralWidget(self.mdiArea) # Connect subWindowActivate to updateMenu # Activate the items on the file_menu and the edit_menu self.mdiArea.subWindowActivated.connect(self.updateMenus) # from mdi example... self.windowMapper = QSignalMapper(self) self.windowMapper.mapped[QWidget].connect(self.setActiveSubWindow) # instantiate various elements self.createNodesDock() self.createActions() self.createMenus() self.createToolBars() self.createStatusBar() self.updateMenus() self.readSettings() self.setWindowTitle("Calculator NodeEditor Example") def createActions(self): """Instantiate various `QAction` for the main toolbar. File and Edit menu actions are instantiated in the :classs:~`node_editor.node_editor_widget.NodeEditorWidget` Window and Help actions are specific to the :class:~`examples.calc_window.CalcWindow` """ super().createActions() self.actClose = QAction("Cl&ose", self, statusTip="Close the active window", triggered=self.mdiArea.closeActiveSubWindow) self.actCloseAll = QAction("Close &All", self, statusTip="Close all the windows", triggered=self.mdiArea.closeAllSubWindows) self.actTile = QAction("&Tile", self, statusTip="Tile the windows", triggered=self.mdiArea.tileSubWindows) self.actCascade = QAction("&Cascade", self, statusTip="Cascade the windows", triggered=self.mdiArea.cascadeSubWindows) self.actNext = QAction("Ne&xt", self, shortcut=QKeySequence.NextChild, statusTip="Move the focus to the next window", triggered=self.mdiArea.activateNextSubWindow) self.actPrevious = QAction( "Pre&vious", self, shortcut=QKeySequence.PreviousChild, statusTip="Move the focus to the previous window", triggered=self.mdiArea.activatePreviousSubWindow) self.actSeparator = QAction(self) self.actSeparator.setSeparator(True) self.actAbout = QAction("&About", self, statusTip="Show the application's About box", triggered=self.about) def createMenus(self): """Populate File, Edit, Window and Help with `QAction`""" super().createMenus() self.windowMenu = self.menuBar().addMenu("&Window") self.updateWindowMenu() self.windowMenu.aboutToShow.connect(self.updateWindowMenu) self.menuBar().addSeparator() self.helpMenu = self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.actAbout) # Any time the edit menu is about to be shown, update it self.editMenu.aboutToShow.connect(self.updateEditMenu) def onWindowNodesToolbar(self): """Event handling the visibility of the `Nodes Dock`""" if self.nodesDock.isVisible(): self.nodesDock.hide() else: self.nodesDock.show() def createToolBars(self): pass def createNodesDock(self): """Create `Nodes Dock` and populates it with the list of `Nodes` The `Nodes` are automatically detected via the :class:~`examples.calc_drag_listbox.QNEDragListBox` """ self.nodeListWidget = QNEDragListbox() self.nodesDock = QDockWidget("Nodes") self.nodesDock.setWidget(self.nodeListWidget) self.nodesDock.setFloating(False) self.addDockWidget(Qt.RightDockWidgetArea, self.nodesDock) def createStatusBar(self): self.statusBar().showMessage("Ready", ) def updateMenus(self): active = self.getCurrentNodeEditorWidget() hasMdiChild = (active is not None) self.actSave.setEnabled(hasMdiChild) self.actSaveAs.setEnabled(hasMdiChild) self.actClose.setEnabled(hasMdiChild) self.actCloseAll.setEnabled(hasMdiChild) self.actTile.setEnabled(hasMdiChild) self.actCascade.setEnabled(hasMdiChild) self.actNext.setEnabled(hasMdiChild) self.actPrevious.setEnabled(hasMdiChild) self.actSeparator.setVisible(hasMdiChild) self.updateEditMenu() def updateEditMenu(self): if DEBUG: print('updateEditMenu') try: active = self.getCurrentNodeEditorWidget() hasMdiChild = (active is not None) hasSelectedItems = hasMdiChild and active.hasSelectedItems() self.actPaste.setEnabled(hasMdiChild) self.actCut.setEnabled(hasSelectedItems) self.actCopy.setEnabled(hasSelectedItems) self.actDelete.setEnabled(hasSelectedItems) self.actUndo.setEnabled(hasMdiChild and active.canUndo()) self.actRedo.setEnabled(hasMdiChild and active.canRedo()) except Exception as e: dumpException(e) def updateWindowMenu(self): self.windowMenu.clear() toolbar_nodes = self.windowMenu.addAction('Nodes toolbar') toolbar_nodes.setCheckable(True) toolbar_nodes.triggered.connect(self.onWindowNodesToolbar) toolbar_nodes.setChecked(self.nodesDock.isVisible()) self.windowMenu.addSeparator() self.windowMenu.addAction(self.actClose) self.windowMenu.addAction(self.actCloseAll) self.windowMenu.addSeparator() self.windowMenu.addAction(self.actTile) self.windowMenu.addAction(self.actCascade) self.windowMenu.addSeparator() self.windowMenu.addAction(self.actNext) self.windowMenu.addAction(self.actPrevious) self.windowMenu.addAction(self.actSeparator) windows = self.mdiArea.subWindowList() self.actSeparator.setVisible(len(windows) != 0) for i, window in enumerate(windows): child = window.widget() text = "%d %s" % (i + 1, child.getUserFriendlyFilename()) if i < 9: text = '&' + text action = self.windowMenu.addAction(text) action.setCheckable(True) action.setChecked(child is self.getCurrentNodeEditorWidget()) action.triggered.connect(self.windowMapper.map) self.windowMapper.setMapping(action, window) def getCurrentNodeEditorWidget(self) -> NodeEditorWidget: """Return the widget currently holding the scene. For different application, the method can be overridden to return mdiArea, the central widget... Returns ------- NodeEditorWidget Node editor Widget. The widget holding the scene. """ activeSubWindow = self.mdiArea.activeSubWindow() if activeSubWindow: return activeSubWindow.widget() return None def onFileNew(self): try: subwnd = self.createMdiChild() subwnd.widget().fileNew() subwnd.show() except Exception as e: dumpException(e) def onFileOpen(self): """Open OpenFileDialog""" # OpenFile dialog fnames, filter = QFileDialog.getOpenFileNames( self, 'Open graph from file', self.getFileDialogDirectory(), self.getFileDialogFilter()) try: for fname in fnames: if fname: existing = self.findMdiChild(fname) if existing: self.mdiArea.setActiveSubWindow(existing) else: # do not use createMdiChild as a new node editor to call the fileLoad method # Create new subwindow and open file nodeeditor = CalculatorSubWindow() if nodeeditor.fileLoad(fname): self.statusBar().showMessage( f'File {fname} loaded', 5000) nodeeditor.setTitle() subwnd = self.createMdiChild(nodeeditor) subwnd.show() else: nodeeditor.close() except Exception as e: dumpException(e) def about(self): QMessageBox.about( self, "About Calculator NodeEditor Example", "The <b>Calculator NodeEditor</b> example demonstrates how to write multiple " "document interface applications using PyQt5 and NodeEditor.") def closeEvent(self, event: QCloseEvent) -> None: try: self.mdiArea.closeAllSubWindows() if self.mdiArea.currentSubWindow(): event.ignore() else: self.writeSettings() event.accept() # In case of fixing the application closing # import sys # sys.exit(0) except Exception as e: dumpException(e) def createMdiChild(self, child_widget=None): nodeeditor = child_widget if child_widget is not None else CalculatorSubWindow( ) subwnd = self.mdiArea.addSubWindow(nodeeditor, ) subwnd.setWindowIcon(self.empty_icon) # nodeeditor.scene.addItemSelectedListener(self.updateEditMenu) # nodeeditor.scene.addItemsDeselectedListener(self.updateEditMenu) nodeeditor.scene.history.addHistoryModifiedListener( self.updateEditMenu) nodeeditor.addCloseEventListener(self.onSubWndClose) return subwnd def onSubWndClose(self, widget: CalculatorSubWindow, event: QCloseEvent): # close event from the nodeeditor works by asking the active widget # if modification occurs on the active widget, ask to save or not. # Therefore when closing a subwindow, select the corresponding subwindow existing = self.findMdiChild(widget.filename) self.mdiArea.setActiveSubWindow(existing) # Does the active widget need to be saved ? if self.maybeSave(): event.accept() else: event.ignore() def findMdiChild(self, fileName): for window in self.mdiArea.subWindowList(): if window.widget().filename == fileName: return window return None def setActiveSubWindow(self, window): if window: self.mdiArea.setActiveSubWindow(window)
class RDFNavigator(QMainWindow): output_message = pyqtSignal(str) def __init__(self): super(RDFNavigator, self).__init__() self.lastDir = '.' self.settingsManager = RDFNavigatorSettignsManager() self.resourceRefManager = RDFNavigatorResourceReferenceManager() self.childrenFactory = RDFNavigatorChildrenFactory(self) self.mdiArea = QMdiArea() self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setCentralWidget(self.mdiArea) self.mdiArea.subWindowActivated.connect(self.updateMenus) self.windowMapper = QSignalMapper(self) self.windowMapper.mapped[QWidget].connect(self.setActiveSubWindow) self.createActions() self.createMenus() self.createToolBars() self.createStatusBar() self.updateMenus() self.createDockWidgets() self.readSettings() self.setWindowTitle("RDF Navigator") self.global_data = {} self.analyzeSystemData() #self.setStyleSheet("""QToolTip { background-color: black; color: white; border: black solid 1px }""") def closeEvent(self, event): self.mdiArea.closeAllSubWindows() if self.mdiArea.currentSubWindow(): event.ignore() else: self.writeSettings() event.accept() def newFile(self, fileType): child = self.createMdiChild(fileType) child.newFile() child.show() def openFileHelper(self, fileName, fileType): if fileName: self.lastDir = os.path.dirname(fileName) existing = self.findMdiChild(fileName) if existing: self.mdiArea.setActiveSubWindow(existing) return child = self.createMdiChild(fileType) child.setManager(self.settingsManager) if child.loadFile(fileName): self.statusBar().showMessage("File loaded", 2000) child.show() else: child.close() def open(self): fileName, _ = QFileDialog.getOpenFileName( self, "Open runntime data format file", self.lastDir, "RDF Files (*.RDF);;XML Files (*.xml)") self.openFileHelper(fileName, RDFNavigatorChildrenTypes.XML) def openProject(self): fileName, _ = QFileDialog.getOpenFileName( self, "Open XML schema project file", self.lastDir, "XML Schema Files (*.xsd);;") self.openFileHelper(fileName, RDFNavigatorChildrenTypes.SCHEMA) child = self.findMdiChild(fileName) if child: schema = RDFNavigatorXmlSchema() schema.validation_message.connect(self.output_message) schema.setSchemaPath(fileName) graph = schema.getSchemaDependencyGraph() self.projectStructureWidget.createProjectTree( fileName, graph, RDFNavigatorChildrenTypes.SCHEMA) self.projectStructureWidget.open_file_request.connect( self.openFileHelper) def openTemplate(self): fileName, _ = QFileDialog.getOpenFileName( self, "Open system data template file", self.lastDir, "XML Template Files (*.xml);;") self.openFileHelper(fileName, RDFNavigatorChildrenTypes.TEMPLATE) child = self.findMdiChild(fileName) if child: schema = RDFNavigatorXmlSchema() schema.validation_message.connect(self.output_message) schema.setSchemaPath(fileName) graph = schema.getTemplateDependencyGraph() self.projectStructureWidget.createProjectTree( fileName, graph, RDFNavigatorChildrenTypes.TEMPLATE) self.projectStructureWidget.createObjectsTree(fileName) self.projectStructureWidget.createFileSystemTree(fileName) self.projectStructureWidget.open_file_request.connect( self.openFileHelper) self.analyzeTemplateData(os.path.dirname(fileName)) def save(self): if self.activeMdiChild() and self.activeMdiChild().save(): self.statusBar().showMessage("File saved", 2000) def saveAs(self): if self.activeMdiChild() and self.activeMdiChild().saveAs(): self.statusBar().showMessage("File saved", 2000) def cut(self): if self.activeMdiChild(): self.activeMdiChild().cut() def copy(self): if self.activeMdiChild(): self.activeMdiChild().copy() def paste(self): if self.activeMdiChild(): self.activeMdiChild().paste() def activateFind(self): child = self.activeMdiChild() find = RDFNavigatorFind(self) find.findAllCurrentClicked.connect(child.findAll) find.findNextClicked.connect(child.findNextWord) find.findCountClicked.connect(child.countWord) if child.hasSelectedText(): text = child.selectedText() find.setFindText(text) find.show() def about(self): QMessageBox.about(self, "About RDF Navigator", "Tool to simplify work with RDF data") def updateMenus(self): hasMdiChild = (self.activeMdiChild() is not None) self.saveAct.setEnabled(hasMdiChild) self.saveAsAct.setEnabled(hasMdiChild) self.pasteAct.setEnabled(hasMdiChild) self.closeAct.setEnabled(hasMdiChild) self.closeAllAct.setEnabled(hasMdiChild) self.tileAct.setEnabled(hasMdiChild) self.cascadeAct.setEnabled(hasMdiChild) self.nextAct.setEnabled(hasMdiChild) self.previousAct.setEnabled(hasMdiChild) self.separatorAct.setVisible(hasMdiChild) hasSelection = (self.activeMdiChild() is not None and self.activeMdiChild().hasSelectedText()) self.cutAct.setEnabled(hasSelection) self.copyAct.setEnabled(hasSelection) def updateWindowMenu(self): self.windowMenu.clear() self.windowMenu.addAction(self.closeAct) self.windowMenu.addAction(self.closeAllAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.tileAct) self.windowMenu.addAction(self.cascadeAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.nextAct) self.windowMenu.addAction(self.previousAct) self.windowMenu.addAction(self.separatorAct) windows = self.mdiArea.subWindowList() self.separatorAct.setVisible(len(windows) != 0) for i, window in enumerate(windows): child = window.widget() text = "%d %s" % (i + 1, child.userFriendlyCurrentFile()) if i < 9: text = '&' + text action = self.windowMenu.addAction(text) action.setCheckable(True) action.setChecked(child is self.activeMdiChild()) action.triggered.connect(self.windowMapper.map) self.windowMapper.setMapping(action, window) def createMdiChild(self, childType): child = self.childrenFactory.createObject(childType) self.mdiArea.addSubWindow(child) child.copyAvailable.connect(self.cutAct.setEnabled) child.copyAvailable.connect(self.copyAct.setEnabled) return child def createActions(self): self.newAct = QAction(QIcon(':/images/new.png'), "&New", self, shortcut=QKeySequence.New, statusTip="Create a new file", triggered=self.newFile) self.openFileAct = QAction(QIcon(':/images/open.png'), "&Open file...", self, shortcut=QKeySequence.Open, statusTip="Open an existing file", triggered=self.open) self.openProjectAct = QAction(QIcon(':/images/openProject.png'), "&Open project...", self, shortcut=QKeySequence("Ctrl+Shift+O"), statusTip="Open an existing project", triggered=self.openProject) self.openTemplate = QAction(QIcon(':/images/sdt.png'), "&Open template...", self, shortcut=QKeySequence("Alt+Shift+O"), statusTip="Open an existing template", triggered=self.openTemplate) self.saveAct = QAction(QIcon(':/images/save.png'), "&Save", self, shortcut=QKeySequence.Save, statusTip="Save the document to disk", triggered=self.save) self.saveAsAct = QAction( "Save &As...", self, shortcut=QKeySequence.SaveAs, statusTip="Save the document under a new name", triggered=self.saveAs) self.exitAct = QAction( "E&xit", self, shortcut=QKeySequence.Quit, statusTip="Exit the application", triggered=QApplication.instance().closeAllWindows) self.cutAct = QAction( QIcon(':/images/cut.png'), "Cu&t", self, shortcut=QKeySequence.Cut, statusTip="Cut the current selection's contents to the clipboard", triggered=self.cut) self.copyAct = QAction( QIcon(':/images/copy.png'), "&Copy", self, shortcut=QKeySequence.Copy, statusTip="Copy the current selection's contents to the clipboard", triggered=self.copy) self.pasteAct = QAction( QIcon(':/images/paste.png'), "&Paste", self, shortcut=QKeySequence.Paste, statusTip= "Paste the clipboard's contents into the current selection", triggered=self.paste) self.findAct = QAction(QIcon(':/images/find.png'), "&Find", self, shortcut=QKeySequence.Find, statusTip="Find text", triggered=self.activateFind) self.settingsAct = QAction(QIcon(':/images/settings.png'), "Open settings", self, shortcut=QKeySequence("Ctrl+1"), statusTip="Open Settings", triggered=self.activateSettings) self.showProjectStructAct = QAction( QIcon(':/images/project_structure.png'), "Show structure", self, shortcut=QKeySequence("Alt+1"), statusTip="Show project structure", triggered=self.showProjectStructure) self.showOutputAct = QAction(QIcon(':/images/project_output.png'), "Show output", self, shortcut=QKeySequence("Alt+2"), statusTip="Show output", triggered=self.showOutput) self.showBookmarks = QAction(QIcon(':/images/project_bookmarks.png'), "Show bookmarks", self, shortcut=QKeySequence("Alt+3"), statusTip="Show bookmarks", triggered=self.showBookmarks) self.showAsDiagram = QAction(QIcon(':/images/diagram.png'), "Show as diagram", self, shortcut=QKeySequence("Alt+4"), statusTip="Show document as diagram", triggered=self.showAsDiagram) self.closeAct = QAction("Cl&ose", self, statusTip="Close the active window", triggered=self.mdiArea.closeActiveSubWindow) self.closeAllAct = QAction("Close &All", self, statusTip="Close all the windows", triggered=self.mdiArea.closeAllSubWindows) self.tileAct = QAction("&Tile", self, statusTip="Tile the windows", triggered=self.mdiArea.tileSubWindows) self.cascadeAct = QAction("&Cascade", self, statusTip="Cascade the windows", triggered=self.mdiArea.cascadeSubWindows) self.nextAct = QAction("Ne&xt", self, shortcut=QKeySequence.NextChild, statusTip="Move the focus to the next window", triggered=self.mdiArea.activateNextSubWindow) self.previousAct = QAction( "Pre&vious", self, shortcut=QKeySequence.PreviousChild, statusTip="Move the focus to the previous window", triggered=self.mdiArea.activatePreviousSubWindow) self.separatorAct = QAction(self) self.separatorAct.setSeparator(True) self.aboutAct = QAction("&About", self, statusTip="Show the application's About box", triggered=self.about) self.aboutQtAct = QAction("About &Qt", self, statusTip="Show the Qt library's About box", triggered=QApplication.instance().aboutQt) def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addAction(self.newAct) self.fileMenu.addAction(self.openFileAct) self.fileMenu.addAction(self.openProjectAct) self.fileMenu.addAction(self.openTemplate) self.fileMenu.addAction(self.saveAct) self.fileMenu.addAction(self.saveAsAct) self.fileMenu.addSeparator() action = self.fileMenu.addAction("Switch layout direction") action.triggered.connect(self.switchLayoutDirection) self.fileMenu.addAction(self.exitAct) self.editMenu = self.menuBar().addMenu("&Edit") self.editMenu.addAction(self.cutAct) self.editMenu.addAction(self.copyAct) self.editMenu.addAction(self.pasteAct) self.editMenu.addAction(self.findAct) self.settingsMenu = self.menuBar().addMenu("Set&tings") self.settingsMenu.addAction(self.settingsAct) self.viewMenu = self.menuBar().addMenu("&View") self.createViewMenu() self.windowMenu = self.menuBar().addMenu("&Window") self.updateWindowMenu() self.windowMenu.aboutToShow.connect(self.updateWindowMenu) self.menuBar().addSeparator() self.helpMenu = self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.aboutAct) self.helpMenu.addAction(self.aboutQtAct) def createToolBars(self): self.fileToolBar = self.addToolBar("File") self.fileToolBar.addAction(self.newAct) self.fileToolBar.addAction(self.openFileAct) self.fileToolBar.addAction(self.openProjectAct) self.fileToolBar.addAction(self.openTemplate) self.fileToolBar.addAction(self.saveAct) self.editToolBar = self.addToolBar("Edit") self.editToolBar.addAction(self.cutAct) self.editToolBar.addAction(self.copyAct) self.editToolBar.addAction(self.pasteAct) def createStatusBar(self): self.statusBar().showMessage("Ready") def createDockWidgets(self): self.projectStructureWidget = RDFNavigatorProjectStructure(self) self.projectStructureDockWidget = QDockWidget("Project structure", self) self.projectStructureDockWidget.setWidget(self.projectStructureWidget) self.addDockWidget(Qt.LeftDockWidgetArea, self.projectStructureDockWidget) self.projectOutputWidget = RDFNavigatorOutput(self) self.projectOutputDockWidget = QDockWidget("Project output", self) self.projectOutputDockWidget.setWidget(self.projectOutputWidget) self.addDockWidget(Qt.BottomDockWidgetArea, self.projectOutputDockWidget) self.output_message.connect(self.projectOutputWidget.write) self.bookmarskWidget = RDFNavigatorBookmarks(self) self.bookmarksDockWidget = QDockWidget("Bookmarks", self) self.bookmarksDockWidget.setWidget(self.bookmarskWidget) self.addDockWidget(Qt.BottomDockWidgetArea, self.bookmarksDockWidget) self.bookmarskWidget.bookmark_ref_requested.connect(self.showBookmark) def readSettings(self): pos = self.settingsManager.getConfig('pos', QPoint(200, 200)) size = self.settingsManager.getConfig('size', QSize(400, 400)) self.lastDir = self.settingsManager.getConfig('lastDir', '') self.move(pos) self.resize(size) def writeSettings(self): self.settingsManager.setConfig('pos', self.pos()) self.settingsManager.setConfig('size', self.size()) self.settingsManager.setConfig('lastDir', self.lastDir) def activeMdiChild(self): activeSubWindow = self.mdiArea.activeSubWindow() if activeSubWindow: return activeSubWindow.widget() return None def findMdiChild(self, fileName): canonicalFilePath = QFileInfo(fileName).canonicalFilePath() for window in self.mdiArea.subWindowList(): if window.widget().currentFile() == canonicalFilePath: return window return None def switchLayoutDirection(self): if self.layoutDirection() == Qt.LeftToRight: QApplication.setLayoutDirection(Qt.RightToLeft) else: QApplication.setLayoutDirection(Qt.LeftToRight) def setActiveSubWindow(self, window): if window: self.mdiArea.setActiveSubWindow(window) def activateSettings(self): settingsDlg = RDFNavigatorSettings(self) settingsDlg.setPluginsPath(self.settingsManager) settingsDlg.setRDFToolsPath(self.settingsManager) settingsDlg.setSchemaPath(self.settingsManager) settingsDlg.setSysDataPath(self.settingsManager) settingsDlg.exec_() settingsDict = settingsDlg.getConfig() map(lambda (x, y): self.settingsManager.setConfig(x, y), settingsDict.items()) def analyzeSystemData(self): self.resourceRefManager.setSysDataPath( self.settingsManager.getConfig('sys_data', '')) self.global_refs_data, self.global_vals_data = self.resourceRefManager.analyzeRefs( ) if self.global_refs_data != {} and self.global_vals_data != {}: self.global_file_refs_data = dict( reduce(lambda x, y: x + y, [[(v, keys) for v in vals] for keys, vals in self.global_refs_data.iteritems() if vals != {}])) def analyzeTemplateData(self, template_path): sysDataPath = self.resourceRefManager.getSysDataPath() self.resourceRefManager.setSysDataPath(template_path) self.template_refs_data, self.template_vals_data = self.resourceRefManager.analyzeRefs( ) if self.template_refs_data != {} and self.template_vals_data != {}: self.template_file_refs_data = dict( reduce(lambda x, y: x + y, [[(v, keys) for v in vals] for keys, vals in self.template_refs_data.iteritems() if vals != {}])) self.resourceRefManager.setSysDataPath(sysDataPath) def showReference(self, obj_name, key_id): child_name = self.template_file_refs_data.get(obj_name) if child_name is None: child_name = self.global_file_refs_data[obj_name] child = self.findMdiChild(child_name) if child is None: self.openFileHelper(child_name, RDFNavigatorChildrenTypes.TEMPLATE) child = self.findMdiChild(child_name) self.mdiArea.setActiveSubWindow(child) line = None try: line = self.template_refs_data[child_name][obj_name][key_id] except KeyError: line = self.global_refs_data[child_name][obj_name][key_id] child.widget().goToLine(line) def showReferenceValue(self, obj_name, key_id): child_name = self.template_file_refs_data.get(obj_name) if child_name is None: child_name = self.global_file_refs_data[obj_name] value = None try: value = self.template_vals_data[child_name][obj_name][key_id] except KeyError: value = self.global_refs_data[child_name][obj_name][key_id] child = self.activeMdiChild() if child is not None: child.displayRefValue(value) def showBookmark(self, filename, line): child = self.findMdiChild(filename) if child is None: self.openFileHelper(filename, RDFNavigatorChildrenTypes.TEMPLATE) child = self.findMdiChild(filename) self.mdiArea.setActiveSubWindow(child) child.widget().goToLine(line) def createViewMenu(self): self.viewMenu.addAction(self.showProjectStructAct) self.viewMenu.addAction(self.showOutputAct) self.viewMenu.addAction(self.showBookmarks) self.viewMenu.addAction(self.showAsDiagram) def showProjectStructure(self): self.projectStructureDockWidget.show() def showOutput(self): self.projectOutputDockWidget.show() def showBookmarks(self): self.bookmarksDockWidget.show() def showAsDiagram(self): from rdfdiagram.rdfdiagramwidget import RdfDiagramWidget rdfdiagram = RdfDiagramWidget(self) self.mdiArea.addSubWindow(rdfdiagram) rdfdiagram.show()
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.mdiArea = QMdiArea() self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setCentralWidget(self.mdiArea) self.mdiArea.subWindowActivated.connect(self.updateMenus) self.windowMapper = QSignalMapper(self) self.windowMapper.mapped[QWidget].connect(self.setActiveSubWindow) self.createActions() self.createMenus() self.createToolBars() self.createStatusBar() self.updateMenus() self.readSettings() self.setWindowTitle("MDI") def closeEvent(self, event): self.mdiArea.closeAllSubWindows() if self.mdiArea.currentSubWindow(): event.ignore() else: self.writeSettings() event.accept() def newFile(self): child = self.createMdiChild() child.newFile() child.show() def open(self): fileName, _ = QFileDialog.getOpenFileName(self) if fileName: existing = self.findMdiChild(fileName) if existing: self.mdiArea.setActiveSubWindow(existing) return child = self.createMdiChild() if child.loadFile(fileName): self.statusBar().showMessage("File loaded", 2000) child.show() else: child.close() def save(self): if self.activeMdiChild() and self.activeMdiChild().save(): self.statusBar().showMessage("File saved", 2000) def saveAs(self): if self.activeMdiChild() and self.activeMdiChild().saveAs(): self.statusBar().showMessage("File saved", 2000) def cut(self): if self.activeMdiChild(): self.activeMdiChild().cut() def copy(self): if self.activeMdiChild(): self.activeMdiChild().copy() def paste(self): if self.activeMdiChild(): self.activeMdiChild().paste() def about(self): QMessageBox.about(self, "About MDI", "The <b>MDI</b> example demonstrates how to write multiple " "document interface applications using Qt.") def updateMenus(self): hasMdiChild = (self.activeMdiChild() is not None) self.saveAct.setEnabled(hasMdiChild) self.saveAsAct.setEnabled(hasMdiChild) self.pasteAct.setEnabled(hasMdiChild) self.closeAct.setEnabled(hasMdiChild) self.closeAllAct.setEnabled(hasMdiChild) self.tileAct.setEnabled(hasMdiChild) self.cascadeAct.setEnabled(hasMdiChild) self.nextAct.setEnabled(hasMdiChild) self.previousAct.setEnabled(hasMdiChild) self.separatorAct.setVisible(hasMdiChild) hasSelection = (self.activeMdiChild() is not None and self.activeMdiChild().textCursor().hasSelection()) self.cutAct.setEnabled(hasSelection) self.copyAct.setEnabled(hasSelection) def updateWindowMenu(self): self.windowMenu.clear() self.windowMenu.addAction(self.closeAct) self.windowMenu.addAction(self.closeAllAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.tileAct) self.windowMenu.addAction(self.cascadeAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.nextAct) self.windowMenu.addAction(self.previousAct) self.windowMenu.addAction(self.separatorAct) windows = self.mdiArea.subWindowList() self.separatorAct.setVisible(len(windows) != 0) for i, window in enumerate(windows): child = window.widget() text = "%d %s" % (i + 1, child.userFriendlyCurrentFile()) if i < 9: text = '&' + text action = self.windowMenu.addAction(text) action.setCheckable(True) action.setChecked(child is self.activeMdiChild()) action.triggered.connect(self.windowMapper.map) self.windowMapper.setMapping(action, window) def createMdiChild(self): child = MdiChild() self.mdiArea.addSubWindow(child) child.copyAvailable.connect(self.cutAct.setEnabled) child.copyAvailable.connect(self.copyAct.setEnabled) return child def createActions(self): self.newAct = QAction(QIcon(':/images/new.png'), "&New", self, shortcut=QKeySequence.New, statusTip="Create a new file", triggered=self.newFile) self.openAct = QAction(QIcon(':/images/open.png'), "&Open...", self, shortcut=QKeySequence.Open, statusTip="Open an existing file", triggered=self.open) self.saveAct = QAction(QIcon(':/images/save.png'), "&Save", self, shortcut=QKeySequence.Save, statusTip="Save the document to disk", triggered=self.save) self.saveAsAct = QAction("Save &As...", self, shortcut=QKeySequence.SaveAs, statusTip="Save the document under a new name", triggered=self.saveAs) self.exitAct = QAction("E&xit", self, shortcut=QKeySequence.Quit, statusTip="Exit the application", triggered=QApplication.instance().closeAllWindows) self.cutAct = QAction(QIcon(':/images/cut.png'), "Cu&t", self, shortcut=QKeySequence.Cut, statusTip="Cut the current selection's contents to the clipboard", triggered=self.cut) self.copyAct = QAction(QIcon(':/images/copy.png'), "&Copy", self, shortcut=QKeySequence.Copy, statusTip="Copy the current selection's contents to the clipboard", triggered=self.copy) self.pasteAct = QAction(QIcon(':/images/paste.png'), "&Paste", self, shortcut=QKeySequence.Paste, statusTip="Paste the clipboard's contents into the current selection", triggered=self.paste) self.closeAct = QAction("Cl&ose", self, statusTip="Close the active window", triggered=self.mdiArea.closeActiveSubWindow) self.closeAllAct = QAction("Close &All", self, statusTip="Close all the windows", triggered=self.mdiArea.closeAllSubWindows) self.tileAct = QAction("&Tile", self, statusTip="Tile the windows", triggered=self.mdiArea.tileSubWindows) self.cascadeAct = QAction("&Cascade", self, statusTip="Cascade the windows", triggered=self.mdiArea.cascadeSubWindows) self.nextAct = QAction("Ne&xt", self, shortcut=QKeySequence.NextChild, statusTip="Move the focus to the next window", triggered=self.mdiArea.activateNextSubWindow) self.previousAct = QAction("Pre&vious", self, shortcut=QKeySequence.PreviousChild, statusTip="Move the focus to the previous window", triggered=self.mdiArea.activatePreviousSubWindow) self.separatorAct = QAction(self) self.separatorAct.setSeparator(True) self.aboutAct = QAction("&About", self, statusTip="Show the application's About box", triggered=self.about) self.aboutQtAct = QAction("About &Qt", self, statusTip="Show the Qt library's About box", triggered=QApplication.instance().aboutQt) def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addAction(self.newAct) self.fileMenu.addAction(self.openAct) self.fileMenu.addAction(self.saveAct) self.fileMenu.addAction(self.saveAsAct) self.fileMenu.addSeparator() action = self.fileMenu.addAction("Switch layout direction") action.triggered.connect(self.switchLayoutDirection) self.fileMenu.addAction(self.exitAct) self.editMenu = self.menuBar().addMenu("&Edit") self.editMenu.addAction(self.cutAct) self.editMenu.addAction(self.copyAct) self.editMenu.addAction(self.pasteAct) self.windowMenu = self.menuBar().addMenu("&Window") self.updateWindowMenu() self.windowMenu.aboutToShow.connect(self.updateWindowMenu) self.menuBar().addSeparator() self.helpMenu = self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.aboutAct) self.helpMenu.addAction(self.aboutQtAct) def createToolBars(self): self.fileToolBar = self.addToolBar("File") self.fileToolBar.addAction(self.newAct) self.fileToolBar.addAction(self.openAct) self.fileToolBar.addAction(self.saveAct) self.editToolBar = self.addToolBar("Edit") self.editToolBar.addAction(self.cutAct) self.editToolBar.addAction(self.copyAct) self.editToolBar.addAction(self.pasteAct) def createStatusBar(self): self.statusBar().showMessage("Ready") def readSettings(self): settings = QSettings('Trolltech', 'MDI Example') pos = settings.value('pos', QPoint(200, 200)) size = settings.value('size', QSize(400, 400)) self.move(pos) self.resize(size) def writeSettings(self): settings = QSettings('Trolltech', 'MDI Example') settings.setValue('pos', self.pos()) settings.setValue('size', self.size()) def activeMdiChild(self): activeSubWindow = self.mdiArea.activeSubWindow() if activeSubWindow: return activeSubWindow.widget() return None def findMdiChild(self, fileName): canonicalFilePath = QFileInfo(fileName).canonicalFilePath() for window in self.mdiArea.subWindowList(): if window.widget().currentFile() == canonicalFilePath: return window return None def switchLayoutDirection(self): if self.layoutDirection() == Qt.LeftToRight: QApplication.setLayoutDirection(Qt.RightToLeft) else: QApplication.setLayoutDirection(Qt.LeftToRight) def setActiveSubWindow(self, window): if window: self.mdiArea.setActiveSubWindow(window)
class MainWindow(QMainWindow): """This create the main window of the application""" def __init__(self): super(MainWindow, self).__init__() # remove close & maximize window buttons #self.setWindowFlags(Qt.CustomizeWindowHint|Qt.WindowMinimizeButtonHint) self.setMinimumSize(500, 666) #self.setMaximumSize(1000,666) self.mdiArea = QMdiArea() self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setCentralWidget(self.mdiArea) self.mdiArea.subWindowActivated.connect(self.updateMenus) self.mdiArea.setViewMode(QMdiArea.TabbedView) self.windowMapper = QSignalMapper(self) self.windowMapper.mapped[QWidget].connect(self.setActiveSubWindow) self.child = None self.createActions() self.createMenus() self.createStatusBar() self.updateMenus() self.readSettings() self.setWindowTitle("LEKTURE") mytoolbar = QToolBar() #self.toolbar = self.addToolBar() mytoolbar.addAction(self.newAct) mytoolbar.addAction(self.openAct) mytoolbar.addAction(self.saveAct) mytoolbar.addAction(self.saveAsAct) mytoolbar.addSeparator() mytoolbar.addAction(self.outputsAct) mytoolbar.addAction(self.scenarioAct) self.scenarioAct.setVisible(False) mytoolbar.setMovable(False) mytoolbar.setFixedWidth(60) self.addToolBar(Qt.LeftToolBarArea, mytoolbar) def closeEvent(self, scenario): """method called when the main window wants to be closed""" self.mdiArea.closeAllSubWindows() if self.mdiArea.currentSubWindow(): scenario.ignore() else: self.writeSettings() scenario.accept() def newFile(self): """creates a new project""" child = self.createProjekt() child.newFile() child.show() self.child = child def open(self): """open a project""" fileName, _ = QFileDialog.getOpenFileName(self) if fileName: existing = self.findProjekt(fileName) if existing: self.mdiArea.setActiveSubWindow(existing) return child = self.createProjekt() if child.loadFile(fileName): self.statusBar().showMessage("File loaded", 2000) child.show() else: child.close() def save(self): """called when user save a project""" if self.activeProjekt() and self.activeProjekt().save(): self.statusBar().showMessage("File saved", 2000) else: self.statusBar().showMessage("Error when trying to save the file") def saveAs(self): """called when user save AS a project""" if self.activeProjekt() and self.activeProjekt().saveAs(): self.statusBar().showMessage("File saved", 2000) else: self.statusBar().showMessage("Error when trying to save the file") def openFolder(self): """called when user calls 'reveal in finder' function""" if self.activeProjekt() and self.activeProjekt().openFolder(): self.statusBar().showMessage("File revealed in Finder", 2000) def about(self): """called when user wants to know a bit more on the app""" import sys python_version = str(sys.version_info[0]) python_version_temp = sys.version_info[1:5] for item in python_version_temp: python_version = python_version + "." + str(item) QMessageBox.about(self, "About Lekture", "pylekture build " + str(pylekture.__version__ + "\n" + \ "python version " + str(python_version))) def updateMenus(self): """update menus""" hasProjekt = (self.activeProjekt() is not None) self.saveAct.setEnabled(hasProjekt) self.saveAsAct.setEnabled(hasProjekt) self.outputsAct.setEnabled(hasProjekt) self.scenarioAct.setEnabled(hasProjekt) self.openFolderAct.setEnabled(hasProjekt) self.closeAct.setEnabled(hasProjekt) self.closeAllAct.setEnabled(hasProjekt) self.nextAct.setEnabled(hasProjekt) self.previousAct.setEnabled(hasProjekt) self.separatorAct.setVisible(hasProjekt) def updateWindowMenu(self): """unpates menus on the window toolbar""" self.windowMenu.clear() self.windowMenu.addAction(self.closeAct) self.windowMenu.addAction(self.closeAllAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.nextAct) self.windowMenu.addAction(self.previousAct) self.windowMenu.addAction(self.separatorAct) windows = self.mdiArea.subWindowList() self.separatorAct.setVisible(len(windows) != 0) for i, window in enumerate(windows): child = window.widget() text = "%d %s" % (i + 1, child.userFriendlyCurrentFile()) if i < 9: text = '&' + text action = self.windowMenu.addAction(text) action.setCheckable(True) action.setChecked(child is self.activeProjekt()) action.triggered.connect(self.windowMapper.map) self.windowMapper.setMapping(action, window) def createProjekt(self): """create a new project""" child = Projekt() self.mdiArea.addSubWindow(child) self.child = child return child def createActions(self): """create all actions""" self.newAct = QAction("&New", self, shortcut=QKeySequence.New, statusTip="Create a new file", triggered=self.newFile) self.openAct = QAction("&Open...", self, shortcut=QKeySequence.Open, statusTip="Open an existing file", triggered=self.open) self.saveAct = QAction("&Save", self, shortcut=QKeySequence.Save, statusTip="Save the document to disk", triggered=self.save) self.saveAsAct = QAction("Save &As...", self, shortcut=QKeySequence.SaveAs, statusTip="Save the document under a new name", triggered=self.saveAs) self.openFolderAct = QAction("Open Project Folder", self, statusTip="Reveal Project in Finder", triggered=self.openFolder) self.exitAct = QAction("E&xit", self, shortcut=QKeySequence.Quit, statusTip="Exit the application", triggered=QApplication.instance().closeAllWindows) self.closeAct = QAction("Cl&ose", self, statusTip="Close the active window", triggered=self.mdiArea.closeActiveSubWindow) self.outputsAct = QAction("Outputs", self, statusTip="Open the outputs panel", triggered=self.openOutputsPanel) self.scenarioAct = QAction("Scenario", self, statusTip="Open the scenario panel", triggered=self.openScenarioPanel) self.closeAllAct = QAction("Close &All", self, statusTip="Close all the windows", triggered=self.mdiArea.closeAllSubWindows) self.nextAct = QAction("Ne&xt", self, shortcut=QKeySequence.NextChild, statusTip="Move the focus to the next window", triggered=self.mdiArea.activateNextSubWindow) self.previousAct = QAction("Pre&vious", self, shortcut=QKeySequence.PreviousChild, statusTip="Move the focus to the previous window", triggered=self.mdiArea.activatePreviousSubWindow) self.separatorAct = QAction(self) self.separatorAct.setSeparator(True) self.aboutAct = QAction("&About", self, statusTip="Show the application's About box", triggered=self.about) def createMenus(self): """create all menus""" self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addAction(self.newAct) self.fileMenu.addAction(self.openAct) self.fileMenu.addAction(self.saveAct) self.fileMenu.addAction(self.saveAsAct) self.fileMenu.addSeparator() self.fileMenu.addAction(self.openFolderAct) self.fileMenu.addAction(self.exitAct) self.viewMenu = self.menuBar().addMenu("&View") self.viewMenu.addAction(self.outputsAct) self.viewMenu.addAction(self.scenarioAct) self.windowMenu = self.menuBar().addMenu("&Window") self.updateWindowMenu() self.windowMenu.aboutToShow.connect(self.updateWindowMenu) self.menuBar().addSeparator() self.helpMenu = self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.aboutAct) def createStatusBar(self): """create the status bar""" self.statusBar().showMessage("Ready") def readSettings(self): """read the settings""" settings = QSettings('Pixel Stereo', 'lekture') pos = settings.value('pos', QPoint(200, 200)) size = settings.value('size', QSize(1000, 650)) self.move(pos) self.resize(size) def writeSettings(self): """write settings""" settings = QSettings('Pixel Stereo', 'lekture') settings.setValue('pos', self.pos()) settings.setValue('size', self.size()) def activeProjekt(self): """return the active project object""" activeSubWindow = self.mdiArea.activeSubWindow() if activeSubWindow: return activeSubWindow.widget() else: return None def findProjekt(self, fileName): """return the project""" canonicalFilePath = QFileInfo(fileName).canonicalFilePath() for window in self.mdiArea.subWindowList(): if window.widget().currentFile() == canonicalFilePath: return window return None def setActiveSubWindow(self, window): """set the active sub window""" if window: self.mdiArea.setActiveSubWindow(window) def openOutputsPanel(self): """switch to the outputs editor""" if self.child: project = self.activeProjekt() project.scenario_events_group.setVisible(False) project.outputs_group.setVisible(True) self.scenarioAct.setVisible(True) self.outputsAct.setVisible(False) def openScenarioPanel(self): """switch to the scenario editors""" if self.child: project = self.activeProjekt() project.outputs_group.setVisible(False) project.scenario_events_group.setVisible(True) self.scenarioAct.setVisible(False) self.outputsAct.setVisible(True)
class EditorMainWindow(object): def __init__(self): self.seq = 0 self.widget = loadUi(MAIN_UI_PATH) self.init_mdi() self.init_actions() self.init_instance() self.widget.closeEvent = self.close_handler self.widget.showMaximized() def get_seq(self): self.seq += 1 return self.seq def init_mdi(self): self.mdi = QMdiArea(self.widget) self.mdi.setViewMode(QMdiArea.TabbedView) self.mdi.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdi.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdi.setTabsMovable(True) self.mdi.setTabsClosable(True) self.mdi.setTabShape(QTabWidget.Rounded) self.widget.setCentralWidget(self.mdi) def init_actions(self): self.widget.actionNew.triggered.connect(self.action_new_handler) self.widget.actionOpen.triggered.connect(self.action_open_handler) self.widget.actionSave.triggered.connect(self.action_save_handler) self.widget.actionSave_As.triggered.connect(self.action_save_as_handler) self.widget.actionClose.triggered.connect(self.action_close_handler) self.widget.actionClose_All.triggered.connect(self.action_close_all_handler) self.widget.actionExport.triggered.connect(self.action_export_handler) self.widget.actionStates.triggered.connect(self.action_states_handler) self.widget.actionEvents.triggered.connect(self.action_events_handler) def close_handler(self, ev): l = self.mdi.subWindowList() if len(l) != 0: self.mdi.closeAllSubWindows() ev.ignore() def init_instance(self): self.instances = [] def remove_instance(self, ins): self.instances.remove(ins) def find_non_existing_name(self): while True: tmp_path = os.path.join( config.src_path, "NewFsm" + str(self.get_seq()) + FSM_FILE_EXT) if not os.path.exists(tmp_path): return tmp_path def action_new_handler(self): tmp_path = self.find_non_existing_name() m = FsmModel() m.default_init() vm = InstanceVM(m, self, tmp_path) vm.set_modified(True) def file_already_open(self, pth): for i in self.instances: pth = os.path.abspath(pth) if pth == i.file_path: return i return None def action_open_handler(self): p = QFileDialog() p.setViewMode(QFileDialog.List) p.setFileMode(QFileDialog.ExistingFiles) p.setDirectory(config.src_path) p.exec() paths = p.selectedFiles() for pth in paths: i = self.file_already_open(pth) if i: self.mdi.setActiveSubWindow(i.sub_window) else: m = FsmModel.load_file(pth) vm = InstanceVM(m, self, pth) def action_save_handler(self): w = self.mdi.activeSubWindow() if w is None: return model = w.instance.model model.dump_file(w.instance.file_path) w.instance.set_modified(False) def action_save_as_handler(self): w = self.mdi.activeSubWindow() if w is None: return p = QFileDialog() p.setViewMode(QFileDialog.List) p.setDirectory(config.src_path) p.exec() paths = p.selectedFiles() if len(paths) == 0: return w.instance.file_path = os.path.abspath(paths[0]) w.instance.update_title() model = w.instance.model model.dump_file(w.instance.file_path) w.instance.set_modified(False) def action_close_handler(self): w = self.mdi.activeSubWindow() if w is None: return w.close() def action_close_all_handler(self): self.mdi.closeAllSubWindows() def action_export_handler(self): fsm_files = os.listdir(config.src_path) for fn in fsm_files: full_name = os.path.join(config.src_path, fn) b, e = os.path.splitext(full_name) if e == FSM_FILE_EXT: f = open(full_name, "rb") basename, e = os.path.splitext(fn) model_object = pickle.load(f) f.close() exporter = FsmModelPythonExporter(model_object) exporter.export(os.path.join(config.export_path, basename + "_fsm.py")) def action_states_handler(self): cur = self.get_current_instance() if cur is None: return model = cur.model w = loadUi(STATE_LIST_DIALOG_PATH) list_vm = MultiColumnListModel( model.state, LIST_DIALOG_COLUMNS, STATE_DIALOG_HEADERS) add_item = functools.partial(model.add_item, StateItem, "state") remove_item = functools.partial(model.remove_item, "state") dialog = StateListPanelVM( list_vm, model.state, add_item, remove_item, w) dialog.run() cur.table_vm.refresh() def action_events_handler(self): cur = self.get_current_instance() if cur is None: return model = cur.model w = loadUi(EVENT_DIALOG_PATH) list_vm = MultiColumnListModel( model.event, LIST_DIALOG_COLUMNS, EVENT_DIALOG_HEADERS) add_item = functools.partial(model.add_item, EventItem, "event") remove_item = functools.partial(model.remove_item, "event") dialog = ListEditPanelVM( list_vm, model.event, add_item, remove_item, w) dialog.run() cur.table_vm.refresh() def get_current_instance(self): current = self.mdi.activeSubWindow() if not current: return None for i in self.instances: if i.sub_window == current: return i assert(False) # there is an active sub window but there's no matching instance
class MyMainWindow(QMainWindow): window_index = 1 def __init__(self): super(QMainWindow, self).__init__() self.mdi_area = QMdiArea() self.setCentralWidget(self.mdi_area) self.__init_menu() def __init_menu(self): menu_bar = self.menuBar() file_menu = menu_bar.addMenu('File') open_action = QAction('Open', self) open_action.setShortcut('Ctrl+O') open_action.triggered.connect(self.__on_open) file_menu.addAction(open_action) exit_action = QAction('Exit', self) exit_action.triggered.connect(self.close) file_menu.addAction(exit_action) window_menu = menu_bar.addMenu('Windows') close_current_action = QAction('Close Current Window', self) close_current_action.triggered.connect(self.mdi_area.closeActiveSubWindow) window_menu.addAction(close_current_action) close_all_action = QAction('Close All', self) close_all_action.triggered.connect(self.mdi_area.closeAllSubWindows) window_menu.addAction(close_all_action) cascade_action = QAction('Cascade Windows', self) cascade_action.triggered.connect(self.mdi_area.cascadeSubWindows) window_menu.addAction(cascade_action) tile_action = QAction('Title Windows', self) tile_action.triggered.connect(self.mdi_area.tileSubWindows) window_menu.addAction(tile_action) self.__window_list_menu = window_menu.addMenu('Window List') self.__window_list_menu.aboutToShow.connect(self.__window_list_menu_about_to_show) def __window_list_menu_about_to_show(self): self.__window_list_menu.clear() windows = self.mdi_area.subWindowList() index = 1 for window in windows: action = QAction(str(index) + '. ' + window.windowTitle(), self.__window_list_menu) action.setProperty('WindowObject', window) action.triggered.connect(self.__on_select_window) self.__window_list_menu.addAction(action) index += 1 def __on_select_window(self): action = self.sender() window = action.property('WindowObject') self.mdi_area.setActiveSubWindow(window) def __on_open(self): window = QMdiSubWindow() window.setAttribute(Qt.WA_DeleteOnClose, True) window.setWindowTitle('Sub Window ' + str(MyMainWindow.window_index)) window.resize(300, 200) self.mdi_area.addSubWindow(window) window.show() MyMainWindow.window_index += 1
class EditorMainWindow(object): def __init__(self): self.seq = 0 self.widget = loadUi(MAIN_UI_PATH) self.init_mdi() self.init_actions() self.init_instance() self.widget.closeEvent = self.close_handler self.widget.showMaximized() def get_seq(self): self.seq += 1 return self.seq def init_mdi(self): self.mdi = QMdiArea(self.widget) self.mdi.setViewMode(QMdiArea.TabbedView) self.mdi.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdi.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdi.setTabsMovable(True) self.mdi.setTabsClosable(True) self.mdi.setTabShape(QTabWidget.Rounded) self.widget.setCentralWidget(self.mdi) def init_actions(self): self.widget.actionNew.triggered.connect(self.action_new_handler) self.widget.actionOpen.triggered.connect(self.action_open_handler) self.widget.actionSave.triggered.connect(self.action_save_handler) self.widget.actionSave_As.triggered.connect( self.action_save_as_handler) self.widget.actionClose.triggered.connect(self.action_close_handler) self.widget.actionClose_All.triggered.connect( self.action_close_all_handler) self.widget.actionExport.triggered.connect(self.action_export_handler) self.widget.actionStates.triggered.connect(self.action_states_handler) self.widget.actionEvents.triggered.connect(self.action_events_handler) def close_handler(self, ev): l = self.mdi.subWindowList() if len(l) != 0: self.mdi.closeAllSubWindows() ev.ignore() def init_instance(self): self.instances = [] def remove_instance(self, ins): self.instances.remove(ins) def find_non_existing_name(self): while True: tmp_path = os.path.join( config.src_path, "NewFsm" + str(self.get_seq()) + FSM_FILE_EXT) if not os.path.exists(tmp_path): return tmp_path def action_new_handler(self): tmp_path = self.find_non_existing_name() m = FsmModel() m.default_init() vm = InstanceVM(m, self, tmp_path) vm.set_modified(True) def file_already_open(self, pth): for i in self.instances: pth = os.path.abspath(pth) if pth == i.file_path: return i return None def action_open_handler(self): p = QFileDialog() p.setViewMode(QFileDialog.List) p.setFileMode(QFileDialog.ExistingFiles) p.setDirectory(config.src_path) p.exec() paths = p.selectedFiles() for pth in paths: i = self.file_already_open(pth) if i: self.mdi.setActiveSubWindow(i.sub_window) else: m = FsmModel.load_file(pth) vm = InstanceVM(m, self, pth) def action_save_handler(self): w = self.mdi.activeSubWindow() if w is None: return model = w.instance.model model.dump_file(w.instance.file_path) w.instance.set_modified(False) def action_save_as_handler(self): w = self.mdi.activeSubWindow() if w is None: return p = QFileDialog() p.setViewMode(QFileDialog.List) p.setDirectory(config.src_path) p.exec() paths = p.selectedFiles() if len(paths) == 0: return w.instance.file_path = os.path.abspath(paths[0]) w.instance.update_title() model = w.instance.model model.dump_file(w.instance.file_path) w.instance.set_modified(False) def action_close_handler(self): w = self.mdi.activeSubWindow() if w is None: return w.close() def action_close_all_handler(self): self.mdi.closeAllSubWindows() def action_export_handler(self): fsm_files = os.listdir(config.src_path) for fn in fsm_files: full_name = os.path.join(config.src_path, fn) b, e = os.path.splitext(full_name) if e == FSM_FILE_EXT: f = open(full_name, "rb") basename, e = os.path.splitext(fn) model_object = pickle.load(f) f.close() exporter = FsmModelPythonExporter(model_object) exporter.export( os.path.join(config.export_path, basename + "_fsm.py")) def action_states_handler(self): cur = self.get_current_instance() if cur is None: return model = cur.model w = loadUi(STATE_LIST_DIALOG_PATH) list_vm = MultiColumnListModel(model.state, LIST_DIALOG_COLUMNS, STATE_DIALOG_HEADERS) add_item = functools.partial(model.add_item, StateItem, "state") remove_item = functools.partial(model.remove_item, "state") dialog = StateListPanelVM(list_vm, model.state, add_item, remove_item, w) dialog.run() cur.table_vm.refresh() def action_events_handler(self): cur = self.get_current_instance() if cur is None: return model = cur.model w = loadUi(EVENT_DIALOG_PATH) list_vm = MultiColumnListModel(model.event, LIST_DIALOG_COLUMNS, EVENT_DIALOG_HEADERS) add_item = functools.partial(model.add_item, EventItem, "event") remove_item = functools.partial(model.remove_item, "event") dialog = ListEditPanelVM(list_vm, model.event, add_item, remove_item, w) dialog.run() cur.table_vm.refresh() def get_current_instance(self): current = self.mdi.activeSubWindow() if not current: return None for i in self.instances: if i.sub_window == current: return i assert ( False ) # there is an active sub window but there's no matching instance
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.mdi = QMdiArea() self.setCentralWidget(self.mdi) fileNewAction = self.createAction("&New", self.fileNew, QKeySequence.New, "filenew", "Create a text file") fileOpenAction = self.createAction("&Open...", self.fileOpen, QKeySequence.Open, "fileopen", "Open an existing text file") fileToolbar = self.addToolBar("File") fileToolbar.setObjectName("FileToolbar") self.addActions(fileToolbar, (fileNewAction, fileOpenAction)) def createAction(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/{0}.png".format(icon))) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: action.triggered.connect(slot) if checkable: action.setCheckable(True) return action def addActions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) #@profile def fileNew(self): try: print( u'openSystemConfig内存使用:', round( psutil.Process(getpid()).memory_info().rss / 1024 / 1024, 4)) objgraph.show_growth(shortnames=False) self.taskConfigWindow = Ui_QTaskConfigWindow() self.mdi.addSubWindow(self.taskConfigWindow).show() except Exception as e: print(print_exc()) def fileOpen(self): for win_temp in self.mdi.subWindowList(): win_temp_widget = win_temp.widget() if (win_temp_widget is not None) and (isinstance( win_temp_widget, Ui_QTaskConfigWindow)): self.mdi.setActiveSubWindow(win_temp) self.mdi.closeActiveSubWindow() self.taskConfigWindow = None
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.mdiArea = QMdiArea() self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setCentralWidget(self.mdiArea) self.mdiArea.subWindowActivated.connect(self.updateMenus) self.windowMapper = QSignalMapper(self) self.windowMapper.mapped[QWidget].connect(self.setActiveSubWindow) self.createActions() self.createMenus() self.createStatusBar() self.updateMenus() self.clipboard = QApplication.clipboard() self.setWindowTitle("Qt5 Multi Video Player v0.02 - by Luis Santos AKA DJOKER") def closeEvent(self, event): self.mdiArea.closeAllSubWindows() if self.mdiArea.currentSubWindow(): event.ignore() else: event.accept() def newFile(self): child = VideoPlayer(True) self.mdiArea.addSubWindow(child) url = self.clipboard.text() child.Player(url) child.show() def newMute(self): child = VideoPlayer(False) self.mdiArea.addSubWindow(child) url = self.clipboard.text() child.Player(url) child.show() return def updateMenus(self): hasMdiChild = (self.activeMdiChild() is not None) self.closeAct.setEnabled(hasMdiChild) self.closeAllAct.setEnabled(hasMdiChild) self.tileAct.setEnabled(hasMdiChild) self.cascadeAct.setEnabled(hasMdiChild) self.nextAct.setEnabled(hasMdiChild) self.previousAct.setEnabled(hasMdiChild) self.separatorAct.setVisible(hasMdiChild) def updateWindowMenu(self): self.windowMenu.clear() self.windowMenu.addAction(self.closeAct) self.windowMenu.addAction(self.closeAllAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.tileAct) self.windowMenu.addAction(self.cascadeAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.nextAct) self.windowMenu.addAction(self.previousAct) self.windowMenu.addAction(self.separatorAct) windows = self.mdiArea.subWindowList() self.separatorAct.setVisible(len(windows) != 0) def createMdiChild(self): child = MdiChild() self.mdiArea.addSubWindow(child) return child def createActions(self): self.newAct = QAction( "&New", self, shortcut=QKeySequence.New, statusTip="Create a new Video Player", triggered=self.newFile) self.newActCam4 = QAction("&VideoMute", self, shortcut=QKeySequence.New, statusTip="Create a new Video Player Mute", triggered=self.newMute) self.closeAct = QAction("Cl&ose", self, statusTip="Close the active window", triggered=self.mdiArea.closeActiveSubWindow) self.closeAllAct = QAction("Close &All", self, statusTip="Close all the windows", triggered=self.mdiArea.closeAllSubWindows) self.tileAct = QAction("&Tile", self, statusTip="Tile the windows", triggered=self.mdiArea.tileSubWindows) self.cascadeAct = QAction("&Cascade", self, statusTip="Cascade the windows", triggered=self.mdiArea.cascadeSubWindows) self.nextAct = QAction("Ne&xt", self, shortcut=QKeySequence.NextChild, statusTip="Move the focus to the next window", triggered=self.mdiArea.activateNextSubWindow) self.previousAct = QAction("Pre&vious", self, shortcut=QKeySequence.PreviousChild, statusTip="Move the focus to the previous window", triggered=self.mdiArea.activatePreviousSubWindow) self.separatorAct = QAction(self) self.separatorAct.setSeparator(True) def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addAction(self.newAct) self.fileMenu.addAction(self.newActCam4) self.exitAct = QAction("E&xit", self, shortcut=QKeySequence.Quit, statusTip="Exit the application", triggered=QApplication.instance().closeAllWindows) self.fileMenu.addSeparator() action = self.fileMenu.addAction("Switch layout direction") action.triggered.connect(self.switchLayoutDirection) self.fileMenu.addAction(self.exitAct) self.windowMenu = self.menuBar().addMenu("&Window") self.updateWindowMenu() self.windowMenu.aboutToShow.connect(self.updateWindowMenu) self.menuBar().addSeparator() def createStatusBar(self): self.statusBar().showMessage("Ready") def activeMdiChild(self): activeSubWindow = self.mdiArea.activeSubWindow() if activeSubWindow: return activeSubWindow.widget() return None def findMdiChild(self, fileName): canonicalFilePath = QFileInfo(fileName).canonicalFilePath() for window in self.mdiArea.subWindowList(): if window.widget().currentFile() == canonicalFilePath: return window return None def switchLayoutDirection(self): if self.layoutDirection() == Qt.LeftToRight: QApplication.setLayoutDirection(Qt.RightToLeft) else: QApplication.setLayoutDirection(Qt.LeftToRight) def setActiveSubWindow(self, window): if window: self.mdiArea.setActiveSubWindow(window)
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.mdiArea = QMdiArea() self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setCentralWidget(self.mdiArea) self.mdiArea.subWindowActivated.connect(self.updateMenus) self.windowMapper = QSignalMapper(self) self.windowMapper.mapped[QWidget].connect(self.setActiveSubWindow) self.createActions() self.createMenus() self.createToolBars() self.createStatusBar() self.updateMenus() self.readSettings() self.setWindowTitle("MDI") def closeEvent(self, event): self.mdiArea.closeAllSubWindows() if self.mdiArea.currentSubWindow(): event.ignore() else: self.writeSettings() event.accept() def newFile(self): child = self.createMdiChild() child.newFile() child.show() def open(self): fileName, _ = QFileDialog.getOpenFileName(self) if fileName: existing = self.findMdiChild(fileName) if existing: self.mdiArea.setActiveSubWindow(existing) return child = self.createMdiChild() if child.loadFile(fileName): self.statusBar().showMessage("File loaded", 2000) child.show() else: child.close() def save(self): if self.activeMdiChild() and self.activeMdiChild().save(): self.statusBar().showMessage("File saved", 2000) def saveAs(self): if self.activeMdiChild() and self.activeMdiChild().saveAs(): self.statusBar().showMessage("File saved", 2000) def cut(self): if self.activeMdiChild(): self.activeMdiChild().cut() def copy(self): if self.activeMdiChild(): self.activeMdiChild().copy() def paste(self): if self.activeMdiChild(): self.activeMdiChild().paste() def about(self): QMessageBox.about( self, "About MDI", "The <b>MDI</b> example demonstrates how to write multiple " "document interface applications using Qt.") def updateMenus(self): hasMdiChild = (self.activeMdiChild() is not None) self.saveAct.setEnabled(hasMdiChild) self.saveAsAct.setEnabled(hasMdiChild) self.pasteAct.setEnabled(hasMdiChild) self.closeAct.setEnabled(hasMdiChild) self.closeAllAct.setEnabled(hasMdiChild) self.tileAct.setEnabled(hasMdiChild) self.cascadeAct.setEnabled(hasMdiChild) self.nextAct.setEnabled(hasMdiChild) self.previousAct.setEnabled(hasMdiChild) self.separatorAct.setVisible(hasMdiChild) hasSelection = (self.activeMdiChild() is not None and self.activeMdiChild().textCursor().hasSelection()) self.cutAct.setEnabled(hasSelection) self.copyAct.setEnabled(hasSelection) def updateWindowMenu(self): self.windowMenu.clear() self.windowMenu.addAction(self.closeAct) self.windowMenu.addAction(self.closeAllAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.tileAct) self.windowMenu.addAction(self.cascadeAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.nextAct) self.windowMenu.addAction(self.previousAct) self.windowMenu.addAction(self.separatorAct) windows = self.mdiArea.subWindowList() self.separatorAct.setVisible(len(windows) != 0) for i, window in enumerate(windows): child = window.widget() text = "%d %s" % (i + 1, child.userFriendlyCurrentFile()) if i < 9: text = '&' + text action = self.windowMenu.addAction(text) action.setCheckable(True) action.setChecked(child is self.activeMdiChild()) action.triggered.connect(self.windowMapper.map) self.windowMapper.setMapping(action, window) def createMdiChild(self): child = MdiChild() self.mdiArea.addSubWindow(child) child.copyAvailable.connect(self.cutAct.setEnabled) child.copyAvailable.connect(self.copyAct.setEnabled) return child def createActions(self): self.newAct = QAction(QIcon(':/images/new.png'), "&New", self, shortcut=QKeySequence.New, statusTip="Create a new file", triggered=self.newFile) self.openAct = QAction(QIcon(':/images/open.png'), "&Open...", self, shortcut=QKeySequence.Open, statusTip="Open an existing file", triggered=self.open) self.saveAct = QAction(QIcon(':/images/save.png'), "&Save", self, shortcut=QKeySequence.Save, statusTip="Save the document to disk", triggered=self.save) self.saveAsAct = QAction( "Save &As...", self, shortcut=QKeySequence.SaveAs, statusTip="Save the document under a new name", triggered=self.saveAs) self.exitAct = QAction( "E&xit", self, shortcut=QKeySequence.Quit, statusTip="Exit the application", triggered=QApplication.instance().closeAllWindows) self.cutAct = QAction( QIcon(':/images/cut.png'), "Cu&t", self, shortcut=QKeySequence.Cut, statusTip="Cut the current selection's contents to the clipboard", triggered=self.cut) self.suggestAct = QAction( "Suggest", self, shortcut=QKeySequence.Copy, statusTip="Cut the current selection's contents to the clipboard", triggered=self.copy) self.copyAct = QAction( QIcon(':/images/copy.png'), "&Copy", self, shortcut=QKeySequence.Copy, statusTip="Copy the current selection's contents to the clipboard", triggered=self.copy) self.pasteAct = QAction( QIcon(':/images/paste.png'), "&Paste", self, shortcut=QKeySequence.Paste, statusTip= "Paste the clipboard's contents into the current selection", triggered=self.paste) self.closeAct = QAction("Cl&ose", self, statusTip="Close the active window", triggered=self.mdiArea.closeActiveSubWindow) self.closeAllAct = QAction("Close &All", self, statusTip="Close all the windows", triggered=self.mdiArea.closeAllSubWindows) self.tileAct = QAction("&Tile", self, statusTip="Tile the windows", triggered=self.mdiArea.tileSubWindows) self.cascadeAct = QAction("&Cascade", self, statusTip="Cascade the windows", triggered=self.mdiArea.cascadeSubWindows) self.nextAct = QAction("Ne&xt", self, shortcut=QKeySequence.NextChild, statusTip="Move the focus to the next window", triggered=self.mdiArea.activateNextSubWindow) self.previousAct = QAction( "Pre&vious", self, shortcut=QKeySequence.PreviousChild, statusTip="Move the focus to the previous window", triggered=self.mdiArea.activatePreviousSubWindow) self.separatorAct = QAction(self) self.separatorAct.setSeparator(True) self.aboutAct = QAction("&About", self, statusTip="Show the application's About box", triggered=self.about) self.aboutQtAct = QAction("About &Qt", self, statusTip="Show the Qt library's About box", triggered=QApplication.instance().aboutQt) def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addAction(self.newAct) self.fileMenu.addAction(self.openAct) self.fileMenu.addAction(self.saveAct) self.fileMenu.addAction(self.saveAsAct) self.fileMenu.addSeparator() action = self.fileMenu.addAction("Switch layout direction") action.triggered.connect(self.switchLayoutDirection) self.fileMenu.addAction(self.exitAct) self.editMenu = self.menuBar().addMenu("&Edit") self.editMenu.addAction(self.cutAct) self.editMenu.addAction(self.copyAct) self.editMenu.addAction(self.pasteAct) self.windowMenu = self.menuBar().addMenu("&Window") self.updateWindowMenu() self.windowMenu.aboutToShow.connect(self.updateWindowMenu) self.menuBar().addSeparator() self.helpMenu = self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.aboutAct) self.helpMenu.addAction(self.aboutQtAct) def createToolBars(self): self.fileToolBar = self.addToolBar("File") self.fileToolBar.addAction(self.newAct) self.fileToolBar.addAction(self.openAct) self.fileToolBar.addAction(self.saveAct) self.editToolBar = self.addToolBar("Edit") self.editToolBar.addAction(self.cutAct) self.editToolBar.addAction(self.copyAct) self.editToolBar.addAction(self.pasteAct) def createStatusBar(self): self.statusBar().showMessage("Ready") def readSettings(self): settings = QSettings('Trolltech', 'MDI Example') pos = settings.value('pos', QPoint(200, 200)) size = settings.value('size', QSize(400, 400)) self.move(pos) self.resize(size) def writeSettings(self): settings = QSettings('Trolltech', 'MDI Example') settings.setValue('pos', self.pos()) settings.setValue('size', self.size()) def activeMdiChild(self): activeSubWindow = self.mdiArea.activeSubWindow() if activeSubWindow: return activeSubWindow.widget() return None def findMdiChild(self, fileName): canonicalFilePath = QFileInfo(fileName).canonicalFilePath() for window in self.mdiArea.subWindowList(): if window.widget().currentFile() == canonicalFilePath: return window return None def switchLayoutDirection(self): if self.layoutDirection() == Qt.LeftToRight: QApplication.setLayoutDirection(Qt.RightToLeft) else: QApplication.setLayoutDirection(Qt.LeftToRight) def setActiveSubWindow(self, window): if window: self.mdiArea.setActiveSubWindow(window) def contextMenuEvent(self, event): menu = QMenu(self) menu.addAction(self.cutAct) menu.addAction(self.copyAct) menu.addAction(self.pasteAct) menu.addAction(self.suggestAct) menu.exec_(event.globalPos())
class appWindow(QMainWindow): """ Application entry point, subclasses QMainWindow and implements the main widget, sets necessary window behaviour etc. """ def __init__(self, parent=None): super(appWindow, self).__init__(parent) #create the menu bar self.createMenuBar() self.mdi = QMdiArea(self) #create area for files to be displayed self.mdi.setObjectName('mdi area') #create toolbar and add the toolbar plus mdi to layout self.createToolbar() #set flags so that window doesnt look weird self.mdi.setOption(QMdiArea.DontMaximizeSubWindowOnActivation, True) self.mdi.setTabsClosable(True) self.mdi.setTabsMovable(True) self.mdi.setDocumentMode(False) #declare main window layout self.setCentralWidget(self.mdi) # self.resize(1280, 720) #set collapse dim self.mdi.subWindowActivated.connect(self.tabSwitched) self.readSettings() def createMenuBar(self): # Fetches a reference to the menu bar in the main window, and adds actions to it. titleMenu = self.menuBar() #fetch reference to current menu bar self.menuFile = titleMenu.addMenu('File') #File Menu newAction = self.menuFile.addAction("New", self.newProject) openAction = self.menuFile.addAction("Open", self.openProject) saveAction = self.menuFile.addAction("Save", self.saveProject) newAction.setShortcut(QKeySequence.New) openAction.setShortcut(QKeySequence.Open) saveAction.setShortcut(QKeySequence.Save) self.menuEdit = titleMenu.addMenu('Edit') undoAction = self.undo = self.menuEdit.addAction( "Undo", lambda x=self: x.activeScene.painter.undoAction.trigger()) redoAction = self.redo = self.menuEdit.addAction( "Redo", lambda x=self: x.activeScene.painter.redoAction.trigger()) undoAction.setShortcut(QKeySequence.Undo) redoAction.setShortcut(QKeySequence.Redo) self.menuEdit.addAction( "Show Undo Stack", lambda x=self: x.activeScene.painter.createUndoView(self)) self.menuEdit.addSeparator() self.menuEdit.addAction("Add new symbols", self.addSymbolWindow) self.menuGenerate = titleMenu.addMenu('Generate') #Generate menu imageAction = self.menuGenerate.addAction("Image", self.saveImage) reportAction = self.menuGenerate.addAction("Report", self.generateReport) imageAction.setShortcut(QKeySequence("Ctrl+P")) reportAction.setShortcut(QKeySequence("Ctrl+R")) def createToolbar(self): #place holder for toolbar with fixed width, layout may change self.toolbar = toolbar(self) self.toolbar.setObjectName("Toolbar") # self.addToolBar(Qt.LeftToolBarArea, self.toolbar) self.addDockWidget(Qt.LeftDockWidgetArea, self.toolbar) self.toolbar.toolbuttonClicked.connect(self.toolButtonClicked) self.toolbar.populateToolbar() def toolButtonClicked(self, object): # To add the corresponding symbol for the clicked button to active scene. if self.mdi.currentSubWindow(): currentDiagram = self.mdi.currentSubWindow().tabber.currentWidget( ).painter if currentDiagram: graphic = getattr(shapes, object['object'])(*map( lambda x: int(x) if x.isdigit() else x, object['args'])) graphic.setPos(50, 50) currentDiagram.addItemPlus(graphic) def addSymbolWindow(self): # Opens the add symbol window when requested from utils.custom import ShapeDialog ShapeDialog(self).exec() def newProject(self): #call to create a new file inside mdi area project = FileWindow(self.mdi) project.setObjectName("New Project") self.mdi.addSubWindow(project) if not project.tabList: # important when unpickling a file instead project.newDiagram() #create a new tab in the new file project.fileCloseEvent.connect( self.fileClosed) #closed file signal to switch to sub window view if self.count > 1: #switch to tab view if needed self.mdi.setViewMode(QMdiArea.TabbedView) project.show() def openProject(self): #show the open file dialog to open a saved file, then unpickle it. name = QFileDialog.getOpenFileNames(self, 'Open File(s)', '', 'Process Flow Diagram (*pfd)') if name: for files in name[0]: with open(files, 'r') as file: projectData = load(file) project = FileWindow(self.mdi) self.mdi.addSubWindow(project) #create blank window and set its state project.__setstate__(projectData) project.resizeHandler() project.fileCloseEvent.connect(self.fileClosed) project.show() if self.count > 1: # self.tabSpace.setVisible(True) self.mdi.setViewMode(QMdiArea.TabbedView) def saveProject(self): #serialize all files in mdi area for j, i in enumerate(self.activeFiles ): #get list of all windows with atleast one tab if i.tabCount: name = QFileDialog.getSaveFileName( self, 'Save File', f'New Diagram {j}', 'Process Flow Diagram (*.pfd)') i.saveProject(name) else: return False return True def saveImage(self): #place holder for future implementaion pass def generateReport(self): #place holder for future implementaion pass def tabSwitched(self, window): #handle window switched edge case if window and window.tabCount: window.resizeHandler() def resizeEvent(self, event): #overload resize to also handle resize on file windows inside for i in self.mdi.subWindowList(): i.resizeHandler() self.toolbar.resize() super(appWindow, self).resizeEvent(event) def closeEvent(self, event): #save alert on window close if len(self.activeFiles) and not dialogs.saveEvent(self): event.ignore() else: event.accept() self.writeSettings() def fileClosed(self, index): #checks if the file tab menu needs to be removed if self.count <= 2: self.mdi.setViewMode(QMdiArea.SubWindowView) def writeSettings(self): # write window state on window close settings.beginGroup("MainWindow") settings.setValue("maximized", self.isMaximized()) if not self.isMaximized(): settings.setValue("size", self.size()) settings.setValue("pos", self.pos()) settings.endGroup() def readSettings(self): # read window state when app launches settings.beginGroup("MainWindow") self.resize(settings.value("size", QSize(1280, 720))) self.move(settings.value("pos", QPoint(320, 124))) if settings.value("maximized", False, type=bool): self.showMaximized() settings.endGroup() #useful one liner properties for getting data @property def activeFiles(self): return [i for i in self.mdi.subWindowList() if i.tabCount] @property def count(self): return len(self.mdi.subWindowList()) @property def activeScene(self): return self.mdi.currentSubWindow().tabber.currentWidget() #Key input handler def keyPressEvent(self, event): #overload key press event for custom keyboard shortcuts if event.modifiers() & Qt.ControlModifier: if event.key() == Qt.Key_A: #todo implement selectAll for item in self.mdi.activeSubWindow().tabber.currentWidget( ).items: item.setSelected(True) #todo copy, paste, undo redo else: return event.accept() elif event.key() == Qt.Key_Q: if self.mdi.activeSubWindow() and self.mdi.activeSubWindow( ).tabber.currentWidget(): for item in self.mdi.activeSubWindow().tabber.currentWidget( ).painter.selectedItems(): item.rotation -= 1 elif event.key() == Qt.Key_E: if self.mdi.activeSubWindow() and self.mdi.activeSubWindow( ).tabber.currentWidget(): for item in self.mdi.activeSubWindow().tabber.currentWidget( ).painter.selectedItems(): item.rotation += 1
class MainWindow(object): def __init__(self): self.main_window_tab_table = QTabWidget() self.hbox = QHBoxLayout() self.but = QPushButton('Add') self.file_menu = None self.help_menu = None self.about_qt = None self.exit_action = None self.choice_interface = None def setup_ui(self, main_window): self.main_window = main_window main_window.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) red, green, blue = 11, 7, 11 main_window.setPalette(QPalette(QColor(red, green, blue))) self.mdiArea = QMdiArea() self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.create_menu(main_window) self.create_tool_bars(main_window) main_window.setCentralWidget(self.mdiArea) self.windowMapper = QSignalMapper(main_window) def file_menu_action(self): self.exit_action = QAction(QIcon('../resources/icons/fileclose.png'), "&Exit", self.file_menu) self.exit_action.setShortcut('Ctrl+Q') self.exit_action.setStatusTip('Exit application') # self.exitAct = QAction("E&xit", self, shortcut=QKeySequence.Quit, # statusTip="Exit the application", # triggered=QApplication.instance().closeAllWindows) self.choice_interface = QAction(QIcon('../resources/icons/ethernet_card_vista.png'), '&New Table', self.file_menu) self.choice_interface.setShortcut('Ctrl+A') self.choice_interface.setStatusTip('Exit application') # create new table self.new_act = QAction(QIcon(':/images/new.png'), "&New", self.file_menu) self.new_act.setShortcut('Ctrl+Q') self.new_act.setStatusTip('Create a new file') # triggered=self.open self.open_act = QAction(QIcon(':/images/open.png'), "&Open", self.file_menu) self.open_act.setShortcut(QKeySequence.Open) self.open_act.setStatusTip('Open an existing file') # triggered=self.save self.save_act = QAction(QIcon(':/images/save.png'), "&Save", self.file_menu) self.save_act.setShortcut(QKeySequence.Save) self.save_act.setStatusTip('Save the table to disk') # triggered=self.saveAs self.save_as_act = QAction(QIcon(':/images/save.png'), "&Save &As", self.file_menu) self.save_as_act.setShortcut(QKeySequence.SaveAs) self.save_as_act.setStatusTip('Save the document under a new name') # triggered=self.cut self.cut_act = QAction(QIcon(':/images/save.png'), "&Cut", self.file_menu) self.cut_act.setShortcut(QKeySequence.Cut) self.cut_act.setStatusTip('Cut the current selections contents to the clipboard') # triggered=self.copy self.copy_act = QAction(QIcon(':/images/save.png'), "&Copy", self.file_menu) self.copy_act.setShortcut(QKeySequence.Copy) self.copy_act.setStatusTip('Copy the current selections contents to the clipboard') # triggered=self.paste self.paste_act = QAction(QIcon(':/images/save.png'), "&Paste", self.file_menu) self.paste_act.setShortcut(QKeySequence.Paste) self.paste_act.setStatusTip('Paste the clipboards contents into the current selection') self.close_act = QAction(QIcon(':/images/save.png'), "&Close", self.file_menu) self.close_act.setStatusTip('Close the active window') self.close_act.triggered.connect(self.mdiArea.closeActiveSubWindow) self.close_all_act = QAction(QIcon(':/images/save.png'), "&Close &All", self.file_menu) self.close_all_act.setStatusTip('Close all the windows') self.close_all_act.triggered.connect(self.mdiArea.closeAllSubWindows) self.tile_act = QAction(QIcon(':/images/save.png'), "&Tile", self.file_menu) self.tile_act.setStatusTip('Tile the windows') self.tile_act.triggered.connect(self.mdiArea.tileSubWindows) self.cascade_act = QAction(QIcon(':/images/save.png'), "&Cascade", self.file_menu) self.cascade_act.setStatusTip('Cascade the windows') self.cascade_act.triggered.connect(self.mdiArea.cascadeSubWindows) self.next_act = QAction(QIcon(':/images/save.png'), "&Next", self.file_menu) self.next_act.setShortcut(QKeySequence.NextChild) self.next_act.setStatusTip('Move the focus to the next window') self.next_act.triggered.connect(self.mdiArea.activateNextSubWindow) self.previous_act = QAction(QIcon(':/images/save.png'), "&Previous", self.file_menu) self.previous_act.setShortcut(QKeySequence.PreviousChild) self.previous_act.setStatusTip('Move the focus to the previous window') self.previous_act.triggered.connect(self.mdiArea.activatePreviousSubWindow) # triggered=self.about # self.separatorAct = QAction(self) # self.separatorAct.setSeparator(True) def help_menu_action(self): self.about_qt = QAction(QIcon('../resources/icons/info.png'), '&About Qt', self.help_menu) self.about_qt.setShortcut('Ctrl+L') self.about_qt.setStatusTip('Show the Qt librarys About box') self.about_qt.triggered.connect(qApp.aboutQt) # self.aboutQtAct = QAction("About &Qt", self, # statusTip="Show the Qt library's About box", # triggered=QApplication.instance().aboutQt) self.about_program_act = QAction(QIcon(':/images/save.png'), "&About Program", self.file_menu) self.about_program_act.setStatusTip('Show the applications About box') def create_menu(self, main_window): self.file_menu = main_window.menuBar().addMenu("&File") self.file_menu_action() self.file_menu.addAction(self.choice_interface) self.file_menu.addAction(self.exit_action) self.file_menu.addAction(self.new_act) self.file_menu.addAction(self.open_act) self.file_menu.addAction(self.save_act) self.file_menu.addAction(self.save_as_act) # self.fileMenu.addSeparator() self.help_menu = main_window.menuBar().addMenu("&Help") self.help_menu_action() self.help_menu.addAction(self.about_qt) self.help_menu.addAction(self.about_program_act) self.editMenu = main_window.menuBar().addMenu("&Edit") self.editMenu.addAction(self.cut_act) self.editMenu.addAction(self.copy_act) self.editMenu.addAction(self.paste_act) self.windowMenu = main_window.menuBar().addMenu("&Window") self.updateWindowMenu() self.windowMenu.aboutToShow.connect(self.updateWindowMenu) # self.menuBar().addSeparator() def about(self): QMessageBox.about(self, "About MDI", "The <b>MDI</b> example demonstrates how to write multiple " "document interface applications using Qt.") def updateMenus(self): hasMdiChild = (self.activeMdiChild() is not None) self.save_act.setEnabled(hasMdiChild) self.save_as_act.setEnabled(hasMdiChild) self.paste_act.setEnabled(hasMdiChild) self.close_act.setEnabled(hasMdiChild) self.close_all_act.setEnabled(hasMdiChild) self.tile_act.setEnabled(hasMdiChild) self.cascade_act.setEnabled(hasMdiChild) self.next_act.setEnabled(hasMdiChild) self.previous_act.setEnabled(hasMdiChild) # self.separator_act.setVisible(hasMdiChild) hasSelection = (self.activeMdiChild() is not None and self.activeMdiChild().textCursor().hasSelection()) self.cut_act.setEnabled(hasSelection) self.copy_act.setEnabled(hasSelection) def updateWindowMenu(self): self.windowMenu.clear() self.windowMenu.addAction(self.close_act) self.windowMenu.addAction(self.close_all_act) self.windowMenu.addSeparator() self.windowMenu.addAction(self.tile_act) self.windowMenu.addAction(self.cascade_act) self.windowMenu.addSeparator() self.windowMenu.addAction(self.next_act) self.windowMenu.addAction(self.previous_act) # self.windowMenu.addAction(self.separator_act) windows = self.mdiArea.subWindowList() # self.separator_act.setVisible(len(windows) != 0) for i, window in enumerate(windows): child = window.widget() text = "%d %s" % (i + 1, child.userFriendlyCurrentFile()) if i < 9: text = '&' + text action = self.windowMenu.addAction(text) action.setCheckable(True) action.setChecked(child is self.main_window.activeMdiChild()) action.triggered.connect(self.windowMapper.map) self.windowMapper.setMapping(action, window) # def switchLayoutDirection(self): # if self.layoutDirection() == Qt.LeftToRight: # QApplication.setLayoutDirection(Qt.RightToLeft) # else: # QApplication.setLayoutDirection(Qt.LeftToRight) ''' def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addAction(self.newAct) self.fileMenu.addAction(self.openAct) self.fileMenu.addAction(self.saveAct) self.fileMenu.addAction(self.saveAsAct) self.fileMenu.addSeparator() action = self.fileMenu.addAction("Switch layout direction") action.triggered.connect(self.switchLayoutDirection) self.fileMenu.addAction(self.exitAct) self.editMenu = self.menuBar().addMenu("&Edit") self.editMenu.addAction(self.cutAct) self.editMenu.addAction(self.copyAct) self.editMenu.addAction(self.pasteAct) self.windowMenu = self.menuBar().addMenu("&Window") self.updateWindowMenu() self.windowMenu.aboutToShow.connect(self.updateWindowMenu) self.menuBar().addSeparator() self.helpMenu = self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.aboutAct) self.helpMenu.addAction(self.aboutQtAct) ''' def create_tool_bars(self, main_window): self.file_tool_bar = main_window.addToolBar("File") self.file_tool_bar.addAction(self.new_act) self.file_tool_bar.addAction(self.open_act) self.file_tool_bar.addAction(self.save_act) self.edit_tool_bar = main_window.addToolBar("Edit") self.edit_tool_bar.addAction(self.cut_act) self.edit_tool_bar.addAction(self.copy_act) self.edit_tool_bar.addAction(self.paste_act)
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.mdiArea = QMdiArea() self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setCentralWidget(self.mdiArea) self.mdiArea.subWindowActivated.connect(self.updateMenus) self.windowMapper = QSignalMapper(self) self.windowMapper.mapped[QWidget].connect(self.setActiveSubWindow) self.createActions() self.createMenus() self.createStatusBar() self.updateMenus() self.setWindowTitle("MDI") def closeEvent(self, event): self.mdiArea.closeAllSubWindows() if self.mdiArea.currentSubWindow(): event.ignore() else: event.accept() def newFile(self): child = BrowserChaturbate(self.mdiArea) self.mdiArea.addSubWindow(child) child.load("https://www.chaturbate.com/") child.resize(320, 240) child.show() def newCam4(self): child = BrowserCam4(self.mdiArea) self.mdiArea.addSubWindow(child) child.load("https://www.cam4.com") child.resize(320, 240) child.show() def newFreecam(self): child = BrowserMyFreeCams(self.mdiArea) self.mdiArea.addSubWindow(child) #child.load("https://www.myfreecams.com/php/online_models_splash.php?") child.load('https://www.pornhub.com/categories?o=al') child.resize(320, 240) child.show() def updateMenus(self): hasMdiChild = (self.activeMdiChild() is not None) self.closeAct.setEnabled(hasMdiChild) self.closeAllAct.setEnabled(hasMdiChild) self.tileAct.setEnabled(hasMdiChild) self.cascadeAct.setEnabled(hasMdiChild) self.nextAct.setEnabled(hasMdiChild) self.previousAct.setEnabled(hasMdiChild) self.separatorAct.setVisible(hasMdiChild) def updateWindowMenu(self): self.windowMenu.clear() self.windowMenu.addAction(self.closeAct) self.windowMenu.addAction(self.closeAllAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.tileAct) self.windowMenu.addAction(self.cascadeAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.nextAct) self.windowMenu.addAction(self.previousAct) self.windowMenu.addAction(self.separatorAct) windows = self.mdiArea.subWindowList() self.separatorAct.setVisible(len(windows) != 0) def createActions(self): self.newAct = QAction("&Chartubate", self, shortcut=QKeySequence.New, statusTip="Browse Chartubate", triggered=self.newFile) self.newActCam4 = QAction("&Cam4", self, shortcut=QKeySequence.New, statusTip="Browse Cam4", triggered=self.newCam4) self.newActFreeCam = QAction("&PornHub", self, shortcut=QKeySequence.New, statusTip="Browse PornHub", triggered=self.newFreecam) self.closeAct = QAction("Cl&ose", self, statusTip="Close the active window", triggered=self.mdiArea.closeActiveSubWindow) self.closeAllAct = QAction("Close &All", self, statusTip="Close all the windows", triggered=self.mdiArea.closeAllSubWindows) self.tileAct = QAction("&Tile", self, statusTip="Tile the windows", triggered=self.mdiArea.tileSubWindows) self.cascadeAct = QAction("&Cascade", self, statusTip="Cascade the windows", triggered=self.mdiArea.cascadeSubWindows) self.nextAct = QAction("Ne&xt", self, shortcut=QKeySequence.NextChild, statusTip="Move the focus to the next window", triggered=self.mdiArea.activateNextSubWindow) self.previousAct = QAction( "Pre&vious", self, shortcut=QKeySequence.PreviousChild, statusTip="Move the focus to the previous window", triggered=self.mdiArea.activatePreviousSubWindow) self.separatorAct = QAction(self) self.separatorAct.setSeparator(True) def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addAction(self.newAct) self.fileMenu.addAction(self.newActCam4) self.fileMenu.addAction(self.newActFreeCam) self.exitAct = QAction( "E&xit", self, shortcut=QKeySequence.Quit, statusTip="Exit the application", triggered=QApplication.instance().closeAllWindows) self.fileMenu.addSeparator() action = self.fileMenu.addAction("Switch layout direction") action.triggered.connect(self.switchLayoutDirection) self.fileMenu.addAction(self.exitAct) self.windowMenu = self.menuBar().addMenu("&Window") self.updateWindowMenu() self.windowMenu.aboutToShow.connect(self.updateWindowMenu) self.menuBar().addSeparator() def createStatusBar(self): self.statusBar().showMessage("Ready") def activeMdiChild(self): activeSubWindow = self.mdiArea.activeSubWindow() if activeSubWindow: return activeSubWindow.widget() return None def findMdiChild(self, fileName): canonicalFilePath = QFileInfo(fileName).canonicalFilePath() for window in self.mdiArea.subWindowList(): if window.widget().currentFile() == canonicalFilePath: return window return None def switchLayoutDirection(self): if self.layoutDirection() == Qt.LeftToRight: QApplication.setLayoutDirection(Qt.RightToLeft) else: QApplication.setLayoutDirection(Qt.LeftToRight) def setActiveSubWindow(self, window): if window: self.mdiArea.setActiveSubWindow(window)
class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self._version = __version__ self.setWindowIcon(QIcon(":/logo.png")) self.setWindowTitle("Tasmota Device Manager {}".format(self._version)) self.unknown = [] self.env = TasmotaEnvironment() self.device = None self.topics = [] self.mqtt_queue = [] self.fulltopic_queue = [] # ensure TDM directory exists in the user directory if not os.path.isdir("{}/TDM".format(QDir.homePath())): os.mkdir("{}/TDM".format(QDir.homePath())) self.settings = QSettings("{}/TDM/tdm.cfg".format(QDir.homePath()), QSettings.IniFormat) self.devices = QSettings("{}/TDM/devices.cfg".format(QDir.homePath()), QSettings.IniFormat) self.setMinimumSize(QSize(1000, 600)) # configure logging logging.basicConfig(filename="{}/TDM/tdm.log".format(QDir.homePath()), level=self.settings.value("loglevel", "INFO"), datefmt="%Y-%m-%d %H:%M:%S", format='%(asctime)s [%(levelname)s] %(message)s') logging.info("### TDM START ###") # load devices from the devices file, create TasmotaDevices and add the to the envvironment for mac in self.devices.childGroups(): self.devices.beginGroup(mac) device = TasmotaDevice(self.devices.value("topic"), self.devices.value("full_topic"), self.devices.value("friendly_name")) device.debug = self.devices.value("debug", False, bool) device.p['Mac'] = mac.replace("-", ":") device.env = self.env self.env.devices.append(device) # load device command history self.devices.beginGroup("history") for k in self.devices.childKeys(): device.history.append(self.devices.value(k)) self.devices.endGroup() self.devices.endGroup() self.device_model = TasmotaDevicesModel(self.env) self.setup_mqtt() self.setup_main_layout() self.add_devices_tab() self.build_mainmenu() # self.build_toolbars() self.setStatusBar(QStatusBar()) pbSubs = QPushButton("Show subscriptions") pbSubs.setFlat(True) pbSubs.clicked.connect(self.showSubs) self.statusBar().addPermanentWidget(pbSubs) self.queue_timer = QTimer() self.queue_timer.timeout.connect(self.mqtt_publish_queue) self.queue_timer.start(250) self.auto_timer = QTimer() self.auto_timer.timeout.connect(self.auto_telemetry) self.load_window_state() if self.settings.value("connect_on_startup", False, bool): self.actToggleConnect.trigger() self.tele_docks = {} self.consoles = [] def setup_main_layout(self): self.mdi = QMdiArea() self.mdi.setActivationOrder(QMdiArea.ActivationHistoryOrder) self.mdi.setTabsClosable(True) self.setCentralWidget(self.mdi) def setup_mqtt(self): self.mqtt = MqttClient() self.mqtt.connecting.connect(self.mqtt_connecting) self.mqtt.connected.connect(self.mqtt_connected) self.mqtt.disconnected.connect(self.mqtt_disconnected) self.mqtt.connectError.connect(self.mqtt_connectError) self.mqtt.messageSignal.connect(self.mqtt_message) def add_devices_tab(self): self.devices_list = ListWidget(self) sub = self.mdi.addSubWindow(self.devices_list) sub.setWindowState(Qt.WindowMaximized) self.devices_list.deviceSelected.connect(self.selectDevice) self.devices_list.openConsole.connect(self.openConsole) self.devices_list.openRulesEditor.connect(self.openRulesEditor) self.devices_list.openTelemetry.connect(self.openTelemetry) self.devices_list.openWebUI.connect(self.openWebUI) def load_window_state(self): wndGeometry = self.settings.value('window_geometry') if wndGeometry: self.restoreGeometry(wndGeometry) def build_mainmenu(self): mMQTT = self.menuBar().addMenu("MQTT") self.actToggleConnect = QAction(QIcon(":/disconnect.png"), "Connect") self.actToggleConnect.setCheckable(True) self.actToggleConnect.toggled.connect(self.toggle_connect) mMQTT.addAction(self.actToggleConnect) mMQTT.addAction(QIcon(), "Broker", self.setup_broker) mMQTT.addAction(QIcon(), "Autodiscovery patterns", self.patterns) mMQTT.addSeparator() mMQTT.addAction(QIcon(), "Clear obsolete retained LWTs", self.clear_LWT) mMQTT.addSeparator() mMQTT.addAction(QIcon(), "Auto telemetry period", self.auto_telemetry_period) self.actToggleAutoUpdate = QAction(QIcon(":/auto_telemetry.png"), "Auto telemetry") self.actToggleAutoUpdate.setCheckable(True) self.actToggleAutoUpdate.toggled.connect(self.toggle_autoupdate) mMQTT.addAction(self.actToggleAutoUpdate) mSettings = self.menuBar().addMenu("Settings") mSettings.addAction(QIcon(), "BSSId aliases", self.bssid) mSettings.addSeparator() mSettings.addAction(QIcon(), "Preferences", self.prefs) # mExport = self.menuBar().addMenu("Export") # mExport.addAction(QIcon(), "OpenHAB", self.openhab) def build_toolbars(self): main_toolbar = Toolbar(orientation=Qt.Horizontal, iconsize=24, label_position=Qt.ToolButtonTextBesideIcon) main_toolbar.setObjectName("main_toolbar") def initial_query(self, device, queued=False): for c in initial_commands(): cmd, payload = c cmd = device.cmnd_topic(cmd) if queued: self.mqtt_queue.append([cmd, payload]) else: self.mqtt.publish(cmd, payload, 1) def setup_broker(self): brokers_dlg = BrokerDialog() if brokers_dlg.exec_( ) == QDialog.Accepted and self.mqtt.state == self.mqtt.Connected: self.mqtt.disconnect() def toggle_autoupdate(self, state): if state == True: if self.mqtt.state == self.mqtt.Connected: for d in self.env.devices: self.mqtt.publish(d.cmnd_topic('STATUS'), payload=8) self.auto_timer.setInterval( self.settings.value("autotelemetry", 5000, int)) self.auto_timer.start() else: self.auto_timer.stop() def toggle_connect(self, state): if state and self.mqtt.state == self.mqtt.Disconnected: self.broker_hostname = self.settings.value('hostname', 'localhost') self.broker_port = self.settings.value('port', 1883, int) self.broker_username = self.settings.value('username') self.broker_password = self.settings.value('password') self.mqtt.hostname = self.broker_hostname self.mqtt.port = self.broker_port if self.broker_username: self.mqtt.setAuth(self.broker_username, self.broker_password) self.mqtt.connectToHost() elif not state and self.mqtt.state == self.mqtt.Connected: self.mqtt_disconnect() def auto_telemetry(self): if self.mqtt.state == self.mqtt.Connected: for d in self.env.devices: self.mqtt.publish(d.cmnd_topic('STATUS'), payload=8) def mqtt_connect(self): self.broker_hostname = self.settings.value('hostname', 'localhost') self.broker_port = self.settings.value('port', 1883, int) self.broker_username = self.settings.value('username') self.broker_password = self.settings.value('password') self.mqtt.hostname = self.broker_hostname self.mqtt.port = self.broker_port if self.broker_username: self.mqtt.setAuth(self.broker_username, self.broker_password) if self.mqtt.state == self.mqtt.Disconnected: self.mqtt.connectToHost() def mqtt_disconnect(self): self.mqtt.disconnectFromHost() def mqtt_connecting(self): self.statusBar().showMessage("Connecting to broker") def mqtt_connected(self): self.actToggleConnect.setIcon(QIcon(":/connect.png")) self.actToggleConnect.setText("Disconnect") self.statusBar().showMessage("Connected to {}:{} as {}".format( self.broker_hostname, self.broker_port, self.broker_username if self.broker_username else '[anonymous]')) self.mqtt_subscribe() def mqtt_subscribe(self): # clear old topics self.topics.clear() custom_patterns.clear() # load custom autodiscovery patterns self.settings.beginGroup("Patterns") for k in self.settings.childKeys(): custom_patterns.append(self.settings.value(k)) self.settings.endGroup() # expand fulltopic patterns to subscribable topics for pat in default_patterns: # tasmota default and SO19 self.topics += expand_fulltopic(pat) # check if custom patterns can be matched by default patterns for pat in custom_patterns: if pat.startswith("%prefix%") or pat.split('/')[1] == "%prefix%": continue # do nothing, default subcriptions will match this topic else: self.topics += expand_fulltopic(pat) for d in self.env.devices: # if device has a non-standard pattern, check if the pattern is found in the custom patterns if not d.is_default() and d.p['FullTopic'] not in custom_patterns: # if pattern is not found then add the device topics to subscription list. # if the pattern is found, it will be matched without implicit subscription self.topics += expand_fulltopic(d.p['FullTopic']) # passing a list of tuples as recommended by paho self.mqtt.subscribe([(topic, 0) for topic in self.topics]) @pyqtSlot(str, str) def mqtt_publish(self, t, p): self.mqtt.publish(t, p) def mqtt_publish_queue(self): for q in self.mqtt_queue: t, p = q self.mqtt.publish(t, p) self.mqtt_queue.pop(self.mqtt_queue.index(q)) def mqtt_disconnected(self): self.actToggleConnect.setIcon(QIcon(":/disconnect.png")) self.actToggleConnect.setText("Connect") self.statusBar().showMessage("Disconnected") def mqtt_connectError(self, rc): reason = { 1: "Incorrect protocol version", 2: "Invalid client identifier", 3: "Server unavailable", 4: "Bad username or password", 5: "Not authorized", } self.statusBar().showMessage("Connection error: {}".format(reason[rc])) self.actToggleConnect.setChecked(False) def mqtt_message(self, topic, msg): # try to find a device by matching known FullTopics against the MQTT topic of the message device = self.env.find_device(topic) if device: if topic.endswith("LWT"): if not msg: msg = "Offline" device.update_property("LWT", msg) if msg == 'Online': # known device came online, query initial state self.initial_query(device, True) else: # forward the message for processing device.parse_message(topic, msg) if device.debug: logging.debug("MQTT: %s %s", topic, msg) else: # unknown device, start autodiscovery process if topic.endswith("LWT"): self.env.lwts.append(topic) logging.info("DISCOVERY: LWT from an unknown device %s", topic) # STAGE 1 # load default and user-provided FullTopic patterns and for all the patterns, # try matching the LWT topic (it follows the device's FullTopic syntax for p in default_patterns + custom_patterns: match = re.fullmatch( p.replace("%topic%", "(?P<topic>.*?)").replace( "%prefix%", "(?P<prefix>.*?)") + ".*$", topic) if match: # assume that the matched topic is the one configured in device settings possible_topic = match.groupdict().get('topic') if possible_topic not in ('tele', 'stat'): # if the assumed topic is different from tele or stat, there is a chance that it's a valid topic # query the assumed device for its FullTopic. False positives won't reply. possible_topic_cmnd = p.replace( "%prefix%", "cmnd").replace( "%topic%", possible_topic) + "FullTopic" logging.debug( "DISCOVERY: Asking an unknown device for FullTopic at %s", possible_topic_cmnd) self.mqtt_queue.append([possible_topic_cmnd, ""]) elif topic.endswith("RESULT") or topic.endswith( "FULLTOPIC"): # reply from an unknown device # STAGE 2 full_topic = loads(msg).get('FullTopic') if full_topic: # the device replies with its FullTopic # here the Topic is extracted using the returned FullTopic, identifying the device parsed = parse_topic(full_topic, topic) if parsed: # got a match, we query the device's MAC address in case it's a known device that had its topic changed logging.debug( "DISCOVERY: topic %s is matched by fulltopic %s", topic, full_topic) d = self.env.find_device(topic=parsed['topic']) if d: d.update_property("FullTopic", full_topic) else: logging.info( "DISCOVERY: Discovered topic=%s with fulltopic=%s", parsed['topic'], full_topic) d = TasmotaDevice(parsed['topic'], full_topic) self.env.devices.append(d) self.device_model.addDevice(d) logging.debug( "DISCOVERY: Sending initial query to topic %s", parsed['topic']) self.initial_query(d, True) self.env.lwts.remove(d.tele_topic("LWT")) d.update_property("LWT", "Online") def export(self): fname, _ = QFileDialog.getSaveFileName(self, "Export device list as...", directory=QDir.homePath(), filter="CSV files (*.csv)") if fname: if not fname.endswith(".csv"): fname += ".csv" with open(fname, "w", encoding='utf8') as f: column_titles = [ 'mac', 'topic', 'friendly_name', 'full_topic', 'cmnd_topic', 'stat_topic', 'tele_topic', 'module', 'module_id', 'firmware', 'core' ] c = csv.writer(f) c.writerow(column_titles) for r in range(self.device_model.rowCount()): d = self.device_model.index(r, 0) c.writerow([ self.device_model.mac(d), self.device_model.topic(d), self.device_model.friendly_name(d), self.device_model.fullTopic(d), self.device_model.commandTopic(d), self.device_model.statTopic(d), self.device_model.teleTopic(d), # modules.get(self.device_model.module(d)), self.device_model.module(d), self.device_model.firmware(d), self.device_model.core(d) ]) def bssid(self): BSSIdDialog().exec_() def patterns(self): PatternsDialog().exec_() # def openhab(self): # OpenHABDialog(self.env).exec_() def showSubs(self): QMessageBox.information(self, "Subscriptions", "\n".join(sorted(self.topics))) def clear_LWT(self): dlg = ClearLWTDialog(self.env) if dlg.exec_() == ClearLWTDialog.Accepted: for row in range(dlg.lw.count()): itm = dlg.lw.item(row) if itm.checkState() == Qt.Checked: topic = itm.text() self.mqtt.publish(topic, retain=True) self.env.lwts.remove(topic) logging.info("MQTT: Cleared %s", topic) def prefs(self): dlg = PrefsDialog() if dlg.exec_() == QDialog.Accepted: update_devices = False devices_short_version = self.settings.value( "devices_short_version", True, bool) if devices_short_version != dlg.cbDevShortVersion.isChecked(): update_devices = True self.settings.setValue("devices_short_version", dlg.cbDevShortVersion.isChecked()) update_consoles = False console_font_size = self.settings.value("console_font_size", 9) if console_font_size != dlg.sbConsFontSize.value(): update_consoles = True self.settings.setValue("console_font_size", dlg.sbConsFontSize.value()) console_word_wrap = self.settings.value("console_word_wrap", True, bool) if console_word_wrap != dlg.cbConsWW.isChecked(): update_consoles = True self.settings.setValue("console_word_wrap", dlg.cbConsWW.isChecked()) if update_consoles: for c in self.consoles: c.console.setWordWrapMode(dlg.cbConsWW.isChecked()) new_font = QFont(c.console.font()) new_font.setPointSize(dlg.sbConsFontSize.value()) c.console.setFont(new_font) self.settings.sync() def auto_telemetry_period(self): curr_val = self.settings.value("autotelemetry", 5000, int) period, ok = QInputDialog.getInt( self, "Set AutoTelemetry period", "Values under 5000ms may cause increased ESP LoadAvg", curr_val, 1000) if ok: self.settings.setValue("autotelemetry", period) self.settings.sync() @pyqtSlot(TasmotaDevice) def selectDevice(self, d): self.device = d @pyqtSlot() def openTelemetry(self): if self.device: tele_widget = TelemetryWidget(self.device) self.addDockWidget(Qt.RightDockWidgetArea, tele_widget) self.mqtt_publish(self.device.cmnd_topic('STATUS'), "8") @pyqtSlot() def openConsole(self): if self.device: console_widget = ConsoleWidget(self.device) self.mqtt.messageSignal.connect(console_widget.consoleAppend) console_widget.sendCommand.connect(self.mqtt.publish) self.addDockWidget(Qt.BottomDockWidgetArea, console_widget) console_widget.command.setFocus() self.consoles.append(console_widget) @pyqtSlot() def openRulesEditor(self): if self.device: rules = RulesWidget(self.device) self.mqtt.messageSignal.connect(rules.parseMessage) rules.sendCommand.connect(self.mqtt_publish) self.mdi.setViewMode(QMdiArea.TabbedView) self.mdi.addSubWindow(rules) rules.setWindowState(Qt.WindowMaximized) rules.destroyed.connect(self.updateMDI) self.mqtt_queue.append((self.device.cmnd_topic("ruletimer"), "")) self.mqtt_queue.append((self.device.cmnd_topic("rule1"), "")) self.mqtt_queue.append((self.device.cmnd_topic("Var"), "")) self.mqtt_queue.append((self.device.cmnd_topic("Mem"), "")) @pyqtSlot() def openWebUI(self): if self.device and self.device.p.get('IPAddress'): url = QUrl("http://{}".format(self.device.p['IPAddress'])) try: webui = QWebEngineView() webui.load(url) frm_webui = QFrame() frm_webui.setWindowTitle("WebUI [{}]".format( self.device.p['FriendlyName1'])) frm_webui.setFrameShape(QFrame.StyledPanel) frm_webui.setLayout(VLayout(0)) frm_webui.layout().addWidget(webui) frm_webui.destroyed.connect(self.updateMDI) self.mdi.addSubWindow(frm_webui) self.mdi.setViewMode(QMdiArea.TabbedView) frm_webui.setWindowState(Qt.WindowMaximized) except NameError: QDesktopServices.openUrl( QUrl("http://{}".format(self.device.p['IPAddress']))) def updateMDI(self): if len(self.mdi.subWindowList()) == 1: self.mdi.setViewMode(QMdiArea.SubWindowView) self.devices_list.setWindowState(Qt.WindowMaximized) def closeEvent(self, e): self.settings.setValue("version", self._version) self.settings.setValue("window_geometry", self.saveGeometry()) self.settings.setValue("views_order", ";".join(self.devices_list.views.keys())) self.settings.beginGroup("Views") for view, items in self.devices_list.views.items(): self.settings.setValue(view, ";".join(items[1:])) self.settings.endGroup() self.settings.sync() for d in self.env.devices: mac = d.p.get('Mac') topic = d.p['Topic'] full_topic = d.p['FullTopic'] friendly_name = d.p['FriendlyName1'] if mac: self.devices.beginGroup(mac.replace(":", "-")) self.devices.setValue("topic", topic) self.devices.setValue("full_topic", full_topic) self.devices.setValue("friendly_name", friendly_name) for i, h in enumerate(d.history): self.devices.setValue("history/{}".format(i), h) self.devices.endGroup() self.devices.sync() e.accept()
class DemoMdi(QMainWindow): def __init__(self, parent=None): super(DemoMdi, self).__init__(parent) # 设置窗口标题 self.setWindowTitle( 'MDI with a dockWidget tree and a tab-view mdiArea') # 设置窗口大小 self.resize(800, 640) self.initUi() self.mytimer = QTimer(self) self.mytimer.start(1000) self.mytimer.timeout.connect(self.timerCallback) def initUi(self): self.initMenuBar() self.initToolBar() self.initDockTree() self.initStatusBar() self.mdiArea = QMdiArea(self) self.setCentralWidget(self.mdiArea) # set as tabbedView by default self.mdiArea.setViewMode(QMdiArea.TabbedView) self.mdiArea.setTabShape(QTabWidget.Triangular) self.mdiArea.setTabsClosable(True) self.mdiArea.setTabsMovable(True) # index of document self.newDocIndex = 1 def initDockTree(self): self.dockWind = QDockWidget(self) self.dockWind.setWindowTitle('QProfile Explorer') self.initTree() self.dockWind.setWidget(self.tree) self.dockWind.setFloating(False) # set floating = false self.addDockWidget(Qt.LeftDockWidgetArea, self.dockWind) # set the position at left side # remove all features of DockWidget like Closable, Moveable, Floatable, VerticalTitle etc. self.dockWind.setFeatures(QDockWidget.NoDockWidgetFeatures) def initTree(self): self.tree = QTreeWidget() self.tree.setColumnCount(1) #设置列数 #self.tree.setHeaderLabels(['QProfiler items']) #设置树形控件头部的标题 self.tree.setIndentation(20) # 项目的缩进 self.tree.setHeaderHidden(True) #设置根节点 Perfmon = myQTreeWidgetItem(sin(pi * perfmon_x)) Perfmon.setText(0, 'Perfmon') perfmon_00 = myQTreeWidgetItem(sin(2 * pi * perfmon_x)) perfmon_00.setText(0, 'perfmon_00') Perfmon.addChild(perfmon_00) perfmon_01 = QTreeWidgetItem() perfmon_01.setText(0, 'perfmon_01') Perfmon.addChild(perfmon_01) perfmon_02 = QTreeWidgetItem() perfmon_02.setText(0, 'perfmon_02') Perfmon.addChild(perfmon_02) perfmon_03 = QTreeWidgetItem() perfmon_03.setText(0, 'perfmon_03') Perfmon.addChild(perfmon_03) self.tree.addTopLevelItem(Perfmon) # CPU cpuLoad = QTreeWidgetItem() cpuLoad.setText(0, 'CPU') cpuLoad_1 = QTreeWidgetItem() cpuLoad_1.setText(0, 'core 1') cpuLoad.addChild(cpuLoad_1) cpuLoad_2 = QTreeWidgetItem() cpuLoad_2.setText(0, 'core 2') cpuLoad.addChild(cpuLoad_2) self.tree.addTopLevelItem(cpuLoad) # treeItem signal self.tree.itemClicked[QTreeWidgetItem, int].connect(self.treeItemClicked) def treeItemWindow_open(self, item): title = item.text(0) subWind = QMdiSubWindow(self) subWind.setAttribute(Qt.WA_DeleteOnClose) subWind.setWindowTitle(title) self.newDocIndex += 1 mainWid = QWidget() l = QtWidgets.QVBoxLayout(mainWid) txtWind = QPlainTextEdit(mainWid) txtWind.setPlainText(f"perfmon.x = {item.x}, \n y = {item.y}") figWind = MyCanvas(mainWid, width=5, height=4, dpi=100, treeWidgetItem=item) l.addWidget(figWind) l.addWidget(txtWind) l.setStretch(0, 3) # 设置第一列的伸展比例为 3 l.setStretch(1, 1) # 设置第二列的伸展比例为 1, 这样2列的伸展比为3:1 subWind.setWidget(mainWid) self.mdiArea.addSubWindow(subWind) subWind.show() def treeItemClicked(self, item, column): tab = self.get_treeItem_tab(item.text(column)) if tab is not None: tab.setFocus() else: if item.text(column) == 'Perfmon': self.treeItemWindow_open(item) else: newDoc = QMdiSubWindow(self) newDoc.setAttribute(Qt.WA_DeleteOnClose) newDoc.setWindowTitle(item.text(column)) self.newDocIndex += 1 newDoc.setWidget(QPlainTextEdit( item.text(column) * 10, newDoc)) self.mdiArea.addSubWindow(newDoc) newDoc.show() def get_treeItem_tab(self, title): for wind in self.mdiArea.subWindowList(): if title == wind.windowTitle(): return wind return None def initStatusBar(self): self.statusBar = self.statusBar() self.statusBar.showMessage('Ready to start ...', 0) def initMenuBar(self): menuBar = self.menuBar() style = QApplication.style() #==== 文件 ====# fileMenu = menuBar.addMenu('文件') #新建一个文档 aFileNew = QAction('新建文档', self) aFileNew.setIcon(style.standardIcon(QStyle.SP_FileIcon)) aFileNew.triggered.connect(self.onFileNew) fileMenu.addAction(aFileNew) #打开一个文档 aFileOpen = QAction('打开文档', self) aFileOpen.setIcon(style.standardIcon(QStyle.SP_DialogOpenButton)) aFileOpen.triggered.connect(self.onFileOpen) fileMenu.addAction(aFileOpen) #关闭一个文档 aFileCloseAll = QAction('关闭全部', self) aFileCloseAll.setIcon(style.standardIcon(QStyle.SP_DialogCloseButton)) aFileOpen.triggered.connect(self.onFileCloseAll) fileMenu.addAction(aFileCloseAll) #添加分割线 fileMenu.addSeparator() #退出 aFileExit = QAction('退出', self) aFileExit.triggered.connect(self.close) fileMenu.addAction(aFileExit) #==== 编辑 ====# editMenu = menuBar.addMenu('编辑') #剪切 aEditCut = QAction('剪切', self) aEditCut.setIcon(QIcon(':/ico/cut.png')) aEditCut.triggered.connect(self.onEditCut) editMenu.addAction(aEditCut) #复制 aEditCopy = QAction('复制', self) aEditCopy.setIcon(QIcon(':/ico/copy.png')) aEditCopy.triggered.connect(self.onEditCopy) editMenu.addAction(aEditCopy) #粘贴 aEditPaste = QAction('粘贴', self) aEditPaste.setIcon(QIcon(':/ico/paste.png')) aEditPaste.triggered.connect(self.onEditPaste) editMenu.addAction(aEditPaste) #==== 窗口排列方式 ====# windowMenu = menuBar.addMenu('窗口') #子窗口模式 aWndSubView = QAction('子窗口模式', self) aWndSubView.triggered.connect(lambda: self.onWinowdMode(0)) windowMenu.addAction(aWndSubView) #标签页模式 aWndTab = QAction('标签页模式', self) aWndTab.triggered.connect(lambda: self.onWinowdMode(1)) windowMenu.addAction(aWndTab) windowMenu.addSeparator() #平铺模式 aWndTile = QAction('平铺模式', self) aWndTile.triggered.connect(lambda: self.onWinowdMode(2)) windowMenu.addAction(aWndTile) #窗口级联模式 aWndCascade = QAction('窗口级联模式', self) aWndCascade.triggered.connect(lambda: self.onWinowdMode(3)) windowMenu.addAction(aWndCascade) def initToolBar(self): toolBar = self.addToolBar('ToolBar') style = QApplication.style() min_width = 64 btnFileNew = QToolButton(self) btnFileNew.setText('新建文档') btnFileNew.setMinimumWidth(min_width) btnFileNew.setIcon(style.standardIcon(QStyle.SP_FileIcon)) btnFileNew.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) btnFileNew.clicked.connect(self.onFileNew) toolBar.addWidget(btnFileNew) btnFileOpen = QToolButton(self) btnFileOpen.setText('打开文档') btnFileOpen.setMinimumWidth(min_width) btnFileOpen.setIcon(style.standardIcon(QStyle.SP_DialogOpenButton)) btnFileOpen.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) btnFileOpen.clicked.connect(self.onFileOpen) toolBar.addWidget(btnFileOpen) btnFileCloseAll = QToolButton(self) btnFileCloseAll.setText('关闭全部') btnFileCloseAll.setMinimumWidth(min_width) btnFileCloseAll.setIcon(style.standardIcon( QStyle.SP_DialogCloseButton)) btnFileCloseAll.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) btnFileCloseAll.clicked.connect(self.onFileCloseAll) toolBar.addWidget(btnFileCloseAll) toolBar.addSeparator() btnEditCut = QToolButton(self) btnEditCut.setText('剪切') btnEditCut.setMinimumWidth(64) btnEditCut.setIcon(QIcon(':/ico/cut.png')) btnEditCut.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) btnEditCut.clicked.connect(self.onEditCut) toolBar.addWidget(btnEditCut) btnEditCopy = QToolButton(self) btnEditCopy.setText('复制') btnEditCopy.setMinimumWidth(64) btnEditCopy.setIcon(QIcon(':/ico/copy.png')) btnEditCopy.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) btnEditCopy.clicked.connect(self.onEditCopy) toolBar.addWidget(btnEditCopy) btnEditPaste = QToolButton(self) btnEditPaste.setText('粘贴') btnEditPaste.setMinimumWidth(64) btnEditPaste.setIcon(QIcon(':/ico/paste.png')) btnEditPaste.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) btnEditPaste.clicked.connect(self.onEditPaste) toolBar.addWidget(btnEditPaste) def msgCritical(self, strInfo): dlg = QMessageBox(self) dlg.setIcon(QMessageBox.Critical) dlg.setText(strInfo) dlg.show() def onFileNew(self): newDoc = QMdiSubWindow(self) newDoc.setAttribute(Qt.WA_DeleteOnClose) newDoc.setWindowTitle('新文档 ' + str(self.newDocIndex)) self.newDocIndex += 1 newDoc.setWidget(QPlainTextEdit(newDoc)) self.mdiArea.addSubWindow(newDoc) newDoc.show() def onFileOpen(self): path, _ = QFileDialog.getOpenFileName(self, '打开文件', '', '文本文件 (*.txt, *.prf)') if path: try: with open(path, 'rU') as f: text = f.read() except Exception as e: self.msgCritical(str(e)) else: openDoc = QMdiSubWindow(self) openDoc.setWindowTitle(path) txtEdit = QPlainTextEdit(openDoc) txtEdit.setPlainText(text) openDoc.setWidget(txtEdit) self.mdiArea.addSubWindow(openDoc) openDoc.show() def onFileCloseAll(self): self.mdiArea.closeAllSubWindows() def onEditCut(self): txtEdit = self.mdiArea.activeSubWindow().widget() txtEdit.cut() def onEditCopy(self): txtEdit = self.mdiArea.activeSubWindow().widget() txtEdit.copy() def onEditPaste(self): txtEdit = self.mdiArea.activeSubWindow().widget() txtEdit.paste() def onWinowdMode(self, index): if index == 3: self.mdiArea.cascadeSubWindows() elif index == 2: self.mdiArea.tileSubWindows() elif index == 1: self.mdiArea.setViewMode(QMdiArea.TabbedView) else: self.mdiArea.setViewMode(QMdiArea.SubWindowView) def timerCallback(self): self.statusBar.showMessage( f'Document Index = {self.newDocIndex}, subWind num ={len(self.mdiArea.subWindowList())}', 0)
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.mdiArea = QMdiArea() self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setCentralWidget(self.mdiArea) self.mdiArea.subWindowActivated.connect(self.updateMenus) self.windowMapper = QSignalMapper(self) self.windowMapper.mapped[QWidget].connect(self.setActiveSubWindow) self.createActions() self.createMenus() self.createToolBars() self.createStatusBar() self.updateMenus() self.readSettings() self.setWindowTitle("MDI Test") def closeEvent(self, event): self.mdiArea.closeAllSubWindows() if self.mdiArea.currentSubWindow(): event.ignore() else: self.writeSettings() event.accept() def newFile(self): child = self.createMdiChild() child.newFile() child.show() def open(self): fileName, _ = QFileDialog.getOpenFileName(self) if fileName: existing = self.findMdiChild(fileName) if existing: self.mdiArea.setActiveSubWindow(existing) return child = self.createMdiChild() if child.loadFile(fileName): self.statusBar().showMessage("File loaded", 2000) child.show() else: child.close() def save(self): if self.activeMdiChild() and self.activeMdiChild().save(): self.statusBar().showMessage("File saved", 2000) def saveAs(self): if self.activeMdiChild() and self.activeMdiChild().saveAs(): self.statusBar().showMessage("File saved", 2000) def cut(self): if self.activeMdiChild(): self.activeMdiChild().cut() def copy(self): if self.activeMdiChild(): self.activeMdiChild().copy() def paste(self): if self.activeMdiChild(): self.activeMdiChild().paste() def about(self): QMessageBox.about( self, "About MDI", "The <b>MDI</b> example demonstrates how to write multiple " "document interface applications using Qt.") def updateMenus(self): hasMdiChild = (self.activeMdiChild() is not None) #self.saveAct.setEnabled(hasMdiChild) #self.saveAsAct.setEnabled(hasMdiChild) self.pasteAct.setEnabled(hasMdiChild) self.closeAct.setEnabled(hasMdiChild) self.closeAllAct.setEnabled(hasMdiChild) self.tileAct.setEnabled(hasMdiChild) self.cascadeAct.setEnabled(hasMdiChild) self.nextAct.setEnabled(hasMdiChild) self.previousAct.setEnabled(hasMdiChild) self.separatorAct.setVisible(hasMdiChild) hasSelection = (self.activeMdiChild() is not None and self.activeMdiChild().textCursor().hasSelection()) self.cutAct.setEnabled(hasSelection) self.copyAct.setEnabled(hasSelection) def updateWindowMenu(self): self.windowMenu.clear() self.windowMenu.addAction(self.closeAct) self.windowMenu.addAction(self.closeAllAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.tileAct) self.windowMenu.addAction(self.cascadeAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.nextAct) self.windowMenu.addAction(self.previousAct) self.windowMenu.addAction(self.separatorAct) windows = self.mdiArea.subWindowList() self.separatorAct.setVisible(len(windows) != 0) for i, window in enumerate(windows): child = window.widget() text = "%d %s" % (i + 1, child.userFriendlyCurrentFile()) if i < 9: text = '&' + text action = self.windowMenu.addAction(text) action.setCheckable(True) action.setChecked(child is self.activeMdiChild()) action.triggered.connect(self.windowMapper.map) self.windowMapper.setMapping(action, window) def createMdiChild(self): child = MdiChild() self.mdiArea.addSubWindow(child) child.copyAvailable.connect(self.cutAct.setEnabled) child.copyAvailable.connect(self.copyAct.setEnabled) return child # showntell def createMdiChild15(self): child = MdiChild_ShowNTell() self.mdiArea.addSubWindow(child) return child #MNIST def show_n_tell(self): print('show_n_tell....') child = self.createMdiChild15() print('self.createMdiChild15') #child.resize(830,480) #print('self.createMdiChild15') child.show print('child.show()') def createActions(self): self.cutAct = QAction( QIcon(':/images/cut.png'), "Cu&t", self, shortcut=QKeySequence.Cut, statusTip="Cut the current selection's contents to the clipboard", triggered=self.cut) self.copyAct = QAction( QIcon(':/images/copy.png'), "&Copy", self, shortcut=QKeySequence.Copy, statusTip="Copy the current selection's contents to the clipboard", triggered=self.copy) self.pasteAct = QAction( QIcon(':/images/paste.png'), "&Paste", self, shortcut=QKeySequence.Paste, statusTip= "Paste the clipboard's contents into the current selection", triggered=self.paste) self.closeAct = QAction("Cl&ose", self, statusTip="Close the active window", triggered=self.mdiArea.closeActiveSubWindow) self.closeAllAct = QAction("Close &All", self, statusTip="Close all the windows", triggered=self.mdiArea.closeAllSubWindows) self.tileAct = QAction("&Tile", self, statusTip="Tile the windows", triggered=self.mdiArea.tileSubWindows) self.cascadeAct = QAction("&Cascade", self, statusTip="Cascade the windows", triggered=self.mdiArea.cascadeSubWindows) self.nextAct = QAction("Ne&xt", self, shortcut=QKeySequence.NextChild, statusTip="Move the focus to the next window", triggered=self.mdiArea.activateNextSubWindow) self.previousAct = QAction( "Pre&vious", self, shortcut=QKeySequence.PreviousChild, statusTip="Move the focus to the previous window", triggered=self.mdiArea.activatePreviousSubWindow) self.separatorAct = QAction(self) self.separatorAct.setSeparator(True) # 메뉴 ACTION을 다이나믹하게 연결해준다 self.MenuActRef = { 'NewFileAct': 0, 'OpnFileAct': 0, 'SavFileAct': 0, 'SavASFileAct': 0, 'AboutAct': 0, 'AboutQTAct': 0, 'ExitAct': 0, 'SwitchLayout': 0, 'ShowNTell': 0 } # ******* Create the File Menu ******* self.NewFileAct = QAction(QIcon(':/images/new.png'), '&New File', self) self.NewFileAct.setShortcut("Ctrl+N") self.NewFileAct.setStatusTip('Create a New File') self.NewFileAct.triggered.connect(self.newFile) self.MenuActRef['NewFileAct'] = self.NewFileAct #self.newAct = QAction(QIcon(':/images/new.png'), "&New", self, # shortcut=QKeySequence.New, statusTip="Create a new file", # triggered=self.newFile) # ******* Open File Menu Items ******* self.OpnFileAct = QAction(QIcon(':/images/open.png'), '&Open File', self) self.OpnFileAct.setShortcut("Ctrl+O") self.OpnFileAct.setStatusTip('Open an Existing File') self.OpnFileAct.triggered.connect(self.open) self.MenuActRef['OpnFileAct'] = self.OpnFileAct #self.openAct = QAction(QIcon(':/images/open.png'), "&Open...", self, # shortcut=QKeySequence.Open, statusTip="Open an existing file", # triggered=self.open) # ******* Save File Menu Items ******* self.SavFileAct = QAction(QIcon(':/images/save.png'), '&Save File', self) self.SavFileAct.setShortcut("Ctrl+S") self.SavFileAct.setStatusTip('Save Current File') self.SavFileAct.triggered.connect(self.save) self.MenuActRef['SavFileAct'] = self.SavFileAct #self.saveAct = QAction(QIcon(':/images/save.png'), "&Save", self, # shortcut=QKeySequence.Save, # statusTip="Save the document to disk", triggered=self.save) # ******* SaveAS File Menu Items ******* self.SavASFileAct = QAction('Save &As File', self) self.SavASFileAct.setShortcut("Ctrl+A") self.SavASFileAct.setStatusTip('Save Current File under a new name ') self.SavASFileAct.triggered.connect(self.saveAs) self.MenuActRef['SavASFileAct'] = self.SavASFileAct #self.saveAsAct = QAction("Save &As...", self, # shortcut=QKeySequence.SaveAs, # statusTip="Save the document under a new name", # triggered=self.saveAs) # ******* About Menu Items ******* self.aboutAct = QAction("&About", self) self.aboutAct.setStatusTip("Show the application's About box") self.aboutAct.triggered.connect(self.about) self.MenuActRef['AboutAct'] = self.aboutAct # ******* About QT Menu Items ******* self.aboutAct = QAction("About &Qt", self) self.aboutAct.setStatusTip("Show the Qt library's About box") self.aboutAct.triggered.connect(QApplication.instance().aboutQt) self.MenuActRef['AboutQTAct'] = self.aboutAct # ******* Exit Menu Items ******* self.exitAct = QAction("E&xit", self) self.exitAct.setStatusTip("Exit the application") self.exitAct.triggered.connect(QApplication.instance().closeAllWindows) self.MenuActRef['ExitAct'] = self.exitAct #self.exitAct = QAction("E&xit", self, shortcut=QKeySequence.Quit, # statusTip="Exit the application", # triggered=QApplication.instance().closeAllWindows) # ******* Switch layout Items ******* self.SwitchLayout = QAction("&Switch layout direction", self) self.SwitchLayout.setStatusTip("Switch layout direction") self.SwitchLayout.triggered.connect(self.switchLayoutDirection) self.MenuActRef['SwitchLayout'] = self.SwitchLayout #self.SwitchLayout = QAction("&Switch layout direction", self, # statusTip="Switch layout direction", # triggered=self.switchLayoutDirection) # ******* Switch layout Items ******* self.ShowNTell = QAction("&ShowNTell", self) self.ShowNTell.setStatusTip("&ShowNTell") self.ShowNTell.triggered.connect(self.show_n_tell) self.MenuActRef['ShowNTell'] = self.ShowNTell #self.ShowNTell = QAction("&show_n_tell", self, # statusTip="show_n_tell", # triggered=self.show_n_tell) def createMenus(self): # 메뉴를 다이나믹하게 생성하고 연결함 self.MenuLayout = { 0: { 'addMenu': '&File', 'addToolMenu': 'File' }, 1: { 'addDynamic': 'NewFileAct', 'addToolbar': 'NewFileAct' }, 2: { 'addDynamic': 'OpnFileAct', 'addToolbar': 'OpnFileAct' }, 3: { 'addDynamic': 'SavFileAct', 'addToolbar': 'SavFileAct' }, 4: { 'addDynamic': 'SavASFileAct' }, 5: { 'addSeparator': '' }, 6: { 'addDynamic': 'SwitchLayout' }, 7: { 'addDynamic': 'ExitAct' }, 8: { 'addMenu': '&Edit' }, 9: { 'addAction': self.cutAct }, 10: { 'addAction': self.copyAct }, 11: { 'addAction': self.pasteAct }, 12: { 'addMenu': '&Window' }, 13: { 'updateMenu': '' }, 14: { 'addSeparator': '' }, 15: { 'addMenu': '&Help' }, 16: { 'addDynamic': 'AboutAct' }, 17: { 'addDynamic': 'AboutQTAct' }, 18: { 'addMenu': '&MNIST' }, 19: { 'addDynamic': 'ShowNTell' } } for idx in self.MenuLayout: item = self.MenuLayout[idx] if 'addMenu' in item.keys(): self.windowMenu = self.menuBar().addMenu(item['addMenu']) elif 'addAction' in item.keys(): self.windowMenu.addAction(item['addAction']) elif 'addSeparator' in item.keys(): self.windowMenu.addSeparator() elif 'updateMenu' in item.keys(): self.updateWindowMenu() self.windowMenu.aboutToShow.connect(self.updateWindowMenu) # 메뉴 ACTION을 다이나믹하게 elif 'addDynamic' in item.keys(): self.windowMenu.addAction(self.MenuActRef[item['addDynamic']]) def createToolBars(self): for idx in self.MenuLayout: item = self.MenuLayout[idx] if 'addToolMenu' in item.keys(): self.fileToolBar = self.addToolBar(item['addToolMenu']) elif 'addToolbar' in item.keys(): self.fileToolBar.addAction(self.MenuActRef[item['addDynamic']]) #self.fileToolBar = self.addToolBar("File") #self.fileToolBar.addAction(self.MenuActRef['NewFileAct']) #self.fileToolBar.addAction(self.MenuActRef['OpnFileAct']) #self.fileToolBar.addAction(self.MenuActRef['SavFileAct']) #self.fileToolBar.addAction(self.newAct) #self.fileToolBar.addAction(self.openAct) #self.fileToolBar.addAction(self.saveAct) self.editToolBar = self.addToolBar("Edit") self.editToolBar.addAction(self.cutAct) self.editToolBar.addAction(self.copyAct) self.editToolBar.addAction(self.pasteAct) def createStatusBar(self): self.statusBar().showMessage("Ready") def readSettings(self): settings = QSettings('NH-Soft', 'MDI Example') pos = settings.value('pos', QPoint(200, 200)) size = settings.value('size', QSize(400, 400)) self.move(pos) self.resize(size) def writeSettings(self): settings = QSettings('NH-Soft', 'MDI Example') settings.setValue('pos', self.pos()) settings.setValue('size', self.size()) def activeMdiChild(self): activeSubWindow = self.mdiArea.activeSubWindow() if activeSubWindow: return activeSubWindow.widget() return None def findMdiChild(self, fileName): canonicalFilePath = QFileInfo(fileName).canonicalFilePath() for window in self.mdiArea.subWindowList(): if window.widget().currentFile() == canonicalFilePath: return window return None def switchLayoutDirection(self): if self.layoutDirection() == Qt.LeftToRight: QApplication.setLayoutDirection(Qt.RightToLeft) else: QApplication.setLayoutDirection(Qt.LeftToRight) def setActiveSubWindow(self, window): if window: self.mdiArea.setActiveSubWindow(window)
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.mdiArea = QMdiArea() self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setCentralWidget(self.mdiArea) self.mdiArea.subWindowActivated.connect(self.update_menus) self.windowMapper = QSignalMapper(self) self.windowMapper.mapped.connect(self.set_active_sub_window) self.newAct = QAction(self) self.newAct.setIcon(self.style().standardIcon(QStyle.SP_FileIcon)) # self.newAct.setIcon(QIcon(':/images/new.png')) self.newAct.setIconText('New') self.newAct.setShortcut(QKeySequence.New) self.newAct.setStatusTip('Create a new file') self.newAct.triggered.connect(self.new_file) self.openAct = QAction(self) self.openAct.setIcon(self.style().standardIcon(QStyle.SP_DirOpenIcon)) self.openAct.setIconText('Open...') self.openAct.setShortcut(QKeySequence.Open) self.openAct.setStatusTip('Open an existing file') self.openAct.triggered.connect(self.open) self.saveAct = QAction(self) self.saveAct.setIcon(self.style().standardIcon(QStyle.SP_DialogSaveButton)) self.saveAct.setIconText('Save') self.saveAct.setShortcut(QKeySequence.Save) self.saveAct.setStatusTip('Save the document to disk') self.saveAct.triggered.connect(self.save) self.saveAsAct = QAction(self) self.saveAsAct.setIconText('Save As...') self.saveAsAct.setShortcut(QKeySequence.SaveAs) self.saveAsAct.setStatusTip('Save the document under a new name') self.saveAsAct.triggered.connect(self.save_as) self.exitAct = QAction(self) self.exitAct.setIconText('Exit') self.exitAct.setShortcut(QKeySequence.Quit) self.exitAct.setStatusTip('Exit the application') self.exitAct.triggered.connect(qApp.closeAllWindows) self.cutAct = QAction(self) # self.cutAct.setIcon(QIcon(':/images/cut.png')) self.cutAct.setIconText('Cut') self.cutAct.setShortcut(QKeySequence.Cut) self.cutAct.setStatusTip("Cut the current selection's contents to the clipboard") self.cutAct.triggered.connect(self.cut) self.copyAct = QAction(self) # self.copyAct.setIcon(QIcon(':/images/copy.png')) self.copyAct.setIconText('Copy') self.copyAct.setShortcut(QKeySequence.Copy) self.copyAct.setStatusTip("Copy the current selection's contents to the clipboard") self.copyAct.triggered.connect(self.copy) self.pasteAct = QAction(self) # self.pasteAct.setIcon(QIcon(':/images/paste.png')) self.pasteAct.setIconText('Paste') self.pasteAct.setShortcut(QKeySequence.Paste) self.pasteAct.setStatusTip("Paste the clipboard's contents into the current selection") self.pasteAct.triggered.connect(self.paste) self.closeAct = QAction(self) self.closeAct.setIconText('Close') self.closeAct.setShortcut('Ctrl+W') self.closeAct.setStatusTip("Close the active window") self.closeAct.triggered.connect(self.mdiArea.closeActiveSubWindow) self.closeAllAct = QAction(self) self.closeAllAct.setIconText('Close All') self.closeAllAct.setStatusTip('Close all the windows') self.closeAllAct.triggered.connect(self.mdiArea.closeAllSubWindows) self.tileAct = QAction(self) self.tileAct.setIconText('Tile') self.tileAct.setStatusTip('Tile the windows') self.tileAct.triggered.connect(self.mdiArea.tileSubWindows) self.cascadeAct = QAction(self) self.cascadeAct.setIconText('Cascade') self.cascadeAct.setStatusTip('Cascade the windows') self.cascadeAct.triggered.connect(self.mdiArea.cascadeSubWindows) self.nextAct = QAction(self) self.nextAct.setIconText('Next') self.nextAct.setShortcut(QKeySequence.NextChild) self.nextAct.setStatusTip('Move the focus to the next window') self.nextAct.triggered.connect(self.mdiArea.activateNextSubWindow) self.previousAct = QAction(self) self.previousAct.setIconText('Previous') self.previousAct.setShortcut(QKeySequence.PreviousChild) self.previousAct.setStatusTip('Move the focus to the previous window') self.previousAct.triggered.connect(self.mdiArea.activatePreviousSubWindow) self.separatorAct = QAction(self) self.separatorAct.setSeparator(True) self.aboutAct = QAction(self) self.aboutAct.setIconText('About') self.aboutAct.setStatusTip("Show the application's About box") self.aboutAct.triggered.connect(self.about) self.aboutQtAct = QAction(self) self.aboutQtAct.setIconText('About Qt') self.aboutQtAct.setStatusTip("Show the Qt library's About box") self.aboutQtAct.triggered.connect(qApp.aboutQt) self.fileMenu = self.menuBar().addMenu('File') self.fileMenu.addAction(self.newAct) self.fileMenu.addAction(self.openAct) self.fileMenu.addAction(self.saveAct) self.fileMenu.addAction(self.saveAsAct) self.fileMenu.addSeparator() action = self.fileMenu.addAction('Switch layout direction') action.triggered.connect(self.switch_layout_direction) self.fileMenu.addAction(self.exitAct) self.editMenu = self.menuBar().addMenu('Edit') self.editMenu.addAction(self.cutAct) self.editMenu.addAction(self.copyAct) self.editMenu.addAction(self.pasteAct) self.windowMenu = self.menuBar().addMenu('Window') self.update_window_menu() self.windowMenu.aboutToShow.connect(self.update_window_menu) self.menuBar().addSeparator() self.helpMenu = self.menuBar().addMenu('Help') self.helpMenu.addAction(self.aboutAct) self.helpMenu.addAction(self.aboutQtAct) self.file_tool_bar = self.addToolBar('File') self.file_tool_bar.addAction(self.newAct) self.file_tool_bar.addAction(self.openAct) self.file_tool_bar.addAction(self.saveAct) self.edit_tool_bar = self.addToolBar('Edit') self.edit_tool_bar.addAction(self.cutAct) self.edit_tool_bar.addAction(self.copyAct) self.edit_tool_bar.addAction(self.pasteAct) self.statusBar().showMessage('Ready') self.update_menus() self.settings = QSettings('SavSoft', 'Combiner') self.last_directory: str = '' self.read_settings() self.setWindowTitle('MDI') self.setUnifiedTitleAndToolBarOnMac(True) def closeEvent(self, event): self.mdiArea.closeAllSubWindows() if self.active_mdi_child(): event.ignore() else: self.write_settings() event.accept() def new_file(self): child = self.create_mdi_child() child.new_file() child.show() def open(self): filters = ['IRTECON files (*.grd)', 'Plain text files (*.csv *.tsv *.dat *.txt)'] file_name, _ = QFileDialog.getOpenFileName(self, filter=';;'.join(filters), directory=self.last_directory, options=QFileDialog.DontUseNativeDialog) if file_name: child = self.create_mdi_child() if QFileInfo(file_name).suffix() == 'grd': if child.load_irtecon_file(file_name): self.statusBar().showMessage('File loaded', 2000) self.last_directory = QFileInfo(file_name).dir().absolutePath() child.show() else: child.close() else: print(PlainTextImportDialog(file_name).exec()) raise NotImplementedError def save(self): if self.active_mdi_child() and self.active_mdi_child().save(): self.statusBar().showMessage('File saved', 2000) def save_as(self): if self.active_mdi_child() and self.active_mdi_child().save_as(): self.statusBar().showMessage('File saved', 2000) def cut(self): if self.active_mdi_child(): self.active_mdi_child().cut() def copy(self): if self.active_mdi_child(): self.active_mdi_child().copy() def paste(self): if self.active_mdi_child(): self.active_mdi_child().paste() def about(self): QMessageBox.about(self, 'About MDI', 'The <b>MDI</b> example demonstrates how to write multiple ' 'document interface applications using Qt.') def update_menus(self): has_mdi_child = (self.active_mdi_child() is not None) self.saveAct.setEnabled(has_mdi_child) self.saveAsAct.setEnabled(has_mdi_child) self.pasteAct.setEnabled(has_mdi_child) self.closeAct.setEnabled(has_mdi_child) self.closeAllAct.setEnabled(has_mdi_child) self.tileAct.setEnabled(has_mdi_child) self.cascadeAct.setEnabled(has_mdi_child) self.nextAct.setEnabled(has_mdi_child) self.previousAct.setEnabled(has_mdi_child) self.separatorAct.setVisible(has_mdi_child) def update_window_menu(self): self.windowMenu.clear() self.windowMenu.addAction(self.closeAct) self.windowMenu.addAction(self.closeAllAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.tileAct) self.windowMenu.addAction(self.cascadeAct) self.windowMenu.addSeparator() self.windowMenu.addAction(self.nextAct) self.windowMenu.addAction(self.previousAct) self.windowMenu.addAction(self.separatorAct) windows = self.mdiArea.subWindowList() self.separatorAct.setVisible(len(windows) != 0) for i, window in enumerate(windows): child = window.widget() text = f'{i + 1:d} {child.user_friendly_current_file()}' if i < 9: text = '' + text action = self.windowMenu.addAction(text) action.setCheckable(True) action.setChecked(child == self.active_mdi_child()) action.triggered.connect(self.windowMapper.map) self.windowMapper.setMapping(action, window) def create_mdi_child(self): child = MDIChildPlot() self.mdiArea.addSubWindow(child) return child def read_settings(self): pos = self.settings.value('pos', QPoint(200, 200)) self.move(pos) size = self.settings.value('size', QSize(400, 400)) self.resize(size) self.last_directory = self.settings.value('directory', '') def write_settings(self): self.settings.setValue('pos', self.pos()) self.settings.setValue('size', self.size()) self.settings.setValue('directory', self.last_directory) def active_mdi_child(self): active_sub_window = self.mdiArea.activeSubWindow() if active_sub_window: return active_sub_window.widget() return None def switch_layout_direction(self): if self.layoutDirection() == Qt.LeftToRight: qApp.setLayoutDirection(Qt.RightToLeft) else: qApp.setLayoutDirection(Qt.LeftToRight) def set_active_sub_window(self, window): if window: self.mdiArea.setActiveSubWindow(window)