def init_ui(self): """Initialize all GUI elements and show window.""" self.set_status('Welcome') self.create_menus() canvas_box = self.create_canvas() sequence_form = self.create_sequence_form() # let's have the sequence form over the canvas. vbox = QVBoxLayout() vbox.addLayout(sequence_form, stretch=0) vbox.setAlignment(Qt.AlignTop) vbox.addLayout(canvas_box, stretch=1) splitter = QSplitter(Qt.Horizontal) options = OptionPanel(self.args) for layout in [vbox, options]: widget = QWidget() widget.setLayout(layout) splitter.addWidget(widget) self.setCentralWidget(splitter) self.resize(600, 600) self.setWindowTitle('Dotplot') self.show()
def __init__(self, parent=None): super(_s_CentralWidget, self).__init__(parent) self.parent = parent #This variables are used to save the splitter sizes before hide self._splitterMainSizes = None self._splitterAreaSizes = None self.lateralPanel = None hbox = QHBoxLayout(self) hbox.setContentsMargins(0, 0, 0, 0) hbox.setSpacing(0) #Create Splitters to divide the UI in: MainPanel, Explorer, Misc self._splitterArea = QSplitter(Qt.Horizontal) self._splitterMain = QSplitter(Qt.Vertical) #Create scrollbar for follow mode self.scrollBar = QScrollBar(Qt.Vertical, self) self.scrollBar.setFixedWidth(20) self.scrollBar.setToolTip('Follow Mode: Scroll the Editors together') self.scrollBar.hide() self.scrollBar.valueChanged[int].connect(self.move_follow_scrolls) #Add to Main Layout hbox.addWidget(self.scrollBar) hbox.addWidget(self._splitterArea)
def setupUI(self): """Create User Interface. """ sourceWidget = self.widgetSource() frameWidget = self.widgetFrame() parametersWidget = self.widgetParameters() leftSide = QWidget() leftSide.setLayout(parametersWidget) rightSide = QWidget() rightSide.setLayout(frameWidget) self.hsplitter = QSplitter(QtCore.Qt.Horizontal) self.hsplitter.addWidget(leftSide) self.hsplitter.addWidget(rightSide) self.hsplitter.setStretchFactor(0, 1) self.hsplitter.setStretchFactor(1, 10) downSide = QWidget() downSide.setLayout(self.widgetDebug()) self.vsplitter = QSplitter(QtCore.Qt.Vertical) self.vsplitter.addWidget(self.hsplitter) self.vsplitter.addWidget(downSide) self.vsplitter.setStretchFactor(0, 10) self.vsplitter.setStretchFactor(1, 1) mainLayout = QVBoxLayout() mainLayout.addLayout(sourceWidget) mainLayout.addWidget(self.vsplitter) self.setLayout(mainLayout) self.setGeometry(300, 300, 800, 600) self.show()
def initUI(self): hbox = QHBoxLayout(self) topleft = QFrame(self) topleft.setFrameShape(QFrame.StyledPanel) topright = QFrame(self) topright.setFrameShape(QFrame.StyledPanel) bottom = QFrame(self) bottom.setFrameShape(QFrame.StyledPanel) splitter1 = QSplitter(Qt.Horizontal) splitter1.addWidget(topleft) splitter1.addWidget(topright) splitter2 = QSplitter(Qt.Vertical) splitter2.addWidget(splitter1) splitter2.addWidget(bottom) hbox.addWidget(splitter2) self.setLayout(hbox) self.setGeometry(300, 300, 300, 200) self.setWindowTitle('QSplitter') self.show()
def __init__(self): QWidget.__init__(self) self.sun=1 hbox=QHBoxLayout(self) mainLayout = QSplitter(Qt.Horizontal) # splitter1 = QtGui.QSplitter(QtCore.Qt.Horizontal) self.three_d=display_widget() self.three_d.show() self.frame=layer_widget() self.frame.changed.connect(self.three_d.recalculate) mainLayout.addWidget(self.frame) mainLayout.addWidget(self.three_d) hbox.addWidget(mainLayout) self.setLayout(hbox) if enable_webupdates()==True: print("Looking for updates") self.web_update=update_thread() self.web_update.got_data.connect(self.got_help) self.web_update.start() self.frame.tab.itemSelectionChanged.connect(self.layer_selection_changed)
def initUI(self): self.content = QWidget() self.hbox = QHBoxLayout(self.content) self.setCentralWidget(self.content) self.friend_list = QListWidget() self.friend_list.itemClicked.connect(self.friendClicked) self.message_scroll = QScrollArea() self.message_scroll.setWidgetResizable(True) #TODO have a setting to disable this self.message_scroll.verticalScrollBar().rangeChanged.connect(self.scrollBottom) self.message_input = MessageInput() self.message_input.sendMessage.connect(self.sendMessage) self.message_split = QSplitter(Qt.Vertical) self.message_split.addWidget(self.message_scroll) self.message_split.addWidget(self.message_input) self.main_split = QSplitter(Qt.Horizontal) self.main_split.addWidget(self.friend_list) self.main_split.addWidget(self.message_split) self.hbox.addWidget(self.main_split) self.show()
def __init__(self, orientation=Qt.Vertical): QSplitter.__init__(self, orientation) self.pfile = None self._hsplitter = QSplitter(Qt.Horizontal) self.lateral_widget = lateral_widget.LateralWidget() self._hsplitter.addWidget(self.lateral_widget) self.table_widget = table_widget.TableWidget() self._hsplitter.addWidget(self.table_widget) self.addWidget(self._hsplitter) self.query_container = query_container.QueryContainer(self) self.addWidget(self.query_container) self.modified = False self.__nquery = 1 # Connections # FIXME self.lateral_widget.itemClicked.connect( lambda: self.table_widget.stacked.setCurrentIndex( self.lateral_widget.row())) # For change table widget item when up/down # see issue #39 self.lateral_widget.itemSelectionChanged.connect( lambda: self.table_widget.stacked.setCurrentIndex( self.lateral_widget.row())) self.query_container.saveEditor['PyQt_PyObject'].connect( self.save_query) self.setSizes([1, 1])
def _setupUi(self): self.resize(558, 447) self.mainLayout = QVBoxLayout(self) self.mainLayout.setSpacing(0) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.splitterView = QSplitter() self.splitterView.setChildrenCollapsible(False) self.splitterView.setOrientation(Qt.Vertical) self.subSplitterView = QSplitter() self.subSplitterView.setChildrenCollapsible(False) self.treeView = TreeView(self) self.treeView.setAcceptDrops(True) self.treeView.setFrameShape(QFrame.NoFrame) self.treeView.setFrameShadow(QFrame.Plain) self.treeView.setEditTriggers(QAbstractItemView.EditKeyPressed|QAbstractItemView.SelectedClicked) self.treeView.setDragEnabled(True) self.treeView.setDragDropMode(QAbstractItemView.InternalMove) self.treeView.setUniformRowHeights(True) self.treeView.setAllColumnsShowFocus(True) self.treeView.setSelectionMode(QAbstractItemView.ExtendedSelection) self.treeView.header().setStretchLastSection(False) self.subSplitterView.addWidget(self.treeView) self.pieChart = PieChartView(self) self.pieChart.setMinimumSize(300, 0) self.subSplitterView.addWidget(self.pieChart) self.splitterView.addWidget(self.subSplitterView) self.graphView = LineGraphView(self) self.graphView.setMinimumSize(0, 200) self.splitterView.addWidget(self.graphView) self.splitterView.setStretchFactor(0, 1) self.splitterView.setStretchFactor(1, 0) self.subSplitterView.setStretchFactor(0, 1) self.subSplitterView.setStretchFactor(1, 0) self.mainLayout.addWidget(self.splitterView)
def initUI(self): """Create User Interface. """ sourcePath = self.widgetSourcePath() parameters = self.widgetParameters() scroll = self.widgetImage() debug = self.widgetDebug() vbox1 = QVBoxLayout() vbox1.addLayout(sourcePath) hbox = QHBoxLayout() hbox.addLayout(parameters, 1) hbox.addLayout(scroll, 10) vbox1.addLayout(hbox) upSide = QWidget() upSide.setLayout(vbox1) vbox2 = QVBoxLayout() vbox2.addLayout(debug) downSide = QWidget() downSide.setLayout(vbox2) splitter = QSplitter(QtCore.Qt.Vertical) splitter.addWidget(upSide) splitter.addWidget(downSide) splitter.splitterMoved.connect(self.splitterMoved) mainLayout = QHBoxLayout() mainLayout.addWidget(splitter) self.setLayout(mainLayout) self.setGeometry(300, 300, 300, 150) self.show()
def __init__(self): super().__init__() # information widget self.plotWidget = VariantPlotWidget() self.infoWidget = VariantInfoWidget() # splitter settings splitter = QSplitter(Qt.Horizontal) splitter.addWidget(self.plotWidget) splitter.addWidget(self.infoWidget) splitter.setStretchFactor(0, 3) splitter.setStretchFactor(1, 1) # layout layout = QBoxLayout(QBoxLayout.TopToBottom) layout.addWidget(splitter) self.setLayout(layout) # connect signals self.plotWidget.curvePlotted.connect(self.infoWidget.updateResults) self.plotWidget.plotReady.connect(self.infoWidget.showResults) self.plotWidget.cleared.connect(self.infoWidget.clear) self.infoWidget.legendChanged.connect(self.plotWidget.paintCalculation) # translate the graphical user interface self.retranslateUi()
def doIt(self): self.box = QHBoxLayout(self) # cria uma box para receber os widgets self.gridAStar = Grid(self.width, self.height) # cria um grid para admin os widgets self.gridAStar.changed.connect(self.reDoAStar) # quando a land muda chama o reDo self.gridAStar.setFrameShape(QFrame.StyledPanel) # seta o formato do frame para um quadrado self.gridDfs = Grid(self.width, self.height) self.gridDfs.changed.connect(self.reDoDfs) # quando a land muda chama o reDo self.dfsDestroyed = False self.gridDfs.setFrameShape(QFrame.StyledPanel) self.right = Settings(self.gridAStar, self.gridDfs) # right rrecebe as congiguracoes de campo self.right.changed.connect(self.reDo) # quando a land muda chama o reDo self.right.setFrameShape(QFrame.StyledPanel) # seta o formato do frame para um quadrado self.splitterV = QSplitter(Qt.Vertical) #reorganiza os qFrame's de acordo com o splitter self.splitterV.addWidget(self.gridAStar) self.splitterV.addWidget(self.gridDfs) self.splitterH = QSplitter(Qt.Horizontal) self.splitterH.addWidget(self.splitterV) self.splitterH.addWidget(self.right) self.box.addWidget(self.splitterH) # adiciona o splitter ao boox self.setLayout(self.box) # organiza tudo de acordo com o layout da box self.setWindowTitle('Path Finder') self.reDo() # chama a classe para refazer self.show()
def __init__(self, app, ui): QWidget.__init__(self) center_layout = QVBoxLayout() self.fwidg = QWidget() self.paramfunc = 0 self.c = Communicate() self.c.exec_operation_signal[Myc.FuncCommand].connect(app.exec_command) self.application = app self.setLayout(center_layout) print('ddd') self.ui = ui self.ui.setupUi(self.fwidg) splitter = QSplitter(Qt.Vertical) splitter.addWidget(self.fwidg) buttonExec = QPushButton() buttonExec.setText("Выполнить") center_layout.addWidget(buttonExec) buttonExec.clicked.connect(self.execOperation) splitter.addWidget(buttonExec) center_layout.addWidget(splitter)
def __init__(self, parent): """ Constructor @param parent parent widget (QWidget) """ self.tabWidgets = [] QSplitter.__init__(self, parent) ViewManager.__init__(self) self.setChildrenCollapsible(False) tw = TabWidget(self) self.addWidget(tw) self.tabWidgets.append(tw) self.currentTabWidget = tw self.currentTabWidget.showIndicator(True) tw.currentChanged.connect(self.__currentChanged) tw.installEventFilter(self) tw.tabBar().installEventFilter(self) self.setOrientation(Qt.Vertical) self.__inRemoveView = False self.maxFileNameChars = Preferences.getUI( "TabViewManagerFilenameLength") self.filenameOnly = Preferences.getUI("TabViewManagerFilenameOnly")
class DualFrame(QFrame): def __init__(self, plot_title, finish_creating_plot_gui, is_top_level): QFrame.__init__(self) self.setWindowTitle(plot_title) self.main_layout = QVBoxLayout(self) self.splitter = QSplitter() self.dnd_frame_1 = DndFrame('Output Graphs') self.dnd_frame_2 = DndFrame('Graphs to Display') self.splitter.addWidget(self.dnd_frame_1) self.splitter.addWidget(self.dnd_frame_2) self.main_layout.addWidget(self.splitter) self.button_layout = QHBoxLayout() self.dnd_close_button = PyQtExtras.CommandButton('Close') self.dnd_close_button.set_handler(self.on_close) self.dnd_accept_button = PyQtExtras.CommandButton('Accept') self.dnd_accept_button.set_handler(self.on_accept) self.button_layout.addWidget(self.dnd_close_button) self.button_layout.addWidget(self.dnd_accept_button) self.button_layout.setAlignment(Qt.AlignRight) self.main_layout.addLayout(self.button_layout) self.finish_creating_plot_gui = finish_creating_plot_gui self.is_top_level = is_top_level self.setMinimumSize(QSize(800, 640)) def add_to_first(self, text): self.dnd_frame_1.add_label(text) def add_to_second(self, text): self.dnd_frame_2.add_label(text) def on_accept(self): plots_to_output = self.dnd_frame_1.get_output_plot_filenames() if self.finish_creating_plot_gui != None: self.finish_creating_plot_gui(plots_to_output) self.close() def on_close(self): self.hide() if self.is_top_level: QApplication.exit(0)
def __init__(self, parent=None): super(QMainWindow,self).__init__() #--------------------------------------------------------------- statusWin = QLabel(self) #statusWin = QPlainTextEdit(self) # status window #statusWin.appendHtml("<b>hallo<br>hallo2<br>hallo3</b>") tabWin = TabWidgets(self) # tabbed window print('hint status win: {0}'.format(statusWin.sizeHint())) print('hint_tab win: {0}'.format(tabWin.sizeHint())) print('hint main win: {0}'.format(self.sizeHint())) mSize = QFontMetrics(statusWin.font()) rowHt = mSize.lineSpacing() # fixed height for statusWin needed as the sizeHint of tabWin is very small #statusWin.setFixedHeight(4*rowHt+4) # add status window underneath plot Tab Widgets: spltVMain = QSplitter(QtCore.Qt.Vertical) spltVMain.addWidget(tabWin) spltVMain.addWidget(statusWin) # relative initial sizes of subwidgets, this doesn't work here # spltVMain.setStretchFactor(4,1) spltVMain.setSizes([statusWin.sizeHint().height()*2, statusWin.sizeHint().height()*0.05]) spltVMain.setFocus() # make spltVMain occupy the main area of QMainWindow and set inheritance self.setCentralWidget(spltVMain) print('size tabs: {0}'.format(tabWin.size())) print('size status: {0}'.format(statusWin.size())) print('size self: {0}'.format(self.size()))
def create_mid_group(self): self.ddi_tree = QTreeWidget() self.ddi_tree.itemSelectionChanged.connect(self.show_ddi_details) ddi_details = QGroupBox() ddi_details_layout = QGridLayout() ddi_details_layout.setContentsMargins(0,0,0,0) ddi_details_layout.addWidget(self.create_common_ddi_details(), 0, 0, 1, 1) ddi_details_layout.addWidget(self.create_specific_ddi_details(), 1, 0, 3, 1) ddi_details.setLayout(ddi_details_layout) self.step_tree = QTreeWidget() self.step_tree.itemSelectionChanged.connect(self.show_step_details) step_details = QGroupBox() step_details_layout = QGridLayout() step_details_layout.setContentsMargins(0,0,0,0) step_details_layout.addWidget(self.create_common_step_details(), 0, 0, 1, 1) # step_details_layout.addWidget(self.create_specific_step_details(), 1, 0, 3, 1) step_details.setLayout(step_details_layout) splitter = QSplitter(self) splitter.addWidget(self.ddi_tree) splitter.addWidget(ddi_details) splitter.addWidget(self.step_tree) splitter.addWidget(step_details) hbox = QHBoxLayout() hbox.setContentsMargins(0,0,0,0) # self.__mix_to_layout(hbox, self.ddi_tree, ddi_details, self.step_tree, step_details) hbox.addWidget(splitter) # group_box.setLayout(hbox) return hbox
def __init__(self, parent=None): super().__init__(parent) self.editor = PythonEditor(self) self.resize(650, 500) fileMenu = QMenu(self.tr("&File"), self) fileMenu.addAction(self.tr("&New…"), self.newFile, QKeySequence.New) fileMenu.addAction(self.tr("&Open…"), self.openFile, QKeySequence.Open) fileMenu.addAction(self.tr("&Save"), self.saveFile, QKeySequence.Save) fileMenu.addAction(self.tr("Save &As…"), self.saveFileAs, QKeySequence.SaveAs) fileMenu.addSeparator() fileMenu.addAction(self.tr("&Run…"), self.runScript, "Ctrl+R") fileMenu.addSeparator() fileMenu.addAction(self.tr("&Close"), self.close, platformSpecific.closeKeySequence()) self.menuBar().addMenu(fileMenu) self.fileChooser = FileChooser(self) self.fileChooser.fileOpened.connect(self.openFile) splitter = QSplitter(self) splitter.addWidget(self.fileChooser) splitter.addWidget(self.editor) splitter.setStretchFactor(0, 2) splitter.setStretchFactor(1, 5) splitter.setSizes([0, 1]) self.setCentralWidget(splitter) self.newFile() self.editor.modificationChanged.connect(self.setWindowModified)
def sig_to_stems_clicked(self, row): signature = self.sig_to_stems_major_table.item(row, 0).text() print(signature) signature = tuple(signature.split(SEP_SIG)) stems = sorted(self.lexicon.signatures_to_stems()[signature]) number_of_stems_per_column = 5 # create a master list of sublists, where each sublist contains k stems # k = number_of_stems_per_column stem_rows = list() stem_row = list() for i, stem in enumerate(stems, 1): stem_row.append(stem) if not i % number_of_stems_per_column: stem_rows.append(stem_row) stem_row = list() if stem_row: stem_rows.append(stem_row) # set up the minor table as table widget sig_to_stems_minor_table = QTableWidget() sig_to_stems_minor_table.horizontalHeader().hide() sig_to_stems_minor_table.verticalHeader().hide() sig_to_stems_minor_table.clear() sig_to_stems_minor_table.setRowCount(len(stem_rows)) sig_to_stems_minor_table.setColumnCount(number_of_stems_per_column) # fill in the minor table for row, stem_row in enumerate(stem_rows): for col, stem in enumerate(stem_row): item = QTableWidgetItem(stem) sig_to_stems_minor_table.setItem(row, col, item) sig_to_stems_minor_table.resizeColumnsToContents() minor_table_title = QLabel('{} (number of stems: {})' .format(SEP_SIG.join(signature), len(stems))) minor_table_widget_with_title = QWidget() layout = QVBoxLayout() layout.addWidget(minor_table_title) layout.addWidget(sig_to_stems_minor_table) minor_table_widget_with_title.setLayout(layout) new_display = QSplitter(Qt.Horizontal) new_display.setHandleWidth(10) new_display.setChildrenCollapsible(False) new_display.addWidget(self.sig_to_stems_major_table) new_display.addWidget(minor_table_widget_with_title) new_display_width = self.majorDisplay.width() / 2 new_display.setSizes( [new_display_width * 0.4, new_display_width * 0.6]) self.load_main_window(major_display=new_display) self.status.clearMessage() self.status.showMessage('{} selected'.format(signature))
def showEvent(self, event): QSplitter.showEvent(self, event) qsettings = QSettings(settings.SETTINGS_PATH, QSettings.IniFormat) hsizes = qsettings.value('hsplitter_sizes', None) if hsizes is not None: self._hsplitter.restoreState(hsizes) else: self._hsplitter.setSizes([1, self._hsplitter.width() / 3]) vsizes = qsettings.value('vsplitter_sizes', None) if vsizes is not None: self.restoreState(vsizes) else: self.setSizes([self.height() / 3, self.height() / 3])
def __init__(self): QSplitter.__init__(self) self.setObjectName("main_container") self.main_tab = tab_manager.TabManager() self.secundary_tab = tab_manager.TabManager() self.secundary_tab.hide() self.tab = self.main_tab self.addWidget(self.main_tab) self.addWidget(self.secundary_tab) Amaru.load_component("main_container", self) self.fileChanged.connect(self._file_changed) self.tab.currentChanged[int].connect(self._current_tab_changed) self.tab.allTabsClosed.connect(self._all_tabs_closed)
def __init__(self): super(MainWindow, self).__init__() self.createActions() self.createMenus() # self.createToolBars() self.createStatusBar() treeLeft = FileTree() treeRight = FileTree() sp = QSplitter(Qt.Horizontal) sp.addWidget(treeLeft) sp.addWidget(treeRight) self.setCentralWidget(sp) self.resize(640, 480)
def initUI(self): ''' Example hbox splitter2 splitter1 topleft vbox self.lbl combo topright bottom ''' # splitter hbox = QHBoxLayout(self) topleft = QFrame(self) topleft.setFrameShape(QFrame.StyledPanel) topright = QFrame(self) topright.setFrameShape(QFrame.StyledPanel) bottom = QFrame(self) bottom.setFrameShape(QFrame.StyledPanel) splitter1 = QSplitter(Qt.Horizontal) splitter1.addWidget(topleft) splitter1.addWidget(topright) splitter2 = QSplitter(Qt.Vertical) splitter2.addWidget(splitter1) splitter2.addWidget(bottom) hbox.addWidget(splitter2) self.setLayout(hbox) # combo self.lbl = QLabel("Ubuntu", self) combo = QComboBox(self) combo.addItem("Ubuntu") combo.addItem("Mandriva") combo.addItem("Fedora") combo.addItem("Arch") combo.addItem("Gentoo") combo.activated[str].connect(self.onActivated) # put combo and label into layout into frame vbox = QVBoxLayout(topleft) vbox.addWidget(self.lbl) vbox.addWidget(combo) self.setGeometry(300, 300, 300, 200) self.setWindowTitle('QSplitter') self.show()
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.container = QSplitter(self) self.setCentralWidget(self.container) #mon = DMX_Monitor(self) mon = None self.container.addWidget(ControlPanel(self, mon)) if mon: self.container.addWidget(mon) self.createActions() self.createMenus() self.createStatusBar() def about(self): QMessageBox.about(self, "About Application", __main__.__doc__) def createActions(self): self.exitAct = QAction("E&xit", self, shortcut="Ctrl+Q", statusTip="Exit the application", triggered=self.close) 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.exitAct) self.helpMenu = self.menuBar().addMenu("&About") self.helpMenu.addAction(self.aboutAct) self.helpMenu.addAction(self.aboutQtAct) def createStatusBar(self): self.statusBar().showMessage("Ready")
def setup(self, theme): """ Sets up the window. Defines the various attributes of the window and defines how the user interface is laid out. """ self.theme = theme # Give the window a default icon, title and minimum size. self.setWindowIcon(load_icon(self.icon)) self.update_title() self.setMinimumSize(800, 600) self.widget = QWidget() self.splitter = QSplitter(Qt.Vertical) widget_layout = QVBoxLayout() self.widget.setLayout(widget_layout) self.button_bar = ButtonBar(self.widget) self.tabs = QTabWidget() self.tabs.setTabsClosable(True) self.tabs.tabCloseRequested.connect(self.tabs.removeTab) widget_layout.addWidget(self.button_bar) widget_layout.addWidget(self.splitter) self.splitter.addWidget(self.tabs) self.addWidget(self.widget) self.setCurrentWidget(self.widget) self.set_theme(theme) self.show() self.autosize_window()
def set_splitter_stylesheet(splitter: QSplitter): splitter.setHandleWidth(4) bgcolor = constants.BGCOLOR.lighter(150) r, g, b, a = bgcolor.red(), bgcolor.green(), bgcolor.blue(), bgcolor.alpha() splitter.setStyleSheet("QSplitter::handle:vertical {{margin: 4px 0px; " "background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, " "stop:0.2 rgba(255, 255, 255, 0)," "stop:0.5 rgba({0}, {1}, {2}, {3})," "stop:0.8 rgba(255, 255, 255, 0));" "image: url(:/icons/icons/splitter_handle_horizontal.svg);}}" "QSplitter::handle:horizontal {{margin: 4px 0px; " "background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, " "stop:0.2 rgba(255, 255, 255, 0)," "stop:0.5 rgba({0}, {1}, {2}, {3})," "stop:0.8 rgba(255, 255, 255, 0));" "image: url(:/icons/icons/splitter_handle_vertical.svg);}}".format(r, g, b, a))
def setup(self, theme, api=None): """ Sets up the window. Defines the various attributes of the window and defines how the user interface is laid out. """ self.theme = theme self.api = api if api else [] # Give the window a default icon, title and minimum size. self.setWindowIcon(load_icon(self.icon)) self.update_title() self.setMinimumSize(926, 600) self.widget = QWidget() self.splitter = QSplitter(Qt.Vertical) widget_layout = QVBoxLayout() self.widget.setLayout(widget_layout) self.button_bar = ButtonBar(self.widget) widget_layout.addWidget(self.button_bar) widget_layout.addWidget(self.splitter) self.tabs = FileTabs() self.splitter.addWidget(self.tabs) self.addWidget(self.widget) self.setCurrentWidget(self.widget) self.set_theme(theme) self.show() self.autosize_window()
def populate_central_widget(self): self.vertical_widgets = collections.OrderedDict() self.horizontal_splitter = QSplitter( Qt.Horizontal, self.vertical_splitter) self.horizontal_widgets = collections.OrderedDict() self.vertical_widgets["horizontal_splitter"] = self.horizontal_splitter Alter.invoke_all( 'main_window_add_vertical_widget', self.vertical_widgets, self ) for widget in self.vertical_widgets.values(): self.vertical_splitter.addWidget(widget) Alter.invoke_all( 'main_window_add_horizontal_widget', self.horizontal_widgets, self.vertical_splitter ) for widget in self.horizontal_widgets.values(): self.horizontal_splitter.addWidget(widget) #restore horizontal splitter state state = ModuleManager.core['settings'].Settings.value( self.KEY_H_SPLITTER_STATE, None ) if state: self.horizontal_splitter.restoreState(state)
def __init__(self): # Parent constructor(s) QMainWindow.__init__(self) self.controller = None # Main widget self.mainWidget = QWidget(self) self.setCentralWidget(self.mainWidget) self.setWindowTitle("dotEd") # Menu self.createMenu() # Status bar just for a test self.statusBar().showMessage("Double click to create a node") # Layout/Splitter which will contain all widgets self.splitter = QSplitter(Qt.Horizontal) layout = QVBoxLayout(self.mainWidget) layout.addWidget(self.splitter) # Clear graph button clearGraphButton = QPushButton("Clear graph") clearGraphButton.clicked.connect(self.onClearGraph) layout.addWidget(clearGraphButton)
def setupUI(self): """Create User Interface. """ mainWidget = QWidget() mainLayout = QHBoxLayout() tabs = QTabWidget() self.classes_tree_view = ClassesTreeView(self) tabs.addTab(self.widgetDataset(), self.tr("Dataset")) tabs.addTab(self.widgetTraining(), self.tr("Training")) tabs.addTab(self.widgetRecognition(), self.tr("Recognition")) leftLayout, rightLayout = QHBoxLayout(), QHBoxLayout() leftLayout.addWidget(self.classes_tree_view) rightLayout.addWidget(tabs) left, right = QWidget(), QWidget() left.setLayout(leftLayout) right.setLayout(rightLayout) self.hsplitter = QSplitter(QtCore.Qt.Horizontal) self.hsplitter.addWidget(left) self.hsplitter.addWidget(right) self.hsplitter.setStretchFactor(1, 3) mainLayout.addWidget(self.hsplitter) mainWidget.setLayout(mainLayout) self.setCentralWidget(mainWidget)
def setup_layout(self): main_widget = QWidget() main_layout = QHBoxLayout() main_layout_splitter = QSplitter(Qt.Horizontal, self) main_widget.setLayout(main_layout) main_layout.addWidget(main_layout_splitter) main_layout_splitter.addWidget(self.selection_list) main_layout_splitter.addWidget(self.view_tabs) main_layout_splitter.setStretchFactor(0, 1) main_layout_splitter.setStretchFactor(1, 10) self.setCentralWidget(main_widget)
def initUI(self): """Override.""" self._cw = QSplitter(Qt.Vertical) for img, fom_hist, roi_hist in zip(self._poi_imgs, self._poi_fom_hists, self._poi_roi_hists): rw = QSplitter(Qt.Vertical) rw.addWidget(fom_hist) rw.addWidget(roi_hist) w = QSplitter() w.addWidget(img) w.addWidget(rw) w.setSizes([self._TOTAL_W / 2, self._TOTAL_W / 2]) self._cw.addWidget(w) self.setCentralWidget(self._cw) self._cw.setHandleWidth(self._SPLITTER_HANDLE_WIDTH)
class LossVisualizer(QWidget): def __init__(self, mat_output_node: GMaterialOutputNode): super().__init__(parent=None) self._mat_out_node = mat_output_node # Declare widgets self._layout = QGridLayout() self._splitter = QSplitter(Qt.Horizontal) self._plot = PlotWidget3D() self._canvas = self._plot.get_canvas() self._fig_ax = self._plot.get_axis() self._table_widget = QTableWidget(self) self._p1_res = IntInput(0, 100) self._p2_res = IntInput(0, 100) self._plot_button = QPushButton("Plot Loss") self._start_gd_button = QPushButton("Start Gradient Descent") # Declare data self._item_queue = FIFOQueue(maxsize=2) self._bg_brush_selected = QBrush(QColor("#8bf9b0")) self._bg_brush_default = QBrush(QColor("#ffffff")) self._settings = None self._target_image = None self._target_matrix = None self._out_node = None self._thread = None self._gd = None self._p1 = None self._p2 = None self._hist_p1 = [] self._hist_p2 = [] self._plot_line3d = None self._progress_dialog = None self._init() self._list_parameters() def _init(self): self.setWindowTitle("Loss Visualizer") # Setup table widget self._table_widget.setColumnCount(3) self._table_widget.setHorizontalHeaderLabels( ["Parameter", "Min", "Max"]) self._table_widget.setColumnWidth(1, 50) self._table_widget.setColumnWidth(2, 50) # Setup plot self._fig_ax.set_title("Loss Surface") self._fig_ax.set_xlabel("Parameter ?") self._fig_ax.set_ylabel("Parameter ?") self._fig_ax.set_zlabel("Loss Value") # Setup resolution input self._p1_res.set_value(20) self._p2_res.set_value(20) p1_module = Module("Param 1 Res.", self._p1_res) p2_module = Module("Param 2 Res.", self._p2_res) # Setup buttons self._plot_button.clicked.connect(self._plot_loss) self._start_gd_button.clicked.connect(self._start_gd) self._start_gd_button.setEnabled(False) # Add widgets to layout self._splitter.addWidget(self._table_widget) self._splitter.addWidget(self._plot) self._layout.addWidget(self._splitter, 0, 0, 1, 5) self._layout.addWidget(p1_module, 1, 1) self._layout.addWidget(p2_module, 1, 2) self._layout.addWidget(self._plot_button, 1, 3) self._layout.addWidget(self._start_gd_button, 1, 4) self.setLayout(self._layout) def _list_parameters(self): _, param_dict = self._mat_out_node.get_backend_node().render( 10, 10, retain_graph=True) row = 0 self._table_widget.setRowCount(len(param_dict)) for key in param_dict: param = param_dict[key] param.set_modified_arg(key) limits = param.get_limits() diff = limits[1] - limits[0] min_item = FloatInput(limits[0] - diff, limits[1] + diff) min_item.set_value(limits[0]) max_item = FloatInput(limits[0] - diff, limits[1] + diff) max_item.set_value(limits[1]) item = CheckboxItem(key, content={"param": param, "index": -1}) item.state_changed.connect(self._item_state_changed) self._table_widget.setCellWidget(row, 0, item) self._table_widget.setCellWidget(row, 1, min_item) self._table_widget.setCellWidget(row, 2, max_item) row += 1 if param.is_vector(): item.set_checkable(False) item.setEnabled(False) for i in range(param.shape()[1]): self._table_widget.insertRow(row) min_item = FloatInput(limits[0], limits[1]) min_item.set_value(limits[0]) max_item = FloatInput(limits[0], limits[1]) max_item.set_value(limits[1]) sub_item = CheckboxItem(" [{}]".format(i), content={ "param": param, "index": i }) sub_item.state_changed.connect(self._item_state_changed) self._table_widget.setCellWidget(row, 0, sub_item) self._table_widget.setCellWidget(row, 1, min_item) self._table_widget.setCellWidget(row, 2, max_item) row += 1 self._table_widget.resizeColumnToContents(0) self._table_widget.resizeRowsToContents() def _checked_items( self) -> typing.List[typing.Tuple[QWidget, QWidget, QWidget]]: checked = [] for i in range(self._table_widget.rowCount()): item = self._table_widget.cellWidget(i, 0) min_item = self._table_widget.cellWidget(i, 1) max_item = self._table_widget.cellWidget(i, 2) if item.get_state() == Qt.Checked: checked.append((item, min_item, max_item)) return checked def _item_state_changed(self, item: CheckboxItem): if item.get_state() == Qt.Checked: if self._item_queue.is_full(): first_item = self._item_queue.pop() first_item.set_state(Qt.Unchecked) self._item_queue.put(item) elif item.get_state() == Qt.Unchecked: if item in self._item_queue: self._item_queue.remove(item) def _plot_loss(self): self._fig_ax.clear() W, H = self._settings.render_width, self._settings.render_height R1, R2 = self._p1_res.get_gl_value(), self._p2_res.get_gl_value() progress_dialog = QProgressDialog("Calculating loss surface...", "Cancel", 0, R1 - 1, self) progress_dialog.setWindowTitle("Calculating") progress_dialog.setWindowModality(Qt.WindowModal) progress_dialog.setMinimumDuration(1) self._target_matrix = image_funcs.image_to_tensor( self._target_image, (W, H)) loss_surface = np.empty((R1, R2)) loss_f = self._settings.loss_func(**self._settings.loss_args) checked_items = self._checked_items() item1 = checked_items[0][0] item1_min = checked_items[0][1].get_gl_value() item1_max = checked_items[0][2].get_gl_value() self._fig_ax.set_xlabel(item1.label) self._p1: Parameter = item1.content["param"] p1_index = item1.content["index"] self._p1.save_value() p1_values = torch.from_numpy( np.linspace(item1_min, item1_max, num=R1, endpoint=True)) item2 = checked_items[1][0] item2_min = checked_items[1][1].get_gl_value() item2_max = checked_items[1][2].get_gl_value() self._fig_ax.set_ylabel(item2.label) self._p2: Parameter = item2.content["param"] p2_index = item2.content["index"] self._p2.save_value() p2_values = torch.from_numpy( np.linspace(item2_min, item2_max, num=R2, endpoint=True)) min_loss = np.finfo(np.float32).max min_loss_p1 = None min_loss_p2 = None for i in range(R1): self._p1.set_value(p1_values[i], index=p1_index) progress_dialog.setValue(i) if progress_dialog.wasCanceled(): return for j in range(R2): self._p2.set_value(p2_values[j], index=p2_index) r, _ = self._mat_out_node.get_backend_node().render( W, H, retain_graph=True) loss = loss_f( r, self._target_matrix).detach().clone().cpu().numpy() if loss < min_loss: min_loss = loss min_loss_p1 = self._p1.get_value(p1_index) min_loss_p2 = self._p2.get_value(p2_index) loss_surface[i, j] = loss _logger.info("{:.2f}% complete...".format((i + 1) / R1 * 100)) P1, P2 = torch.meshgrid([p1_values, p2_values]) self._p1.restore_value() self._p2.restore_value() self._fig_ax.plot_surface(P1, P2, loss_surface, cmap=plt.cm.viridis) self._fig_ax.set_zlim(bottom=0) # Add min value marker self._fig_ax.plot([min_loss_p1], [min_loss_p2], [min_loss], marker='+', color="#ff00ff", markersize=14, markeredgewidth=2.5) # self._fig_ax.text(min_loss_p1, min_loss_p2, min_loss * 1.1, "Minimum Loss = {:.4f}".format(float(min_loss)), color='#ff00ff') self._canvas.draw() self._start_gd_button.setEnabled(True) def _start_gd(self): self._hist_p2 = np.empty(self._settings.max_iter) self._hist_p1 = np.empty(self._settings.max_iter) self._progress_dialog = QProgressDialog( "Performing Gradient Descent...", "Cancel", 0, self._settings.max_iter, self) self._progress_dialog.setWindowTitle("Calculating") self._progress_dialog.setWindowModality(Qt.WindowModal) self._progress_dialog.setMinimumDuration(1) checked_items = self._checked_items() params = { i[0].content["param"].get_modified_arg(): i[0].content["param"] for i in checked_items } self._gd = GradientDescent(self._target_image, self._out_node, self._settings) self._gd.set_active_parameters(params) self._thread = QThread() self._gd.iteration_done.connect(self._gd_callback) self._gd.moveToThread(self._thread) self._thread.started.connect(self._gd.run) self._gd.finished.connect(self._finish_gradient_descent) _logger.debug("Started Gradient Descent Thread...") self._thread.start() def _gd_callback(self, info: dict): params = info["params"] i = info["iter"] loss = info["loss"] self._progress_dialog.setValue(i) if self._progress_dialog.wasCanceled(): self._gd.stop() self._thread.quit() x = params[self._p1.get_modified_arg()] y = params[self._p2.get_modified_arg()] self._hist_p1[i] = x self._hist_p2[i] = y _logger.debug("{}. Loss: {}, P1: {}, P2: {}".format(i, loss, x, y)) def _finish_gradient_descent(self, params, loss_hist, _): if self._thread.isRunning(): _logger.info("Stopping Gradient Descent Thread...") self._gd.stop() self._thread.quit() self._gd.restore_params() self._progress_dialog.setValue(self._progress_dialog.maximum()) # Plot dis shit! num_iter = len(loss_hist) x = params[self._p1.get_modified_arg()] y = params[self._p2.get_modified_arg()] self._hist_p1[num_iter - 1] = x.get_value() self._hist_p2[num_iter - 1] = y.get_value() xs = self._hist_p1[0:num_iter] ys = self._hist_p2[0:num_iter] self._fig_ax.set_title("HSV Shader Loss Surface", fontsize=18) self._fig_ax.plot(xs, ys, loss_hist, color="#ff656dff", marker="o", mfc="#c44e52ff", mec="#ff656dff", lw=2) self._fig_ax.set_xlabel("Hue") self._fig_ax.set_ylabel("Saturation") self._fig_ax.set_zlabel("Loss") self._canvas.draw() self._canvas.flush_events() def open(self, settings: GradientDescentSettings, target: Image, mat_out_node: GMaterialOutputNode): if target is None: msg = QMessageBox( QMessageBox.Warning, "Need to set Target Texture!", "Can not open loss visualizer because target texture is not set." ) msg.exec() else: self._settings = settings self._target_image = target self._out_node = mat_out_node super().show()
class MainWindow(QWidget): def __init__(self, game): super().__init__() self.__model = None self.__game = game self.__game_widget = GameWidget(game) self.__game_widget.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) game.start(self.__game_widget) self.__models = [ OneDimensionalModelWrapper1(), OneDimensionalModelWrapper2(), OneDimensionalModelWrapper3(), OneDimensionalModelWrapper(), TwoDimensionalModelWrapper(), ] for model in self.__models: model.model_changing_callback = self.model_changing self.__model_plot = PlotWidget() self.__model_label = QLabel("Model") self.__model_selector = QComboBox(self) self.__config_layout = QGridLayout(self) self.__config_layout.setColumnStretch(1, 2) self.__config_layout.addWidget(self.__model_label) self.__config_layout.addWidget(self.__model_selector) self.__config_widget = QGroupBox(self) self.__config_widget.setLayout(self.__config_layout) self.__left_side_layout = QVBoxLayout(self) self.__left_side_layout.addWidget(self.__config_widget) self.__left_side_layout.addWidget(self.__game_widget) self.__left_side_widget = QWidget(self) self.__left_side_widget.setLayout(self.__left_side_layout) self.__splitter = QSplitter(Qt.Horizontal) self.__splitter.addWidget(self.__left_side_widget) self.__splitter.addWidget(self.__model_plot) self.__splitter.setStretchFactor(0, 4) self.__splitter.setStretchFactor(1, 1) self.__layout = QHBoxLayout(self) self.__layout.addWidget(self.__splitter) self.setLayout(self.__layout) self.__model_selector.currentIndexChanged.connect(self.model_changed) for model in self.__models: self.__model_selector.addItem(model.get_name()) def model_changing(self, model, changing): if changing: self.__game.set_model(None) else: self.__game.set_model(self.__model) self.__model_plot.set_model(model) def __remove_current_model_config_widgets(self): if self.__model is None: return for old_widget in self.__model.get_config_widgets(): old_widget.hide() self.__config_layout.removeWidget(old_widget) self.__config_layout.setColumnStretch(1, 2) def __add_current_model_config_widgets(self): if self.__model is None: return for new_widget in self.__model.get_config_widgets(): new_widget.show() self.__config_layout.addWidget(new_widget) self.__config_layout.setColumnStretch(1, 2) def model_changed(self, index): self.__game.stop() self.__remove_current_model_config_widgets() self.__model = self.__models[index] self.__model.clear_points() self.__add_current_model_config_widgets() self.__model_plot.set_model(self.__model) self.__game.set_model(self.__model) self.__game.restart()
class PrioritizeDialog(QDialog): def __init__(self, parent, app, **kwargs): flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint super().__init__(parent, flags, **kwargs) self._setupUi() self.model = PrioritizeDialogModel(app=app.model) self.categoryList = ComboboxModel(model=self.model.category_list, view=self.categoryCombobox) self.criteriaList = ListviewModel(model=self.model.criteria_list, view=self.criteriaListView) self.prioritizationList = PrioritizationList( model=self.model.prioritization_list, view=self.prioritizationListView) self.model.view = self self.addCriteriaButton.clicked.connect(self.model.add_selected) self.removeCriteriaButton.clicked.connect(self.model.remove_selected) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) def _setupUi(self): self.setWindowTitle(tr("Re-Prioritize duplicates")) self.resize(700, 400) # widgets msg = tr( "Add criteria to the right box and click OK to send the dupes that correspond the " "best to these criteria to their respective group's " "reference position. Read the help file for more information.") self.promptLabel = QLabel(msg) self.promptLabel.setWordWrap(True) self.categoryCombobox = QComboBox() self.criteriaListView = QListView() self.addCriteriaButton = QPushButton( self.style().standardIcon(QStyle.SP_ArrowRight), "") self.removeCriteriaButton = QPushButton( self.style().standardIcon(QStyle.SP_ArrowLeft), "") self.prioritizationListView = QListView() self.prioritizationListView.setAcceptDrops(True) self.prioritizationListView.setDragEnabled(True) self.prioritizationListView.setDragDropMode( QAbstractItemView.InternalMove) self.prioritizationListView.setSelectionBehavior( QAbstractItemView.SelectRows) self.buttonBox = QDialogButtonBox() self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) # layout self.mainLayout = QVBoxLayout(self) self.mainLayout.addWidget(self.promptLabel) self.splitter = QSplitter() sp = self.splitter.sizePolicy() sp.setVerticalPolicy(QSizePolicy.Expanding) self.splitter.setSizePolicy(sp) self.leftSide = QWidget() self.leftWidgetsLayout = QVBoxLayout() self.leftWidgetsLayout.addWidget(self.categoryCombobox) self.leftWidgetsLayout.addWidget(self.criteriaListView) self.leftSide.setLayout(self.leftWidgetsLayout) self.splitter.addWidget(self.leftSide) self.rightSide = QWidget() self.rightWidgetsLayout = QHBoxLayout() self.addRemoveButtonsLayout = QVBoxLayout() self.addRemoveButtonsLayout.addItem(verticalSpacer()) self.addRemoveButtonsLayout.addWidget(self.addCriteriaButton) self.addRemoveButtonsLayout.addWidget(self.removeCriteriaButton) self.addRemoveButtonsLayout.addItem(verticalSpacer()) self.rightWidgetsLayout.addLayout(self.addRemoveButtonsLayout) self.rightWidgetsLayout.addWidget(self.prioritizationListView) self.rightSide.setLayout(self.rightWidgetsLayout) self.splitter.addWidget(self.rightSide) self.mainLayout.addWidget(self.splitter) self.mainLayout.addWidget(self.buttonBox)
def initUI(self): hbox = QHBoxLayout(self) topleft = QFrame(self) topleft.setFrameShape(QFrame.StyledPanel) #add button in left frame btn = QPushButton('button', topleft) btn.setFixedSize(50, 20) btn.move(50,50) topright = QFrame(self) topright.setFrameShape(QFrame.StyledPanel) #add text Edit in right frame self.text2=QTextEdit('textedit2 ',topright) self.text2.setFixedSize(100,100) bottom = QFrame(self) bottom.setFrameShape(QFrame.StyledPanel) self.text1=QTextEdit(' ',bottom) self.text1.setFixedSize(100,100) btn.clicked.connect(self.aaaa) def aaaa(self): print('1') textfrlabel=self.text2.text() print('2') self.text1.setText(textfrlabel) splitter1 = QSplitter(Qt.Horizontal) splitter1.addWidget(topleft) splitter1.addWidget(topright) splitter2 = QSplitter(Qt.Vertical) splitter2.addWidget(splitter1) splitter2.addWidget(bottom) hbox.addWidget(splitter2) self.setLayout(hbox) self.setGeometry(300, 300, 300, 200) self.setWindowTitle('QSplitter') self.show()
def __init__(self, parent=None): # pylint: disable=too-many-statements super(ModulesPanel, self).__init__(parent) self._app_window = parent if self._app_window.dwarf is None: print('ModulesPanel created before Dwarf exists') return self._app_window.dwarf.onSetModules.connect(self.set_modules) self._app_window.dwarf.onModuleLoaded.connect(self.on_module_loaded) self._uppercase_hex = True self._sized = False self.setContentsMargins(0, 0, 0, 0) # setup models self.modules_list = None self.modules_model = QStandardItemModel(0, 4, self) self.modules_model.setHeaderData(0, Qt.Horizontal, 'Name') self.modules_model.setHeaderData(1, Qt.Horizontal, 'Base') self.modules_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self.modules_model.setHeaderData(2, Qt.Horizontal, 'Size') self.modules_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self.modules_model.setHeaderData(3, Qt.Horizontal, 'Path') self.imports_list = None self.imports_model = QStandardItemModel(0, 4, self) self.imports_model.setHeaderData(0, Qt.Horizontal, 'Import') self.imports_model.setHeaderData(1, Qt.Horizontal, 'Address') self.imports_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self.imports_model.setHeaderData(2, Qt.Horizontal, 'Module') self.imports_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self.imports_model.setHeaderData(3, Qt.Horizontal, 'Type') self.exports_list = None self.exports_model = QStandardItemModel(0, 3, self) self.exports_model.setHeaderData(0, Qt.Horizontal, 'Export') self.exports_model.setHeaderData(1, Qt.Horizontal, 'Address') self.exports_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self.exports_model.setHeaderData(2, Qt.Horizontal, 'Type') self.symbols_list = None self.symbols_model = QStandardItemModel(0, 3, self) self.symbols_model.setHeaderData(0, Qt.Horizontal, 'Symbol') self.symbols_model.setHeaderData(1, Qt.Horizontal, 'Address') self.symbols_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self.symbols_model.setHeaderData(2, Qt.Horizontal, 'Type') # setup ui self.modules_list = DwarfListView() self.modules_list.setContextMenuPolicy(Qt.CustomContextMenu) self.modules_list.customContextMenuRequested.connect( self._on_modules_contextmenu) self.modules_list.setEditTriggers(self.modules_list.NoEditTriggers) self.modules_list.clicked.connect(self._module_clicked) self.modules_list.doubleClicked.connect(self._module_dblclicked) self.modules_list.setModel(self.modules_model) self.modules_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.modules_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self.modules_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self.modules_list.selectionModel().selectionChanged.connect( self._module_clicked) self.addWidget(self.modules_list) v_splitter = QSplitter(Qt.Vertical) self.imports_list = DwarfListView() self.imports_list.setContextMenuPolicy(Qt.CustomContextMenu) self.imports_list.customContextMenuRequested.connect( self._on_imports_contextmenu) self.imports_list.setEditTriggers(self.modules_list.NoEditTriggers) self.imports_list.doubleClicked.connect(self._import_dblclicked) self.imports_list.setModel(self.imports_model) self.imports_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.imports_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self.imports_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self.imports_list.setVisible(False) self.exports_list = DwarfListView() self.exports_list.setContextMenuPolicy(Qt.CustomContextMenu) self.exports_list.customContextMenuRequested.connect( self._on_exports_contextmenu) self.exports_list.setEditTriggers(self.modules_list.NoEditTriggers) self.exports_list.doubleClicked.connect(self._export_dblclicked) self.exports_list.setModel(self.exports_model) self.exports_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.exports_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self.exports_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self.exports_list.setVisible(False) self.symbols_list = DwarfListView() self.symbols_list.setContextMenuPolicy(Qt.CustomContextMenu) self.symbols_list.doubleClicked.connect(self._symbol_dblclicked) self.symbols_list.setModel(self.symbols_model) self.symbols_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.symbols_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self.symbols_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self.symbols_list.setVisible(False) v_splitter.addWidget(self.imports_list) v_splitter.addWidget(self.exports_list) v_splitter.addWidget(self.symbols_list) v_splitter.setSizes([100, 100, 100]) self.addWidget(v_splitter)
def __init__(self, h, v, parent=None): super(MyGUI, self).__init__(parent) self.points = obj.PointObjects({ '_ids': ['tether_Atrium', 'tether_Ventricle', 'AVCanal', 'Midline'], 'colors': ['#6eadd8', '#ff7f0e', 'red', '#c4c4c4'], 'markers': ['o', 'o', 'X', '-x'], 'ms': [3, 3, 5, 5], 'is_instance': [0, 0, 0, 0], 'coords': [np.array([])] * 4 }) self.file_name = '' self.stacks = np.zeros((3, 3, 2, v, h)) self.channels = ['ch0', 'ch1'] self.widgets = {} self.createLoadSaveGroupBox() self.createObjectsControlGroupBox() self.createTZCControlGroupBox() self.createCanvas2DGroupBox() self.createCanvas3DGroupBox() self.setEnableState(False) mainLayout = QVBoxLayout() split3 = QSplitter(Qt.Vertical) split3.setMinimumWidth(0) split1 = QSplitter(Qt.Horizontal) split2 = QSplitter(Qt.Horizontal) split3.addWidget(self.groupObjectsControl) split3.addWidget(self.groupTZCControl) split2.addWidget(self.groupCanvas2DBox) split2.addWidget(self.groupCanvas3DBox) split1.addWidget(split3) split1.addWidget(split2) mainLayout.addWidget(self.groupLoadSave) mainLayout.addWidget(split1) self.setLayout(mainLayout) self.resize(1.2 * 960, 1.2 * 413) self.setWindowTitle('Manual annotation tool') QApplication.setStyle('Macintosh')
def __InitView(self): ''' 初始化界面 ''' self.setFixedSize(800, 600) self.setWindowTitle("画笔") # 新建一个水平布局作为本窗体的主布局 main_layout = QHBoxLayout(self) # 设置主布局内边距以及控件间距为10px main_layout.setSpacing(10) # 在主界面左侧放置画板 main_layout.addWidget(self.__paintBoard) # 新建垂直子布局用于放置按键 sub_layout = QVBoxLayout() # 设置此子布局和内部控件的间距为10px sub_layout.setContentsMargins(10, 10, 10, 10) self.__btn_Clear = QPushButton("清空画板") self.__btn_Clear.setParent(self) # 设置父对象为本界面 # 将按键按下信号与画板清空函数相关联 self.__btn_Clear.clicked.connect(self.__paintBoard.Clear) sub_layout.addWidget(self.__btn_Clear) self.__btn_Quit = QPushButton("退出") self.__btn_Quit.setParent(self) # 设置父对象为本界面 self.__btn_Quit.clicked.connect(self.Quit) sub_layout.addWidget(self.__btn_Quit) self.__btn_Save = QPushButton("保存作品") self.__btn_Save.setParent(self) self.__btn_Save.clicked.connect(self.on_btn_Save_Clicked) sub_layout.addWidget(self.__btn_Save) self.__cbtn_Eraser = QCheckBox(" 使用橡皮擦") self.__cbtn_Eraser.setParent(self) self.__cbtn_Eraser.clicked.connect(self.on_cbtn_Eraser_clicked) sub_layout.addWidget(self.__cbtn_Eraser) splitter = QSplitter(self) # 占位符 sub_layout.addWidget(splitter) self.__label_penThickness = QLabel(self) self.__label_penThickness.setText("画笔粗细") self.__label_penThickness.setFixedHeight(20) sub_layout.addWidget(self.__label_penThickness) self.__spinBox_penThickness = QSpinBox(self) self.__spinBox_penThickness.setMaximum(20) self.__spinBox_penThickness.setMinimum(2) self.__spinBox_penThickness.setValue(10) # 默认粗细为10 self.__spinBox_penThickness.setSingleStep(2) # 最小变化值为2 self.__spinBox_penThickness.valueChanged.connect( self.on_PenThicknessChange ) # 关联spinBox值变化信号和函数on_PenThicknessChange sub_layout.addWidget(self.__spinBox_penThickness) self.__label_penColor = QLabel(self) self.__label_penColor.setText("画笔颜色") self.__label_penColor.setFixedHeight(20) sub_layout.addWidget(self.__label_penColor) self.__comboBox_penColor = QComboBox(self) self.__fillColorList(self.__comboBox_penColor) # 用各种颜色填充下拉列表 self.__comboBox_penColor.currentIndexChanged.connect( self.on_PenColorChange) # 关联下拉列表的当前索引变更信号与函数on_PenColorChange sub_layout.addWidget(self.__comboBox_penColor) main_layout.addLayout(sub_layout) # 将子布局加入主布局
def initUI(self): hbox = QHBoxLayout(self) # 칸마다 경계를 나누기 위해 StyledPanel 사용 topleft = QFrame(self) topleft.setFrameShape(QFrame.StyledPanel) topright = QFrame(self) topright.setFrameShape(QFrame.StyledPanel) bottomright = QFrame(self) bottomright.setFrameShape(QFrame.StyledPanel) bottomleft = QFrame(self) bottomleft.setFrameShape(QFrame.StyledPanel) # 수평 Splitter 생성, 두 개의 프레임 추가 splitter1 = QSplitter(Qt.Horizontal) splitter1.addWidget(topleft) splitter1.addWidget(topright) splitter2 = QSplitter(Qt.Horizontal) splitter2.addWidget(bottomleft) splitter2.addWidget(bottomright) # 수직 Splitter 생성, 두 개의 수평 Splitter 추가 splitter3 = QSplitter(Qt.Vertical) splitter3.addWidget(splitter1) splitter3.addWidget(splitter2) hbox.addWidget(splitter3) self.setLayout(hbox) self.setGeometry(300, 300, 300, 200) self.setWindowTitle('QSplitter') self.show()
class Visualization: def __init__(self, world): """ Main Interface between the OpenGL stuff and the simulator. Initializes the camera, and the opengl-widget. controlls the speed of the simulation. :param world: the world class """ self._world = world self._last_light_rotation = 0 self._rounds_per_second = 10 self._reset_flag = False self._running = False self._app = None self._viewer = None self._gui = None self._splitter = None self._recording = False self._animation = world.config_data.animation self._auto_animation = world.config_data.auto_animation self._manual_animation_speed = world.config_data.manual_animation_speed self.light_rotation = False self.grid_size = world.grid.size # create the QApplication self._app = QApplication([]) # create camera for the visualization # if grid is 2D, set to orthographic projection (it is better for 2D) if self._world.grid.get_dimension_count() == 2: self._camera = Camera( self._world.config_data.window_size_x, self._world.config_data.window_size_y, self._world.config_data.look_at, self._world.config_data.phi, self._world.config_data.theta, self._world.config_data.radius, self._world.config_data.fov, self._world.config_data.cursor_offset, self._world.config_data.render_distance, "ortho", self._world.grid.get_scaling()) else: self._camera = Camera( self._world.config_data.window_size_x, self._world.config_data.window_size_y, self._world.config_data.look_at, self._world.config_data.phi, self._world.config_data.theta, self._world.config_data.radius, self._world.config_data.fov, self._world.config_data.cursor_offset, self._world.config_data.render_distance, "perspective", self._world.grid.get_scaling()) # create the opengl widget self._viewer = OGLWidget(self._world, self._camera) self._viewer.glInit() self.recorder = Recorder(self._world, self._viewer) # create and show the main Window self._splitter = QSplitter() self._splitter.closeEvent = close self._splitter.setMinimumWidth(self._world.config_data.window_size_x) self._splitter.setMinimumHeight(self._world.config_data.window_size_y) self._splitter.setWindowTitle("Simulator") self._splitter.show() # create gui # creating the gui has to happen after showing the window, so the gui can access # opengl variables and programs during creation self._gui_module = importlib.import_module('components.gui.' + self._world.config_data.gui) # the key press handler def key_press_event(event): self._gui_module.key_handler(event.key(), self._world, self) # loading key handler from gui module if "key_handler" in dir(self._gui_module): self._viewer.keyPressEventHandler = key_press_event self._splitter.keyPressEvent = key_press_event else: show_msg("No key_handler(key, vis) function found in gui module!", Level.WARNING, self._splitter) # loading gui from gui module if "create_gui" in dir(self._gui_module): self._gui = self._gui_module.create_gui(self._world, self) if self._gui is not None and issubclass(self._gui.__class__, QWidget): self._splitter.addWidget(self._gui) self._splitter.keyPressEvent = self._viewer.keyPressEvent self._splitter.keyReleaseEvent = self._viewer.keyReleaseEvent self._splitter.addWidget(self._viewer) self._splitter.setSizes([ self._world.config_data.window_size_x * 0.25, self._world.config_data.window_size_x * 0.75 ]) else: # noinspection PyUnresolvedReferences show_msg( "The create_gui(world, vis) function in gui module didn't return a QWidget." + "Expected a QWidget or a subclass, but got %s." % self._gui.__class__.__name__, Level.WARNING, self._splitter) self._splitter.addWidget(self._viewer) else: show_msg( "No create_gui(world, vis) function found in gui module. GUI not created", Level.INFO, self._splitter) self._splitter.addWidget(self._viewer) # waiting for the simulation window to be fully active while not self._splitter.windowHandle().isExposed(): self._process_events() # first update and draw call. self._viewer.update_scene() def is_recording(self): return self._recording def _process_events(self): self._app.processEvents() if self._reset_flag: raise ResetException() def reset(self): """ stops the simulation. deletes all data in the visualization. resets the camera :return: """ self._reset_flag = False self._running = False self._viewer.agent_offset_data = {} self._viewer.agent_update_flag = True self._viewer.item_offset_data = {} self._viewer.item_update_flag = True self._viewer.location_offset_data = {} self._viewer.location_update_flag = True self._viewer.update_data() self._camera.reset() self._viewer.update_scene() def wait_for_thread(self, thread: Thread, window_message, window_title): """ executes a thread and shows a loading window till the thread stops. blocks the gui, while thread runs. :param thread: the thread :param window_message: the displayed message :param window_title: the title of the loading window :return: """ loading_window = LoadingWindow(window_message, window_title) if self._gui is not None and issubclass(self._gui.__class__, QWidget): self._gui.setDisabled(True) thread.start() while thread.is_alive(): try: self._process_events() except VisualizationError as ve: show_msg(ve, Level.CRITICAL, self._splitter) exit(1) thread.join() loading_window.close() self._gui.setDisabled(False) def rotate_light(self): """ rotates the light direction at a steady degrees/second velocity independent of the CPU-clock or framerate. :return: """ # rotation of light only in 3d if self._world.grid.get_dimension_count() > 2: # 20° per second rotation if self._last_light_rotation == 0: self._last_light_rotation = time.perf_counter() else: angle = (time.perf_counter() - self._last_light_rotation) * 20 self._last_light_rotation = time.perf_counter() self._viewer.rotate_light(angle) self._viewer.glDraw() def start_stop(self): """ starts and pauses the simulation :return: """ self._running = not self._running def _wait_while_not_running(self): """ helper function. waits until the running flag is set. :return: """ sleep_time = 1.0 / 120.0 self._process_events() if self.light_rotation: self.rotate_light() while not self._running: # sleeping for 1/120 secs, for responsive GUI time.sleep(sleep_time) if self.light_rotation: self.rotate_light() self._process_events() def animate(self, round_start_time, speed): """ loop for animating the movement of agents and carried items :param round_start_time: the start of the round :param speed: speed of the animation in 1/steps. less or equal zero = automatic mode """ if speed < 0: # draw at location according to the passed time and the rps half_round_time = (1.0 / self._rounds_per_second) / 2.0 now = time.perf_counter() while (now - round_start_time) < half_round_time: self._viewer.set_animation_percentage( min(1, (now - round_start_time) / half_round_time)) self._process_events() self._viewer.glDraw() now = time.perf_counter() else: # draw at location according to the selected animation speed for i in range(1, max(1, speed)): self._viewer.set_animation_percentage(float(i / max(1, speed))) self._process_events() self._viewer.glDraw() self._viewer.set_animation_percentage(1) self._viewer.glDraw() # reset the previous position after animation. # not reseting it causes a visual bug if the matter didn't move. for agent in self._viewer.agent_offset_data: current_data = self._viewer.agent_offset_data[agent] self._viewer.agent_offset_data[agent] = (current_data[0], current_data[1], agent.coordinates, current_data[3]) for item in self._viewer.item_offset_data: current_data = self._viewer.item_offset_data[item] self._viewer.item_offset_data[item] = (current_data[0], current_data[1], item.coordinates, current_data[3]) self._viewer.agent_update_flag = True self._viewer.item_update_flag = True def run(self, round_start_timestamp): """ main function for running the simulation with the visualization. At this time, its just error handling here.. the simulation and drawing stuff starts in the run_iteration method :param round_start_timestamp: timestamp of the start of the round. :return: """ try: self._run_iteration(round_start_timestamp) except VisualizationError as ve: if ve.level == Level.INFO: show_msg(ve.msg, ve.level, self.get_main_window()) if ve.level == Level.CRITICAL: show_msg(ve.msg, ve.level, self.get_main_window()) exit(1) if ve.level == Level.WARNING: try: self._run_iteration(round_start_timestamp) show_msg(ve.msg, ve.level, self.get_main_window()) except VisualizationError as ve: show_msg(ve.msg, ve.level, self.get_main_window()) if ve.level != Level.INFO: exit(1) def _run_iteration(self, round_start_timestamp): """ Controls the "waiting time", so the rounds_per_second value is being kept at the specified value. :param round_start_timestamp: timestamp of the start of the round. :return: """ # update and draw/animate scene self._viewer.update_data() if self._animation: self.animate( round_start_timestamp, -1 if self._auto_animation else self._manual_animation_speed) else: self._viewer.glDraw() # waiting until simulation starts self._wait_while_not_running() # record round if self._recording: self.recorder.record_round() self._splitter.setWindowTitle("Simulator, recorded: %d rounds" % len(self.recorder.records)) # waiting until enough time passed to do the next simulation round. time_elapsed = time.perf_counter() - round_start_timestamp # sleeping time - max 1/120 s for a responsive GUI sleep_time = min(1.0 / 120, (1.0 / self._rounds_per_second) / 10.0) max_wait_time = 1 / self._rounds_per_second while time_elapsed < max_wait_time: time.sleep(sleep_time) # check if still running... if not wait (important for low rounds_per_second values) self._wait_while_not_running() time_elapsed = time.perf_counter() - round_start_timestamp def remove_agent(self, agent): """ removes an agent from the visualization. it wont be deleted immediately! not until the next round. if you want an immediate deletion of the agent, then call this function, then, update_data and after that glDraw of the OpenGLWidget. :param agent: the agent (not the id, the instance) to be deleted :return: """ self._viewer.agent_update_flag = True if agent in self._viewer.agent_offset_data: del self._viewer.agent_offset_data[agent] def agent_changed(self, agent): """ updates the offset, color and carry data of the agent in the visualization. it wont be an immediate update. it will update in the beginning of the next "run" call / after current round. :param agent: the agent that has changed (the instance) :return: """ self._viewer.agent_update_flag = True prev_pos = agent.coordinates if agent in self._viewer.agent_offset_data: prev_pos = self._viewer.agent_offset_data[agent][0] self._viewer.agent_offset_data[agent] = (agent.coordinates, agent.color, prev_pos, 1.0 if agent.is_carried() else 0.0) def remove_item(self, item): """ removes an item from the visualization. :param item: the item (not the id, the instance) to be deleted :return: """ self._viewer.item_update_flag = True if item in self._viewer.item_offset_data: del self._viewer.item_offset_data[item] def item_changed(self, item): """ updates the offset, color and carry data of the item in the visualization. :param item: the item ( not the id, the instance) to be deleted :return: """ self._viewer.item_update_flag = True prev_pos = item.coordinates if item in self._viewer.item_offset_data: prev_pos = self._viewer.item_offset_data[item][0] self._viewer.item_offset_data[item] = (item.coordinates, item.color, prev_pos, 1.0 if item.is_carried() else 0.0) def remove_location(self, location): """ removes a location from the visualization. :param location: the location (not the id, the instance) to be deleted :return: """ self._viewer.location_update_flag = True if location in self._viewer.location_offset_data: del self._viewer.location_offset_data[location] def location_changed(self, location): """ updates the offset and color data of the location in the visualization. :param location: the location ( not the id, the instance) to be deleted :return: """ self._viewer.location_update_flag = True self._viewer.location_offset_data[location] = (location.coordinates, location.color) def update_visualization_data(self): self._viewer.update_data() # setters and getters for various variables in the visualization def set_rounds_per_second(self, rounds_per_second): self._rounds_per_second = rounds_per_second def get_rounds_per_second(self): return self._rounds_per_second def reset_camera_position(self): self._camera.reset() self._viewer.update_scene() def set_field_of_view(self, fov: float): self._camera.set_fov(fov) self._viewer.update_programs_projection_matrix() self._viewer.update_cursor_data() self._viewer.glDraw() def get_field_of_view(self): return self._camera.get_fov() def set_drag_sensitivity(self, s: float): self._viewer.drag_sensitivity = s def get_drag_sensitivity(self): return self._viewer.drag_sensitivity def set_zoom_sensitivity(self, s: float): self._viewer.zoom_sensitivity = s def get_zoom_sensitivity(self): return self._viewer.zoom_sensitivity def set_rotation_sensitivity(self, s: float): self._viewer.rotation_sensitivity = s def get_rotation_sensitivity(self): return self._viewer.rotation_sensitivity def get_projection_type(self): return self._camera.get_projection_type() def set_projection_type(self, projection_type): self._camera.set_projection_type(projection_type) self._viewer.update_programs_projection_matrix() self._viewer.glDraw() def get_background_color(self): return self._viewer.background def set_background_color(self, color): self._viewer.set_background_color(color) def get_grid_line_color(self): return self._viewer.programs["grid"].get_line_color() def set_grid_line_color(self, color): self._viewer.programs["grid"].set_line_color(color) def get_grid_border_color(self): return self._viewer.programs["grid"].get_border_color() def set_grid_border_color(self, color): self._viewer.programs["grid"].set_border_color(color) def get_grid_line_width(self): return self._viewer.programs["grid"].width def set_grid_line_width(self, width): self._viewer.programs["grid"].set_width(width) self._viewer.glDraw() def get_grid_line_scaling(self): return self._viewer.programs["grid"].get_line_scaling() def set_grid_line_scaling(self, scaling): self._viewer.programs["grid"].set_line_scaling(scaling) self._viewer.glDraw() def get_grid_coordinates_color(self): return self._viewer.programs["grid"].get_model_color() def set_grid_coordinates_color(self, color): self._viewer.programs["grid"].set_model_color(color) self._viewer.glDraw() def get_grid_coordinates_scaling(self): return self._viewer.programs["grid"].get_model_scaling() def set_grid_coordinates_scaling(self, scaling): self._viewer.programs["grid"].set_model_scaling(scaling) self._viewer.glDraw() def get_render_distance(self): return self._camera.get_render_distance() def set_render_distance(self, render_distance): self._camera.set_render_distance(render_distance) self._viewer.update_programs_projection_matrix() self._viewer.glDraw() def get_show_lines(self): return self._viewer.programs["grid"].show_lines def set_show_lines(self, show_lines: bool): self._viewer.programs["grid"].show_lines = show_lines self._viewer.glDraw() def get_show_border(self): return self._viewer.programs["grid"].show_border def set_show_border(self, show_border: bool): self._viewer.programs["grid"].show_border = show_border self._viewer.glDraw() def get_show_coordinates(self): return self._viewer.programs["grid"].show_coordinates def set_show_coordinates(self, show_coordinates: bool): self._viewer.programs["grid"].show_coordinates = show_coordinates self._viewer.glDraw() def get_show_center(self): return self._viewer.show_center def set_show_center(self, show_center: bool): self._viewer.show_center = show_center self._viewer.glDraw() def get_show_focus(self): return self._viewer.show_focus def set_show_focus(self, show_focus: bool): self._viewer.show_focus = show_focus self._viewer.glDraw() def take_screenshot(self, quick): self._viewer.take_screenshot(quick) def recalculate_grid(self, size): self.grid_size = size self._viewer.programs["grid"].update_offsets( self._world.grid.get_box(size)) self._viewer.glDraw() def get_agent_scaling(self): return self._viewer.programs["agent"].get_model_scaling() def set_agent_scaling(self, scaling): self._viewer.programs["agent"].set_model_scaling(scaling) self._viewer.glDraw() def get_item_scaling(self): return self._viewer.programs["item"].get_model_scaling() def set_item_scaling(self, scaling): self._viewer.programs["item"].set_model_scaling(scaling) self._viewer.glDraw() def get_location_scaling(self): return self._viewer.programs["location"].get_model_scaling() def set_location_scaling(self, scaling): self._viewer.programs["location"].set_model_scaling(scaling) self._viewer.glDraw() def set_on_cursor_click_matter_type(self, matter_type): if matter_type == MatterType.ITEM or matter_type == MatterType.AGENT or matter_type == MatterType.LOCATION: self._viewer.cursor_type = matter_type self._viewer.update_cursor_data() def is_running(self): return self._running def get_added_matter_color(self): return self._viewer.added_matter_color def set_added_matter_color(self, color): self._viewer.added_matter_color = color def start_recording(self): self.recorder.record_round() self._splitter.setWindowTitle("Simulator, recorded: %d rounds" % len(self.recorder.records)) self._recording = True def get_viewer_res(self): return self._viewer.width(), self._viewer.height() def stop_recording(self): self._recording = False def export_recording(self): if len(self.recorder.records) == 0: show_msg("No rounds recorded. Nothing to export.", Level.INFO, self._splitter) return if self._running: self.start_stop() self._viewer.set_show_info_frame(False) self._viewer.set_enable_cursor(False) if "set_disable_sim" in dir(self._gui_module): self._gui_module.set_disable_sim(True) else: show_msg( "No 'set_disable_sim(disable_flag)' function in gui module found." "\nRunning simulation within recording mode may result in undefined behavior!", Level.WARNING, self._splitter) self.recorder.show(self.do_export) # loop while self.recorder.is_open(): self._process_events() # go back to the main window if "set_disable_sim" in dir(self._gui_module): self._gui_module.set_disable_sim(False) self._viewer.agent_update_flag = True self._viewer.item_update_flag = True self._viewer.location_update_flag = True self._viewer.update_data() self._viewer.set_show_info_frame(True) self._viewer.set_enable_cursor(True) def do_export(self, rps, width, height, codec, first_frame_idx, last_frame_idx, animation): if not os.path.exists("outputs/videos") or not os.path.isdir( "outputs/videos"): os.mkdir("outputs/videos") directory = "." if os.path.exists("outputs/videos") and os.path.isdir( "outputs/videos"): directory = "outputs/videos" path = TopQFileDialog(self._splitter).getSaveFileName( options=(TopQFileDialog.Options()), filter="*.mp4;;*.avi;;*.mkv", directory=directory) if path[0] == '': return if path[0].endswith("mp4") or path[0].endswith( ".avi") or path[0].endswith(".mkv"): fullpath = path[0] else: fullpath = path[0] + path[1].replace('*', '') if animation: animation_steps = int(30 / rps) if animation_steps < 1: animation_steps = 1 else: animation_steps = 1 writer = cv2.VideoWriter(fullpath, cv2.VideoWriter_fourcc(*codec), rps * animation_steps, (width, height)) self._viewer.setDisabled(True) # creating and opening loading window lw = LoadingWindow("", "Exporting Video...") lw.show() out_of = (last_frame_idx - first_frame_idx + 1) * animation_steps for i in range(first_frame_idx - 1, last_frame_idx): # render and write frame self._viewer.inject_record_data(self.recorder.records[i]) # animate for j in range(1, animation_steps + 1): # process events so the gui thread does respond to interactions.. self._process_events() # update loading windows text and progress bar processing = (i - first_frame_idx + 1) * animation_steps + j lw.set_message("Please wait!\nExporting frame %d/%d..." % (processing, out_of)) lw.set_progress(processing, out_of) self._viewer.set_animation_percentage(j / animation_steps) self._viewer.glDraw() img = self._viewer.get_frame_cv(width, height) writer.write(img) self._viewer.inject_record_data(self.recorder.records[last_frame_idx - 1]) writer.release() lw.close() self._viewer.setDisabled(False) self._viewer.resizeGL(self._viewer.width(), self._viewer.height()) self._viewer.update_scene() show_msg("Video exported successfully!", Level.INFO, self._splitter) def delete_recording(self): self.recorder = Recorder(self._world, self._viewer) self._splitter.setWindowTitle("Simulator") def set_antialiasing(self, value): if value <= 0: self._viewer.disable_aa() else: self._viewer.enable_aa(value) def take_vector_screenshot(self): if self._world.grid.__class__.__name__ == "TriangularGrid": if not os.path.exists("outputs/screenshots") or not os.path.isdir( "outputs/screenshots"): os.mkdir("outputs/screenshots") directory = "." if os.path.exists("outputs/screenshots") and os.path.isdir( "outputs/screenshots"): directory = "outputs/screenshots" path = TopQFileDialog(self._splitter).getSaveFileName( options=(TopQFileDialog.Options()), filter="*.svg", directory=directory) if path[0] == '': return if path[0].endswith(".svg"): create_svg(self._world, path[0]) else: create_svg(self._world, path[0] + ".svg") else: show_msg( "Not implemented yet.\nWorks only with Triangular Grid for now!\nSorry!", Level.WARNING, self._splitter) def set_animation(self, animation): if not animation: self._viewer.set_animation_percentage(1) self._animation = animation def get_animation(self): return self._animation def set_auto_animation(self, auto_animation): self._auto_animation = auto_animation def get_auto_animation(self): return self._auto_animation def set_manual_animation_speed(self, manual_animation_speed): self._manual_animation_speed = manual_animation_speed def get_manual_animation_speed(self): return self._manual_animation_speed def get_main_window(self): return self._splitter def set_reset_flag(self): self._reset_flag = True
def __init__(self, world): """ Main Interface between the OpenGL stuff and the simulator. Initializes the camera, and the opengl-widget. controlls the speed of the simulation. :param world: the world class """ self._world = world self._last_light_rotation = 0 self._rounds_per_second = 10 self._reset_flag = False self._running = False self._app = None self._viewer = None self._gui = None self._splitter = None self._recording = False self._animation = world.config_data.animation self._auto_animation = world.config_data.auto_animation self._manual_animation_speed = world.config_data.manual_animation_speed self.light_rotation = False self.grid_size = world.grid.size # create the QApplication self._app = QApplication([]) # create camera for the visualization # if grid is 2D, set to orthographic projection (it is better for 2D) if self._world.grid.get_dimension_count() == 2: self._camera = Camera( self._world.config_data.window_size_x, self._world.config_data.window_size_y, self._world.config_data.look_at, self._world.config_data.phi, self._world.config_data.theta, self._world.config_data.radius, self._world.config_data.fov, self._world.config_data.cursor_offset, self._world.config_data.render_distance, "ortho", self._world.grid.get_scaling()) else: self._camera = Camera( self._world.config_data.window_size_x, self._world.config_data.window_size_y, self._world.config_data.look_at, self._world.config_data.phi, self._world.config_data.theta, self._world.config_data.radius, self._world.config_data.fov, self._world.config_data.cursor_offset, self._world.config_data.render_distance, "perspective", self._world.grid.get_scaling()) # create the opengl widget self._viewer = OGLWidget(self._world, self._camera) self._viewer.glInit() self.recorder = Recorder(self._world, self._viewer) # create and show the main Window self._splitter = QSplitter() self._splitter.closeEvent = close self._splitter.setMinimumWidth(self._world.config_data.window_size_x) self._splitter.setMinimumHeight(self._world.config_data.window_size_y) self._splitter.setWindowTitle("Simulator") self._splitter.show() # create gui # creating the gui has to happen after showing the window, so the gui can access # opengl variables and programs during creation self._gui_module = importlib.import_module('components.gui.' + self._world.config_data.gui) # the key press handler def key_press_event(event): self._gui_module.key_handler(event.key(), self._world, self) # loading key handler from gui module if "key_handler" in dir(self._gui_module): self._viewer.keyPressEventHandler = key_press_event self._splitter.keyPressEvent = key_press_event else: show_msg("No key_handler(key, vis) function found in gui module!", Level.WARNING, self._splitter) # loading gui from gui module if "create_gui" in dir(self._gui_module): self._gui = self._gui_module.create_gui(self._world, self) if self._gui is not None and issubclass(self._gui.__class__, QWidget): self._splitter.addWidget(self._gui) self._splitter.keyPressEvent = self._viewer.keyPressEvent self._splitter.keyReleaseEvent = self._viewer.keyReleaseEvent self._splitter.addWidget(self._viewer) self._splitter.setSizes([ self._world.config_data.window_size_x * 0.25, self._world.config_data.window_size_x * 0.75 ]) else: # noinspection PyUnresolvedReferences show_msg( "The create_gui(world, vis) function in gui module didn't return a QWidget." + "Expected a QWidget or a subclass, but got %s." % self._gui.__class__.__name__, Level.WARNING, self._splitter) self._splitter.addWidget(self._viewer) else: show_msg( "No create_gui(world, vis) function found in gui module. GUI not created", Level.INFO, self._splitter) self._splitter.addWidget(self._viewer) # waiting for the simulation window to be fully active while not self._splitter.windowHandle().isExposed(): self._process_events() # first update and draw call. self._viewer.update_scene()
def _layoutUI(self): """Layout the graphical user interface. The standard layout will consist of three columns: The activation maps are shown in the left column. The center column contains widgets for displaying and selecting the input data. The right column contains controls for selecting network and network layer. """ # # Activations (left column) # activationLayout = QVBoxLayout() activationLayout.addWidget(self._activationView) # FIXME[layout] self._activationView.setMinimumWidth(200) self._activationView.resize(400, self._activationView.height()) activationBox = QGroupBox('Activation') activationBox.setLayout(activationLayout) # # Input data (center column) # inputLayout = QVBoxLayout() inputLayout.addWidget(self._dataInspector) inputBox = QGroupBox('Input') inputBox.setLayout(inputLayout) # # Network (right column) # rightLayout = QVBoxLayout() networkBox = QGroupBox("Network") networkLayout = QVBoxLayout() row = QHBoxLayout() row.addWidget(self._networkSelector, stretch=2) row.addWidget(self._networkPrepareButton, stretch=1) networkLayout.addLayout(row) networkLayout.addWidget(self._layerSelector) networkBox.setLayout(networkLayout) rightLayout.addWidget(networkBox) # classes rightLayout.addWidget(self._classesViewBox) # # Attach widgets to window # splitter = QSplitter(Qt.Horizontal) splitter.addWidget(activationBox) splitter.addWidget(inputBox) rightWidget = QWidget() rightWidget.setLayout(rightLayout) rightLayout.setContentsMargins(0, 0, 0, 0) splitter.addWidget(rightWidget) layout = QHBoxLayout() layout.addWidget(splitter) self.setLayout(layout)
class CGWMain(QWZMQListener): _name = 'CGWMain' def __init__(self, parser=None): self.proc_parser(parser) if __name__ != "__main__": daq_control.set_daq_control( DaqControl(host=self.host, platform=self.platform, timeout=self.timeout)) QWZMQListener.__init__(self, host=self.host, platform=self.platform, timeout=self.timeout) else: # emulator mode for TEST ONLY QWZMQListener.__init__(self, is_normal=False) self.init_daq_control_parameters() # cach parameters in cp self.wlogr = QWLoggerStd(log_level=self.loglevel, instrument=cp.instr,\ log_prefix=self.logdir, show_buttons=False) logger.debug('logger started with log_level:%s instrument:%s' % (self.loglevel, cp.instr)) cp.cgwmain = self self.main_win_width = cp.main_win_width self.main_win_height = cp.main_win_height self.main_win_pos_x = cp.main_win_pos_x self.main_win_pos_y = cp.main_win_pos_y #icon.set_icons() self.wconf = CGWMainConfiguration() self.wtabs = CGWMainTabs() self.vspl = QSplitter(Qt.Vertical) self.vspl.addWidget(self.wconf) self.vspl.addWidget(self.wtabs) self.vspl.addWidget(self.wlogr) self.mbox = QHBoxLayout() self.mbox.addWidget(self.vspl) self.setLayout(self.mbox) self.set_style() #self.set_tool_tips() #self.connect_signals_to_slots() #self.move(self.pos()) # + QPoint(self.width()+5, 0)) def connect_signals_to_slots(self): pass #self.connect(self.wbut.but_reset, QtCore.SIGNAL('clicked()'), self.on_but_reset) #self.connect(self.wbut.but_save, QtCore.SIGNAL('clicked()'), self.on_but_save) #------------------------------ def proc_parser(self, parser=None): self.parser = parser if parser is None: self.loglevel = 'DEBUG' self.logdir = 'logdir' self.expert = None return (popts, pargs) = parser.parse_args() self.args = pargs self.opts = vars(popts) self.defs = vars(parser.get_default_values()) #host = popts.host # self.opts['host'] #port = popts.port # self.opts['port'] #cp.user = popts.user #cp.upwd = popts.upwd #exp = popts.experiment #det = popts.detector self.logdir = popts.logdir self.loglevel = popts.loglevel.upper() self.host = popts.host self.platform = popts.platform self.timeout = popts.timeout self.expname = popts.expname self.uris = popts.uris # 'mcbrowne:psana@psdb-dev:9306' self.expert = popts.expert # bool #if host != self.defs['host'] : cp.cdb_host.setValue(host) #if host != self.defs['host'] : cp.cdb_host.setValue(host) #if port != self.defs['port'] : cp.cdb_port.setValue(port) #if exp != self.defs['experiment'] : cp.exp_name.setValue(exp) #if det != self.defs['detector'] : cp.data_source.setValue(det) #if loglevel != self.defs['loglevel'] : cp.log_level.setValue(loglevel) #if logdir != self.defs['logdir'] : cp.log_prefix.setValue(logdir) #if is_in_command_line(None, '--host') : cp.cdb_host.setValue(host) #if is_in_command_line(None, '--port') : cp.cdb_port.setValue(port) #if is_in_command_line('-e', '--experiment') : cp.exp_name.setValue(exp) #if is_in_command_line('-d', '--detector') : cp.data_source.setValue(det) #if is_in_command_line('-l', '--loglevel') : cp.log_level.setValue(loglevel) #if is_in_command_line('-L', '--logdir') : cp.log_prefix.setValue(logdir) #if self.loglevel == 'DEBUG' : # print(40*'_') # print_parser(parser) # print_kwargs(self.opts) #------------------------------ def init_daq_control_parameters(self): cp.s_transition, cp.s_state, cp.s_cfgtype, cp.s_recording, _platform = daq_control_get_status( ) #cp.instr = self.expname[:3].upper() cp.instr = daq_control_get_instrument() print('XXXXXX daq_control_get_instrument(): %s' % cp.instr) if cp.instr is None: cp.instr = 'TST' #------------------------------ def set_tool_tips(self): pass #self.setToolTip('DAQ control') #-------------------- def sizeHint(self): """Set default window size """ return QSize(370, 810) #-------------------- def set_style(self): self.setWindowTitle("DAQ Control") self.layout().setContentsMargins(0, 0, 0, 0) self.setMinimumSize(300, 700) self.wconf.setFixedHeight(80) self.setGeometry(self.main_win_pos_x .value(),\ self.main_win_pos_y .value(),\ self.main_win_width .value(),\ self.main_win_height.value()) #w_height = self.main_win_height.value() #self.layout().setContentsMargins(0,0,0,0) from psdaq.control_gui.QWIcons import icon, QIcon icon.set_icons() #self.setWindowIcon(icon.icon_button_ok) self.setWindowIcon(icon.icon_lcls) #pmap = icon.icon_lcls.pixmap(QSize(200,100)) # change icon.pixmap size #self.setWindowIcon(QIcon(pmap)) #w = self.main_win_width.value() #spl_pos = cp.main_vsplitter.value() #self.vspl.setSizes((spl_pos,w_height-spl_pos,)) #self.wrig.setMinimumWidth(350) #self.wrig.setMaximumWidth(450) #self.wrig.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Ignored) #self.hspl.moveSplitter(w*0.5,0) #self.setFixedSize(800,500) #self.setMinimumSize(500,800) #self.setStyleSheet("background-color:blue; border: 0px solid green") #self.setAttribute(QtCore.Qt.WA_TranslucentBackground) #self. setStyleSheet(style.styleBkgd) #self.butSave.setStyleSheet(style.styleButton) #self.butExit.setStyleSheet(style.styleButton) #self.butELog.setStyleSheet(style.styleButton) #self.butFile.setStyleSheet(style.styleButton) #self.butELog .setVisible(False) #self.butFBrowser.setVisible(False) #self.but1.raise_() def closeEvent(self, e): logger.debug('%s.closeEvent' % self._name) resp = confirm_or_cancel_dialog_box(parent=None, text='Close window?',\ title='Confirm or cancel') if not resp: logger.warning('Closing window is cancelled') e.ignore() return logger.debug('Closing window is confirmed') # save app-configuration parameters #try : # self.on_save() #except Exception as ex: # print('Exception: %s' % ex) try: self.wtabs.close() self.wconf.close() self.wlogr.close() except Exception as ex: print('Exception: %s' % ex) QWZMQListener.closeEvent(self, e) #print('Exit CGWMain.closeEvent') cp.cgwmain = None #-------------------- # def __del__(self) : # logger.debug('In CGConfigParameters d-tor') # #if self.save_cp_at_exit.value() : # if True : # self.on_save() #-------------------- #def resizeEvent(self, e): #logger.debug('CGWMain.resizeEvent: %s' % str(self.size())) #QWZMQListener.resizeEvent(self, e) #def moveEvent(self, e) : #logger.debug('moveEvent', self._name) #self.position = self.mapToGlobal(self.pos()) #self.position = self.pos() #logger.debug('moveEvent - pos:' + str(self.position), __name__) #logger.info('CGWMain.moveEvent - move window to x,y: ', str(self.mapToGlobal(QPoint(0,0)))) #self.wimg.move(self.pos() + QPoint(self.width()+5, 0)) #pass def on_save(self): point, size = self.mapToGlobal(QPoint( -5, -22)), self.size() # Offset (-5,-22) for frame size. x, y, w, h = point.x(), point.y(), size.width(), size.height() msg = 'Save main window x,y,w,h : %d, %d, %d, %d' % (x, y, w, h) logger.info(msg) #, self._name) print(msg) #Save main window position and size self.main_win_pos_x.setValue(x) self.main_win_pos_y.setValue(y) self.main_win_width.setValue(w) self.main_win_height.setValue(h) spl_pos = self.vspl.sizes()[0] msg = 'Save main v-splitter position %d' % spl_pos logger.debug(msg) #cp.main_vsplitter.setValue(spl_pos) cp.printParameters() cp.saveParametersInFile() #if cp.save_log_at_exit.value() : # pass # ????? #log.saveLogInFile(cp.log_file.value()) #print('Saved log file: %s' % cp.log_file.value()) #log.saveLogTotalInFile(fnm.log_file_total()) #------------------------------ def on_zmq_poll(self): """Re-implementation of the superclass QWZMQListener method for zmq message processing. """ t0_sec = time() self.zmq_notifier.setEnabled(False) flags = self.zmq_socket.getsockopt(zmq.EVENTS) flag = 'UNKNOWN' msg = '' if flags & zmq.POLLIN: while self.zmq_socket.getsockopt(zmq.EVENTS) & zmq.POLLIN: flag = 'POLLIN' msg = self.zmq_socket.recv_multipart() self.process_zmq_message(msg) #self.setWindowTitle(str(msg)) elif flags & zmq.POLLOUT: flag = 'POLLOUT' elif flags & zmq.POLLERR: flag = 'POLLERR' else: pass self.zmq_notifier.setEnabled(True) _flags = self.zmq_socket.getsockopt( zmq.EVENTS ) # WITHOUT THIS LINE IT WOULD NOT CALL on_read_msg AGAIN! logger.debug('CGWMain.on_zmq_poll Flag zmq.%s in %d msg: %s' % (flag, flags, msg)\ + '\n poll processing time = %.6f sec' % (time()-t0_sec)) if _flags & zmq.POLLIN: self.on_zmq_poll() def process_zmq_message(self, msg): #print('==== msg: %s' % str(msg)) wcoll = cp.cgwmaincollection wctrl = cp.cgwmaintabuser if cp.cgwmaintabuser is not None else\ cp.cgwmaincontrol try: for rec in msg: jo = json.loads(rec) # jo['header'] # {'key': 'status', 'msg_id': '0918505109-317821000', 'sender_id': None} # jo['body'] # {'state': 'allocated', 'transition': 'alloc'} if jo['header']['key'] == 'status': body = jo['body'] cp.s_transition = body['transition'] cp.s_state = body['state'] cp.s_cfgtype = body['config_alias'] # BEAM/NO BEAM cp.s_recording = body['recording'] # True/False cp.s_platform = body.get('platform', None) # dict #==== if wctrl is not None: wctrl.set_but_ctrls() self.wconf.set_config_type(cp.s_cfgtype) if wcoll is not None: wcoll.update_table() logger.info('zmq msg transition:%s state:%s config:%s recording:%s'%\ (cp.s_transition, cp.s_state, cp.s_cfgtype, cp.s_recording)) elif jo['header']['key'] == 'error': body = jo['body'] logger.error('received error msg: %s' % body['err_info']) ## grab status directly (not from error message) #status = daq_control_get_status() #if status is None : # logger.warning('process_zmq_message on error: STATUS IS NOT AVAILABLE') # return #transition, state, cfgtype, recording = status #if wctrl is not None : wctrl.set_but_ctrls() #self.wconf.set_config_type(cfgtype) #if wcoll is not None : wcoll.update_table() else: sj = json.dumps(jo, indent=2, sort_keys=False) logger.debug('received jason:\n%s' % sj) except KeyError as ex: logger.warning('CGWMain.process_zmq_message: %s\nError: %s' % (str(msg), ex)) except Exception as ex: logger.warning('CGWMain.process_zmq_message: %s\nError: %s' % (str(msg), ex)) #------------------------------ #------------------------------ #------------------------------ #------------------------------ if __name__ == "__main__": def key_usage(self): return 'Keys:'\ '\n V - view/hide tabs'\ '\n' def keyPressEvent(self, e): #print('keyPressEvent, key=', e.key()) if e.key() == Qt.Key_Escape: self.close() elif e.key() == Qt.Key_V: self.wtab.view_hide_tabs() else: logger.info(self.key_usage())
class PlotWidgetContainer(QWidget): def __init__(self, modelRoot, *args, **kwargs): super(PlotWidgetContainer, self).__init__(*args) self.modelRoot = modelRoot if len(moose.wildcardFind(modelRoot + "/##[ISA=ChemCompt]")) == 0: self.modelType = ELECTRICAL else: self.modelType = CHEMICAL self.model = moose.element(self.modelRoot) if self.modelRoot != "/": self.modelRoot = self.findModelPath(self.modelRoot) if moose.exists(modelRoot + "/data"): self.data = moose.element(self.modelRoot + "/data") else: self.data = moose.Neutral(self.modelRoot + "/data") else: self.data = moose.element("/data") self._layout = QVBoxLayout() self.graphs = QSplitter() self.graphs.setOrientation(QtCore.Qt.Vertical) self.graphsArea = QScrollArea() self.rowIndex = 0 self.graphs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.setAcceptDrops(True) self.graphsArea.setWidget(self.graphs) self.graphsArea.setWidgetResizable(True) self.graphWidgets = [] self._layout.addWidget(self.graphsArea) self.setLayout(self._layout) for graph in self.data.children: self.addPlotWidget(graph=graph) if len(self.data.children) == 0: self.addPlotWidget() def mooseIsInstance(self, element, classNames): return moose.element(element).__class__.__name__ in classNames def findModelPath(self, element): child = element while not self.mooseIsInstance(element, "Shell"): child = moose.element(element).path element = moose.element(element).parent return child def deleteWidget(self, graphWidget): # print("Deleted => ", graphWidget) self.graphWidgets.remove(graphWidget) graphWidget.setParent(None) graphWidget.close() def createMenuBar(self): bar = sidebar.sidebar() bar.addAction( sidebar.add_graph_action(bar, lambda event: self.addPlotWidget())) return bar def addPlotWidget(self, row=None, col=0, graph=None): if graph == None: graph = moose.Neutral(self.data.path + "/graph_" + str(self.rowIndex)) if row == None: row = self.rowIndex #if self.modelType == ELECTRICAL: # for axes in list(widget.canvas.axes.values()): # axes.set_ylim(bottom = -0.07, top= 0.03) # FIXME: # Has been removed? See #23 # widget = default.PlotWidget(self.model, graph, self.rowIndex, self) ## self.graphs.addWidget(widget) ## self.rowIndex += 1 ## self.graphWidgets.append(widget) ## widget.widgetClosedSignal.connect(self.deleteWidget) ## widget.addGraph.connect(lambda event : self.addPlotWidget()) ## return widget def showPlotView(self): pass def setModelRoot(self, *args): pass def getMenus(self, *args): return [] def setDataRoot(self, *args): pass def updatePlots(self): for graphWidget in self.graphWidgets: graphWidget.updatePlots() def rescalePlots(self): for graphWidget in self.graphWidgets: graphWidget.rescalePlots() def extendXAxes(self, xlim): for graphWidget in self.graphWidgets: graphWidget.extendXAxes(xlim) def plotAllData(self): for graphWidget in self.graphWidgets: graphWidget.plotAllData()
class PulseOfInterestWindow(_AbstractPlotWindow): """PulseOfInterestWindow class.""" _title = "Pulse-of-interest" _TOTAL_W, _TOTAL_H = config['GUI_PLOT_WINDOW_SIZE'] def __init__(self, *args, **kwargs): """Initialization.""" super().__init__(*args, **kwargs) self._poi_imgs = [ PoiImageView(0, parent=self), PoiImageView(0, parent=self) ] self._poi_fom_hists = [ PoiFomHist(0, parent=self), PoiFomHist(0, parent=self) ] self._poi_roi_hists = [ PoiRoiHist(0, parent=self), PoiRoiHist(0, parent=self) ] self.initUI() self.initConnections() self.resize(self._TOTAL_W, self._TOTAL_H) self.setMinimumSize(0.6 * self._TOTAL_W, 0.6 * self._TOTAL_H) self.update() def initUI(self): """Override.""" self._cw = QSplitter(Qt.Vertical) for img, fom_hist, roi_hist in zip(self._poi_imgs, self._poi_fom_hists, self._poi_roi_hists): rw = QSplitter(Qt.Vertical) rw.addWidget(fom_hist) rw.addWidget(roi_hist) w = QSplitter() w.addWidget(img) w.addWidget(rw) w.setSizes([self._TOTAL_W / 2, self._TOTAL_W / 2]) self._cw.addWidget(w) self.setCentralWidget(self._cw) self._cw.setHandleWidth(self._SPLITTER_HANDLE_WIDTH) def initConnections(self): """Override.""" mediator = self._mediator mediator.poi_index_change_sgn.connect(self._updatePoiIndex) mediator.poi_window_initialized_sgn.emit() def _updatePoiIndex(self, poi_idx, pulse_idx): self._poi_imgs[poi_idx].setPulseIndex(pulse_idx) self._poi_fom_hists[poi_idx].setPulseIndex(pulse_idx) self._poi_roi_hists[poi_idx].setPulseIndex(pulse_idx)
class MainWindow(QMainWindow): receiveUpdateSignal = pyqtSignal(str) errorSignal = pyqtSignal(str) showSerialComboboxSignal = pyqtSignal() isDetectSerialPort = False receiveCount = 0 sendCount = 0 isScheduledSending = False DataPath = "./" isHideSettings = False isHideFunctinal = True app = None isWaveOpen = False def __init__(self,app): super().__init__() self.app = app pathDirList = sys.argv[0].replace("\\", "/").split("/") pathDirList.pop() self.DataPath = os.path.abspath("/".join(str(i) for i in pathDirList)) if not os.path.exists(self.DataPath + "/" + parameters.strDataDirName): pathDirList.pop() self.DataPath = os.path.abspath("/".join(str(i) for i in pathDirList)) self.DataPath = (self.DataPath + "/" + parameters.strDataDirName).replace("\\", "/") self.initWindow() self.initTool() self.initEvent() self.programStartGetSavedParameters() return def __del__(self): return def initTool(self): self.com = serial.Serial() return def initWindow(self): QToolTip.setFont(QFont('SansSerif', 10)) # main layout frameWidget = QWidget() mainWidget = QSplitter(Qt.Horizontal) frameLayout = QVBoxLayout() self.settingWidget = QWidget() self.settingWidget.setProperty("class","settingWidget") self.receiveSendWidget = QSplitter(Qt.Vertical) self.functionalWiget = QWidget() settingLayout = QVBoxLayout() sendReceiveLayout = QVBoxLayout() sendFunctionalLayout = QVBoxLayout() mainLayout = QHBoxLayout() self.settingWidget.setLayout(settingLayout) self.receiveSendWidget.setLayout(sendReceiveLayout) self.functionalWiget.setLayout(sendFunctionalLayout) mainLayout.addWidget(self.settingWidget) mainLayout.addWidget(self.receiveSendWidget) mainLayout.addWidget(self.functionalWiget) mainLayout.setStretch(0,2) mainLayout.setStretch(1, 6) mainLayout.setStretch(2, 2) menuLayout = QHBoxLayout() mainWidget.setLayout(mainLayout) frameLayout.addLayout(menuLayout) frameLayout.addWidget(mainWidget) frameWidget.setLayout(frameLayout) self.setCentralWidget(frameWidget) # option layout self.settingsButton = QPushButton() self.skinButton = QPushButton("") # self.waveButton = QPushButton("") self.aboutButton = QPushButton() self.functionalButton = QPushButton() self.encodingCombobox = ComboBox() self.encodingCombobox.addItem("ASCII") self.encodingCombobox.addItem("UTF-8") self.encodingCombobox.addItem("UTF-16") self.encodingCombobox.addItem("GBK") self.encodingCombobox.addItem("GB2312") self.encodingCombobox.addItem("GB18030") self.settingsButton.setProperty("class", "menuItem1") self.skinButton.setProperty("class", "menuItem2") self.aboutButton.setProperty("class", "menuItem3") self.functionalButton.setProperty("class", "menuItem4") # self.waveButton.setProperty("class", "menuItem5") self.settingsButton.setObjectName("menuItem") self.skinButton.setObjectName("menuItem") self.aboutButton.setObjectName("menuItem") self.functionalButton.setObjectName("menuItem") # self.waveButton.setObjectName("menuItem") menuLayout.addWidget(self.settingsButton) menuLayout.addWidget(self.skinButton) # menuLayout.addWidget(self.waveButton) menuLayout.addWidget(self.aboutButton) menuLayout.addStretch(0) menuLayout.addWidget(self.encodingCombobox) menuLayout.addWidget(self.functionalButton) # widgets receive and send area self.receiveArea = QTextEdit() self.sendArea = QTextEdit() self.clearReceiveButtion = QPushButton(parameters.strClearReceive) self.sendButtion = QPushButton(parameters.strSend) self.sendHistory = ComboBox() sendWidget = QWidget() sendAreaWidgetsLayout = QHBoxLayout() sendWidget.setLayout(sendAreaWidgetsLayout) buttonLayout = QVBoxLayout() buttonLayout.addWidget(self.clearReceiveButtion) buttonLayout.addStretch(1) buttonLayout.addWidget(self.sendButtion) sendAreaWidgetsLayout.addWidget(self.sendArea) sendAreaWidgetsLayout.addLayout(buttonLayout) sendReceiveLayout.addWidget(self.receiveArea) sendReceiveLayout.addWidget(sendWidget) sendReceiveLayout.addWidget(self.sendHistory) sendReceiveLayout.setStretch(0, 7) sendReceiveLayout.setStretch(1, 2) sendReceiveLayout.setStretch(2, 1) # widgets serial settings serialSettingsGroupBox = QGroupBox(parameters.strSerialSettings) serialSettingsLayout = QGridLayout() serialReceiveSettingsLayout = QGridLayout() serialSendSettingsLayout = QGridLayout() serialPortLabek = QLabel(parameters.strSerialPort) serailBaudrateLabel = QLabel(parameters.strSerialBaudrate) serailBytesLabel = QLabel(parameters.strSerialBytes) serailParityLabel = QLabel(parameters.strSerialParity) serailStopbitsLabel = QLabel(parameters.strSerialStopbits) self.serialPortCombobox = ComboBox() self.serailBaudrateCombobox = ComboBox() self.serailBaudrateCombobox.addItem("9600") self.serailBaudrateCombobox.addItem("19200") self.serailBaudrateCombobox.addItem("38400") self.serailBaudrateCombobox.addItem("57600") self.serailBaudrateCombobox.addItem("115200") self.serailBaudrateCombobox.setCurrentIndex(4) self.serailBaudrateCombobox.setEditable(True) self.serailBytesCombobox = ComboBox() self.serailBytesCombobox.addItem("5") self.serailBytesCombobox.addItem("6") self.serailBytesCombobox.addItem("7") self.serailBytesCombobox.addItem("8") self.serailBytesCombobox.setCurrentIndex(3) self.serailParityCombobox = ComboBox() self.serailParityCombobox.addItem("None") self.serailParityCombobox.addItem("Odd") self.serailParityCombobox.addItem("Even") self.serailParityCombobox.addItem("Mark") self.serailParityCombobox.addItem("Space") self.serailParityCombobox.setCurrentIndex(0) self.serailStopbitsCombobox = ComboBox() self.serailStopbitsCombobox.addItem("1") self.serailStopbitsCombobox.addItem("1.5") self.serailStopbitsCombobox.addItem("2") self.serailStopbitsCombobox.setCurrentIndex(0) self.checkBoxRts = QCheckBox("rts") self.checkBoxDtr = QCheckBox("dtr") self.serialOpenCloseButton = QPushButton(parameters.strOpen) serialSettingsLayout.addWidget(serialPortLabek,0,0) serialSettingsLayout.addWidget(serailBaudrateLabel, 1, 0) serialSettingsLayout.addWidget(serailBytesLabel, 2, 0) serialSettingsLayout.addWidget(serailParityLabel, 3, 0) serialSettingsLayout.addWidget(serailStopbitsLabel, 4, 0) serialSettingsLayout.addWidget(self.serialPortCombobox, 0, 1) serialSettingsLayout.addWidget(self.serailBaudrateCombobox, 1, 1) serialSettingsLayout.addWidget(self.serailBytesCombobox, 2, 1) serialSettingsLayout.addWidget(self.serailParityCombobox, 3, 1) serialSettingsLayout.addWidget(self.serailStopbitsCombobox, 4, 1) serialSettingsLayout.addWidget(self.checkBoxRts, 5, 0,1,1) serialSettingsLayout.addWidget(self.checkBoxDtr, 5, 1,1,1) serialSettingsLayout.addWidget(self.serialOpenCloseButton, 6, 0,1,2) serialSettingsGroupBox.setLayout(serialSettingsLayout) settingLayout.addWidget(serialSettingsGroupBox) # serial receive settings serialReceiveSettingsGroupBox = QGroupBox(parameters.strSerialReceiveSettings) self.receiveSettingsAscii = QRadioButton(parameters.strAscii) self.receiveSettingsHex = QRadioButton(parameters.strHex) self.receiveSettingsAscii.setChecked(True) self.receiveSettingsAutoLinefeed = QCheckBox(parameters.strAutoLinefeed) self.receiveSettingsAutoLinefeedTime = QLineEdit(parameters.strAutoLinefeedTime) self.receiveSettingsAutoLinefeed.setMaximumWidth(75) self.receiveSettingsAutoLinefeedTime.setMaximumWidth(75) serialReceiveSettingsLayout.addWidget(self.receiveSettingsAscii,1,0,1,1) serialReceiveSettingsLayout.addWidget(self.receiveSettingsHex,1,1,1,1) serialReceiveSettingsLayout.addWidget(self.receiveSettingsAutoLinefeed, 2, 0, 1, 1) serialReceiveSettingsLayout.addWidget(self.receiveSettingsAutoLinefeedTime, 2, 1, 1, 1) serialReceiveSettingsGroupBox.setLayout(serialReceiveSettingsLayout) settingLayout.addWidget(serialReceiveSettingsGroupBox) # serial send settings serialSendSettingsGroupBox = QGroupBox(parameters.strSerialSendSettings) self.sendSettingsAscii = QRadioButton(parameters.strAscii) self.sendSettingsHex = QRadioButton(parameters.strHex) self.sendSettingsAscii.setChecked(True) self.sendSettingsScheduledCheckBox = QCheckBox(parameters.strScheduled) self.sendSettingsScheduled = QLineEdit(parameters.strScheduledTime) self.sendSettingsScheduledCheckBox.setMaximumWidth(75) self.sendSettingsScheduled.setMaximumWidth(75) self.sendSettingsCFLF = QCheckBox(parameters.strCRLF) self.sendSettingsCFLF.setChecked(False) serialSendSettingsLayout.addWidget(self.sendSettingsAscii,1,0,1,1) serialSendSettingsLayout.addWidget(self.sendSettingsHex,1,1,1,1) serialSendSettingsLayout.addWidget(self.sendSettingsScheduledCheckBox, 2, 0, 1, 1) serialSendSettingsLayout.addWidget(self.sendSettingsScheduled, 2, 1, 1, 1) serialSendSettingsLayout.addWidget(self.sendSettingsCFLF, 3, 0, 1, 2) serialSendSettingsGroupBox.setLayout(serialSendSettingsLayout) settingLayout.addWidget(serialSendSettingsGroupBox) settingLayout.setStretch(0, 5) settingLayout.setStretch(1, 2.5) settingLayout.setStretch(2, 2.5) # right functional layout self.addButton = QPushButton(parameters.strAdd) functionalGroupBox = QGroupBox(parameters.strFunctionalSend) functionalGridLayout = QGridLayout() functionalGridLayout.addWidget(self.addButton,0,1) functionalGroupBox.setLayout(functionalGridLayout) sendFunctionalLayout.addWidget(functionalGroupBox) self.isHideFunctinal = True self.hideFunctional() # main window self.statusBarStauts = QLabel() self.statusBarStauts.setMinimumWidth(80) self.statusBarStauts.setText("<font color=%s>%s</font>" %("#008200", parameters.strReady)) self.statusBarSendCount = QLabel(parameters.strSend+"(bytes): "+"0") self.statusBarReceiveCount = QLabel(parameters.strReceive+"(bytes): "+"0") self.statusBar().addWidget(self.statusBarStauts) self.statusBar().addWidget(self.statusBarSendCount,2) self.statusBar().addWidget(self.statusBarReceiveCount,3) # self.statusBar() self.resize(800, 500) self.MoveToCenter() self.setWindowTitle(parameters.appName+" V"+str(helpAbout.versionMajor)+"."+str(helpAbout.versionMinor)) icon = QIcon() print("icon path:"+self.DataPath+"/"+parameters.appIcon) icon.addPixmap(QPixmap(self.DataPath+"/"+parameters.appIcon), QIcon.Normal, QIcon.Off) self.setWindowIcon(icon) if sys.platform == "win32": ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("comtool") self.show() print("config file path:",os.getcwd()+"comtool.settings.config") return def initEvent(self): self.serialOpenCloseButton.clicked.connect(self.openCloseSerial) self.sendButtion.clicked.connect(self.sendData) self.receiveUpdateSignal.connect(self.updateReceivedDataDisplay) self.clearReceiveButtion.clicked.connect(self.clearReceiveBuffer) self.serialPortCombobox.clicked.connect(self.portComboboxClicked) self.sendSettingsHex.clicked.connect(self.onSendSettingsHexClicked) self.sendSettingsAscii.clicked.connect(self.onSendSettingsAsciiClicked) self.errorSignal.connect(self.errorHint) self.showSerialComboboxSignal.connect(self.showCombobox) # self.showBaudComboboxSignal.connect(self.showBaudCombobox) self.sendHistory.currentIndexChanged.connect(self.sendHistoryIndexChanged) self.settingsButton.clicked.connect(self.showHideSettings) self.skinButton.clicked.connect(self.skinChange) self.aboutButton.clicked.connect(self.showAbout) self.addButton.clicked.connect(self.functionAdd) self.functionalButton.clicked.connect(self.showHideFunctional) self.sendArea.currentCharFormatChanged.connect(self.sendAreaFontChanged) # self.waveButton.clicked.connect(self.openWaveDisplay) self.checkBoxRts.clicked.connect(self.rtsChanged) self.checkBoxDtr.clicked.connect(self.dtrChanged) self.myObject=MyClass(self) slotLambda = lambda: self.indexChanged_lambda(self.myObject) self.serialPortCombobox.currentIndexChanged.connect(slotLambda) # @QtCore.pyqtSlot(str) def indexChanged_lambda(self, obj): mainObj = obj.arg # print("item changed:",mainObj.serialPortCombobox.currentText()) self.serialPortCombobox.setToolTip(mainObj.serialPortCombobox.currentText()) def openCloseSerialProcess(self): try: if self.com.is_open: self.receiveProgressStop = True self.com.close() self.serialOpenCloseButton.setText(parameters.strOpen) self.statusBarStauts.setText("<font color=%s>%s</font>" % ("#f31414", parameters.strClosed)) self.serialPortCombobox.setDisabled(False) self.serailBaudrateCombobox.setDisabled(False) self.serailParityCombobox.setDisabled(False) self.serailStopbitsCombobox.setDisabled(False) self.serailBytesCombobox.setDisabled(False) self.programExitSaveParameters() else: try: self.com.baudrate = int(self.serailBaudrateCombobox.currentText()) self.com.port = self.serialPortCombobox.currentText().split(" ")[0] self.com.bytesize = int(self.serailBytesCombobox.currentText()) self.com.parity = self.serailParityCombobox.currentText()[0] self.com.stopbits = float(self.serailStopbitsCombobox.currentText()) self.com.timeout = None if self.checkBoxRts.isChecked(): self.com.rts = False else: self.com.rts = True if self.checkBoxDtr.isChecked(): self.com.dtr = False else: self.com.dtr = True self.serialOpenCloseButton.setDisabled(True) self.com.open() print("open success") print(self.com) self.serialOpenCloseButton.setText(parameters.strClose) self.statusBarStauts.setText("<font color=%s>%s</font>" % ("#008200", parameters.strReady)) self.serialPortCombobox.setDisabled(True) self.serailBaudrateCombobox.setDisabled(True) self.serailParityCombobox.setDisabled(True) self.serailStopbitsCombobox.setDisabled(True) self.serailBytesCombobox.setDisabled(True) self.serialOpenCloseButton.setDisabled(False) receiveProcess = threading.Thread(target=self.receiveData) receiveProcess.setDaemon(True) receiveProcess.start() except Exception as e: self.com.close() self.receiveProgressStop = True self.errorSignal.emit( parameters.strOpenFailed +"\n"+ str(e)) self.serialOpenCloseButton.setDisabled(False) except Exception: pass return def openCloseSerial(self): t = threading.Thread(target=self.openCloseSerialProcess) t.setDaemon(True) t.start() return def rtsChanged(self): if self.checkBoxRts.isChecked(): self.com.setRTS(False) else: self.com.setRTS(True) def dtrChanged(self): if self.checkBoxDtr.isChecked(): self.com.setDTR(False) else: self.com.setDTR(True) def portComboboxClicked(self): self.detectSerialPort() def getSendData(self): data = self.sendArea.toPlainText() if self.sendSettingsCFLF.isChecked(): data = data.replace("\n", "\r\n") if self.sendSettingsHex.isChecked(): if self.sendSettingsCFLF.isChecked(): data = data.replace("\r\n", " ") else: data = data.replace("\n", " ") data = self.hexStringB2Hex(data) if data == -1: self.errorSignal.emit( parameters.strWriteFormatError) return -1 else: data = data.encode(self.encodingCombobox.currentText(),"ignore") return data def sendData(self): try: if self.com.is_open: data = self.getSendData() if data == -1: return print(self.sendArea.toPlainText()) print("send:",data) self.sendCount += len(data) self.com.write(data) data = self.sendArea.toPlainText() self.sendHistoryFindDelete(data) self.sendHistory.insertItem(0,data) self.sendHistory.setCurrentIndex(0) self.receiveUpdateSignal.emit("") # scheduled send if self.sendSettingsScheduledCheckBox.isChecked(): if not self.isScheduledSending: t = threading.Thread(target=self.scheduledSend) t.setDaemon(True) t.start() except Exception as e: self.errorSignal.emit(parameters.strWriteError) print(e) return def scheduledSend(self): self.isScheduledSending = True while self.sendSettingsScheduledCheckBox.isChecked(): self.sendData() try: time.sleep(int(self.sendSettingsScheduled.text().strip())/1000) except Exception: self.errorSignal.emit(parameters.strTimeFormatError) self.isScheduledSending = False return def receiveData(self): self.receiveProgressStop = False self.timeLastReceive = 0 while(not self.receiveProgressStop): try: # length = self.com.in_waiting length = max(1, min(2048, self.com.in_waiting)) bytes = self.com.read(length) if bytes!= None: # if self.isWaveOpen: # self.wave.displayData(bytes) self.receiveCount += len(bytes) if self.receiveSettingsHex.isChecked(): strReceived = self.asciiB2HexString(bytes) self.receiveUpdateSignal.emit(strReceived) else: self.receiveUpdateSignal.emit(bytes.decode(self.encodingCombobox.currentText(),"ignore")) if self.receiveSettingsAutoLinefeed.isChecked(): if time.time() - self.timeLastReceive> int(self.receiveSettingsAutoLinefeedTime.text())/1000: if self.sendSettingsCFLF.isChecked(): self.receiveUpdateSignal.emit("\r\n") else: self.receiveUpdateSignal.emit("\n") self.timeLastReceive = time.time() except Exception as e: print("receiveData error") if self.com.is_open and not self.serialPortCombobox.isEnabled(): self.openCloseSerial() self.serialPortCombobox.clear() self.detectSerialPort() print(e) # time.sleep(0.009) return def updateReceivedDataDisplay(self,str): if str != "": curScrollValue = self.receiveArea.verticalScrollBar().value() self.receiveArea.moveCursor(QTextCursor.End) endScrollValue = self.receiveArea.verticalScrollBar().value() self.receiveArea.insertPlainText(str) if curScrollValue < endScrollValue: self.receiveArea.verticalScrollBar().setValue(curScrollValue) else: self.receiveArea.moveCursor(QTextCursor.End) self.statusBarSendCount.setText("%s(bytes):%d" %(parameters.strSend ,self.sendCount)) self.statusBarReceiveCount.setText("%s(bytes):%d" %(parameters.strReceive ,self.receiveCount)) return def onSendSettingsHexClicked(self): data = self.sendArea.toPlainText().replace("\n","\r\n") data = self.asciiB2HexString(data.encode()) self.sendArea.clear() self.sendArea.insertPlainText(data) return def onSendSettingsAsciiClicked(self): try: data = self.sendArea.toPlainText().replace("\n"," ").strip() self.sendArea.clear() if data != "": data = self.hexStringB2Hex(data).decode(self.encodingCombobox.currentText(),'ignore') self.sendArea.insertPlainText(data) except Exception as e: # QMessageBox.information(self,parameters.strWriteFormatError,parameters.strWriteFormatError) print("format error"); return def sendHistoryIndexChanged(self): self.sendArea.clear() self.sendArea.insertPlainText(self.sendHistory.currentText()) return def clearReceiveBuffer(self): self.receiveArea.clear() self.receiveCount = 0; self.sendCount = 0; self.receiveUpdateSignal.emit(None) return def MoveToCenter(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) return def errorHint(self,str): QMessageBox.information(self, str, str) return def closeEvent(self, event): reply = QMessageBox.question(self, 'Sure To Quit?', "Are you sure to quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: self.com.close() self.receiveProgressStop = True self.programExitSaveParameters() event.accept() else: event.ignore() def findSerialPort(self): self.port_list = list(serial.tools.list_ports.comports()) return self.port_list def portChanged(self): self.serialPortCombobox.setCurrentIndex(0) self.serialPortCombobox.setToolTip(str(self.portList[0])) def detectSerialPort(self): if not self.isDetectSerialPort: self.isDetectSerialPort = True t = threading.Thread(target=self.detectSerialPortProcess) t.setDaemon(True) t.start() def showCombobox(self): self.serialPortCombobox.showPopup() def detectSerialPortProcess(self): while(1): portList = self.findSerialPort() if len(portList)>0: currText = self.serialPortCombobox.currentText() self.serialPortCombobox.clear() for i in portList: showStr = str(i[0])+" "+str(i[1]) self.serialPortCombobox.addItem(showStr) index = self.serialPortCombobox.findText(currText) if index>=0: self.serialPortCombobox.setCurrentIndex(index) else: self.serialPortCombobox.setCurrentIndex(0) break time.sleep(1) self.showSerialComboboxSignal.emit() self.isDetectSerialPort = False return def sendHistoryFindDelete(self,str): self.sendHistory.removeItem(self.sendHistory.findText(str)) return def test(self): print("test") return def asciiB2HexString(self,strB): strHex = binascii.b2a_hex(strB).upper() return re.sub(r"(?<=\w)(?=(?:\w\w)+$)", " ", strHex.decode())+" " def hexStringB2Hex(self,hexString): dataList = hexString.split(" ") j = 0 for i in dataList: if len(i) > 2: return -1 elif len(i) == 1: dataList[j] = "0" + i j += 1 data = "".join(dataList) try: data = bytes.fromhex(data) except Exception: return -1 print(data) return data def programExitSaveParameters(self): paramObj = parameters.ParametersToSave() paramObj.baudRate = self.serailBaudrateCombobox.currentIndex() paramObj.dataBytes = self.serailBytesCombobox.currentIndex() paramObj.parity = self.serailParityCombobox.currentIndex() paramObj.stopBits = self.serailStopbitsCombobox.currentIndex() paramObj.skin = self.param.skin if self.receiveSettingsHex.isChecked(): paramObj.receiveAscii = False if not self.receiveSettingsAutoLinefeed.isChecked(): paramObj.receiveAutoLinefeed = False else: paramObj.receiveAutoLinefeed = True paramObj.receiveAutoLindefeedTime = self.receiveSettingsAutoLinefeedTime.text() if self.sendSettingsHex.isChecked(): paramObj.sendAscii = False if not self.sendSettingsScheduledCheckBox.isChecked(): paramObj.sendScheduled = False paramObj.sendScheduledTime = self.sendSettingsScheduled.text() if not self.sendSettingsCFLF.isChecked(): paramObj.useCRLF = False paramObj.sendHistoryList.clear() for i in range(0,self.sendHistory.count()): paramObj.sendHistoryList.append(self.sendHistory.itemText(i)) if self.checkBoxRts.isChecked(): paramObj.rts = 1 else: paramObj.rts = 0 if self.checkBoxDtr.isChecked(): paramObj.dtr = 1 else: paramObj.dtr = 0 paramObj.encodingIndex = self.encodingCombobox.currentIndex() f = open("comtool.settings.config","wb") f.truncate() pickle.dump(paramObj, f) pickle.dump(paramObj.sendHistoryList,f) f.close() return def programStartGetSavedParameters(self): paramObj = parameters.ParametersToSave() try: f = open("comtool.settings.config", "rb") paramObj = pickle.load( f) paramObj.sendHistoryList = pickle.load(f) f.close() except Exception as e: f = open("comtool.settings.config", "wb") f.close() self.serailBaudrateCombobox.setCurrentIndex(paramObj.baudRate) self.serailBytesCombobox.setCurrentIndex(paramObj.dataBytes) self.serailParityCombobox.setCurrentIndex(paramObj.parity) self.serailStopbitsCombobox.setCurrentIndex(paramObj.stopBits) if paramObj.receiveAscii == False: self.receiveSettingsHex.setChecked(True) if paramObj.receiveAutoLinefeed == False: self.receiveSettingsAutoLinefeed.setChecked(False) else: self.receiveSettingsAutoLinefeed.setChecked(True) self.receiveSettingsAutoLinefeedTime.setText(paramObj.receiveAutoLindefeedTime) if paramObj.sendAscii == False: self.sendSettingsHex.setChecked(True) if paramObj.sendScheduled == False: self.sendSettingsScheduledCheckBox.setChecked(False) else: self.sendSettingsScheduledCheckBox.setChecked(True) self.sendSettingsScheduled.setText(paramObj.sendScheduledTime) if paramObj.useCRLF == False: self.sendSettingsCFLF.setChecked(False) else: self.sendSettingsCFLF.setChecked(True) for i in range(0, len(paramObj.sendHistoryList)): str = paramObj.sendHistoryList[i] self.sendHistory.addItem(str) if paramObj.rts == 0: self.checkBoxRts.setChecked(False) else: self.checkBoxRts.setChecked(True) if paramObj.dtr == 0: self.checkBoxDtr.setChecked(False) else: self.checkBoxDtr.setChecked(True) self.encodingCombobox.setCurrentIndex(paramObj.encodingIndex) self.param = paramObj return def keyPressEvent(self, event): if event.key() == Qt.Key_Control: self.keyControlPressed = True elif event.key() == Qt.Key_Return or event.key()==Qt.Key_Enter: if self.keyControlPressed: self.sendData() elif event.key() == Qt.Key_L: if self.keyControlPressed: self.sendArea.clear() elif event.key() == Qt.Key_K: if self.keyControlPressed: self.receiveArea.clear() return def keyReleaseEvent(self,event): if event.key() == Qt.Key_Control: self.keyControlPressed = False return def sendAreaFontChanged(self,font): print("font changed") return def functionAdd(self): QMessageBox.information(self, "On the way", "On the way") return def showHideSettings(self): if self.isHideSettings: self.showSettings() self.isHideSettings = False else: self.hideSettings() self.isHideSettings = True return def showSettings(self): self.settingWidget.show() self.settingsButton.setStyleSheet( parameters.strStyleShowHideButtonLeft.replace("$DataPath",self.DataPath)) return; def hideSettings(self): self.settingWidget.hide() self.settingsButton.setStyleSheet( parameters.strStyleShowHideButtonRight.replace("$DataPath", self.DataPath)) return; def showHideFunctional(self): if self.isHideFunctinal: self.showFunctional() self.isHideFunctinal = False else: self.hideFunctional() self.isHideFunctinal = True return def showFunctional(self): self.functionalWiget.show() self.functionalButton.setStyleSheet( parameters.strStyleShowHideButtonRight.replace("$DataPath",self.DataPath)) return; def hideFunctional(self): self.functionalWiget.hide() self.functionalButton.setStyleSheet( parameters.strStyleShowHideButtonLeft.replace("$DataPath", self.DataPath)) return; def skinChange(self): if self.param.skin == 1: # light file = open(self.DataPath + '/assets/qss/style-dark.qss', "r") self.param.skin = 2 else: # elif self.param.skin == 2: # dark file = open(self.DataPath + '/assets/qss/style.qss', "r") self.param.skin = 1 self.app.setStyleSheet(file.read().replace("$DataPath", self.DataPath)) return def showAbout(self): QMessageBox.information(self, "About","<h1 style='color:#f75a5a';margin=10px;>"+parameters.appName+ '</h1><br><b style="color:#08c7a1;margin = 5px;">V'+str(helpAbout.versionMajor)+"."+ str(helpAbout.versionMinor)+"."+str(helpAbout.versionDev)+ "</b><br><br>"+helpAbout.date+"<br><br>"+helpAbout.strAbout()) return def action1(self): print("action1") return def autoUpdateDetect(self): auto = autoUpdate.AutoUpdate() if auto.detectNewVersion(): auto.OpenBrowser() def openDevManagement(self): os.system('start devmgmt.msc')
Model/view documentation can be found at http://doc.qt.nokia.com/latest/model-view-programming.html. """ import sys from PyQt5.QtCore import QDir from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QColumnView from PyQt5.QtWidgets import QFileSystemModel from PyQt5.QtWidgets import QSplitter from PyQt5.QtWidgets import QTreeView if __name__ == '__main__': app = QApplication(sys.argv) # Splitter to show 2 views in same widget easily. splitter = QSplitter() # The model. model = QFileSystemModel() # You can setRootPath to any path. model.setRootPath(QDir.rootPath()) # List of views. views = [] for ViewType in (QColumnView, QTreeView): # Create the view in the splitter. view = ViewType(splitter) # Set the model of the view. view.setModel(model) # # Set the root index of the view as the user's home directory. view.setRootIndex(model.index(QDir.homePath())) # Show the splitter. splitter.show()
def initUI(self): hbox = QHBoxLayout() top = QFrame() top.setFrameShape(QFrame.Box) midleft = QFrame() midleft.setFrameShape(QFrame.StyledPanel) midright = QFrame() midright.setFrameShape(QFrame.Panel) bottom = QFrame() bottom.setFrameShape(QFrame.WinPanel) bottom.setFrameShadow(QFrame.Sunken) splitter1 = QSplitter(Qt.Horizontal) splitter1.addWidget(midleft) splitter1.addWidget(midright) splitter2 = QSplitter(Qt.Vertical) splitter2.addWidget(top) splitter2.addWidget(splitter1) splitter2.addWidget(bottom) hbox.addWidget(splitter2) self.setLayout(hbox) self.setGeometry(300, 300, 300, 200) self.setWindowTitle('QSplitter') self.show()
class UIController(object): documentModifiedText = "" documentStatusBarText = "untitled" def __init__(self): self.mainWidget = scripterdialog.ScripterDialog(self) self.actionToolbar = QToolBar('toolBar', self.mainWidget) self.menu_bar = QMenuBar(self.mainWidget) self.actionToolbar.setObjectName('toolBar') self.menu_bar.setObjectName('menuBar') self.actions = [] self.mainWidget.setWindowModality(Qt.NonModal) def initialize(self, scripter): self.editor = pythoneditor.CodeEditor(scripter) self.tabWidget = QTabWidget() self.statusBar = Elided_Text_Label() self.statusBar.setMainText('untitled') self.splitter = QSplitter() self.splitter.setOrientation(Qt.Vertical) self.highlight = syntax.PythonHighlighter(self.editor.document(), syntaxstyles.DefaultSyntaxStyle()) p = self.editor.palette() p.setColor(QPalette.Base, syntaxstyles.DefaultSyntaxStyle()['background'].foreground().color()) p.setColor(QPalette.Text, syntaxstyles.DefaultSyntaxStyle()['foreground'].foreground().color()) self.editor.setPalette(p) self.scripter = scripter self.loadMenus() self.loadWidgets() self.loadActions() self._readSettings() # sets window size vbox = QVBoxLayout(self.mainWidget) vbox.addWidget(self.menu_bar) vbox.addWidget(self.actionToolbar) self.splitter.addWidget(self.editor) self.splitter.addWidget(self.tabWidget) vbox.addWidget(self.splitter) vbox.addWidget(self.statusBar) self.mainWidget.setWindowTitle(i18n("Scripter")) self.mainWidget.setSizeGripEnabled(True) self.mainWidget.show() self.mainWidget.activateWindow() self.editor.undoAvailable.connect(self.setStatusModified) def loadMenus(self): self.addMenu('File', 'File') def addMenu(self, menuName, parentName): parent = self.menu_bar.findChild(QObject, parentName) self.newMenu = None if parent: self.newMenu = parent.addMenu(menuName) else: self.newMenu = self.menu_bar.addMenu(menuName) self.newMenu.setObjectName(menuName) return self.newMenu def loadActions(self): module_path = 'scripter.ui_scripter.actions' actions_module = importlib.import_module(module_path) modules = [] for class_path in actions_module.action_classes: _module = class_path[:class_path.rfind(".")] _klass = class_path[class_path.rfind(".") + 1:] modules.append(dict(module='{0}.{1}'.format(module_path, _module), klass=_klass)) for module in modules: m = importlib.import_module(module['module']) action_class = getattr(m, module['klass']) obj = action_class(self.scripter) parent = self.mainWidget.findChild(QObject, obj.parent) self.actions.append(dict(action=obj, parent=parent)) for action in self.actions: action['parent'].addAction(action['action']) def loadWidgets(self): modulePath = 'scripter.ui_scripter.tabwidgets' widgetsModule = importlib.import_module(modulePath) modules = [] for class_path in widgetsModule.widgetClasses: _module = class_path[:class_path.rfind(".")] _klass = class_path[class_path.rfind(".") + 1:] modules.append(dict(module='{0}.{1}'.format(modulePath, _module), klass=_klass)) for module in modules: m = importlib.import_module(module['module']) widgetClass = getattr(m, module['klass']) obj = widgetClass(self.scripter) self.tabWidget.addTab(obj, obj.objectName()) def invokeAction(self, actionName): for action in self.actions: if action['action'].objectName() == actionName: method = getattr(action['action'], actionName) if method: return method() def findTabWidget(self, widgetName, childName=''): for index in range(self.tabWidget.count()): widget = self.tabWidget.widget(index) if widget.objectName() == widgetName: if childName: widget = widget.findChild(QObject, childName) return widget def showException(self, exception): QMessageBox.critical(self.editor, i18n("Error Running Script"), str(exception)) def setDocumentEditor(self, document): self.editor.clear() self.editor.moveCursor(QTextCursor.Start) self.editor._documentModified = False self.editor.setPlainText(document.data) self.editor.moveCursor(QTextCursor.End) def setStatusBar(self, value='untitled'): self.documentStatusBarText = value self.statusBar.setMainText(self.documentStatusBarText + self.documentModifiedText) def setStatusModified(self): self.documentModifiedText = "" if (self.editor._documentModified is True): self.documentModifiedText = " [Modified]" self.statusBar.setMainText(self.documentStatusBarText + self.documentModifiedText) def setActiveWidget(self, widgetName): widget = self.findTabWidget(widgetName) if widget: self.tabWidget.setCurrentWidget(widget) def setStepped(self, status): self.editor.setStepped(status) def clearEditor(self): self.editor.clear() def repaintDebugArea(self): self.editor.repaintDebugArea() def closeScripter(self): self.mainWidget.close() def _writeSettings(self): """ _writeSettings is a method invoked when the scripter starts, making control inversion. Actions can implement a writeSettings method to save your own settings without this method to know about it. """ self.scripter.settings.beginGroup('scripter') document = self.scripter.documentcontroller.activeDocument if document: self.scripter.settings.setValue('activeDocumentPath', document.filePath) else: self.scripter.settings.setValue('activeDocumentPath', '') self.scripter.settings.setValue('editorFontSize', self.editor.fontInfo().pointSize()) for action in self.actions: writeSettings = getattr(action['action'], "writeSettings", None) if callable(writeSettings): writeSettings() # Window Geometry rect = self.mainWidget.geometry() self.scripter.settings.setValue(KEY_GEOMETRY, rect) self.scripter.settings.endGroup() def _readSettings(self): """ It's similar to _writeSettings, but reading the settings when the ScripterDialog is closed. """ self.scripter.settings.beginGroup('scripter') activeDocumentPath = self.scripter.settings.value('activeDocumentPath', '') if activeDocumentPath: if QFileInfo(activeDocumentPath).exists(): document = self.scripter.documentcontroller.openDocument(activeDocumentPath) self.setStatusBar(document.filePath) self.setDocumentEditor(document) for action in self.actions: readSettings = getattr(action['action'], "readSettings", None) if callable(readSettings): readSettings() pointSize = self.scripter.settings.value('editorFontSize', str(self.editor.fontInfo().pointSize())) self.editor.setFontSize(int(pointSize)) # Window Geometry rect = self.scripter.settings.value(KEY_GEOMETRY, DEFAULT_GEOMETRY) self.mainWidget.setGeometry(rect) self.scripter.settings.endGroup() def _saveSettings(self): self.scripter.settings.sync()
def initWindow(self): QToolTip.setFont(QFont('SansSerif', 10)) # main layout frameWidget = QWidget() mainWidget = QSplitter(Qt.Horizontal) frameLayout = QVBoxLayout() self.settingWidget = QWidget() self.settingWidget.setProperty("class","settingWidget") self.receiveSendWidget = QSplitter(Qt.Vertical) self.functionalWiget = QWidget() settingLayout = QVBoxLayout() sendReceiveLayout = QVBoxLayout() sendFunctionalLayout = QVBoxLayout() mainLayout = QHBoxLayout() self.settingWidget.setLayout(settingLayout) self.receiveSendWidget.setLayout(sendReceiveLayout) self.functionalWiget.setLayout(sendFunctionalLayout) mainLayout.addWidget(self.settingWidget) mainLayout.addWidget(self.receiveSendWidget) mainLayout.addWidget(self.functionalWiget) mainLayout.setStretch(0,2) mainLayout.setStretch(1, 6) mainLayout.setStretch(2, 2) menuLayout = QHBoxLayout() mainWidget.setLayout(mainLayout) frameLayout.addLayout(menuLayout) frameLayout.addWidget(mainWidget) frameWidget.setLayout(frameLayout) self.setCentralWidget(frameWidget) # option layout self.settingsButton = QPushButton() self.skinButton = QPushButton("") # self.waveButton = QPushButton("") self.aboutButton = QPushButton() self.functionalButton = QPushButton() self.encodingCombobox = ComboBox() self.encodingCombobox.addItem("ASCII") self.encodingCombobox.addItem("UTF-8") self.encodingCombobox.addItem("UTF-16") self.encodingCombobox.addItem("GBK") self.encodingCombobox.addItem("GB2312") self.encodingCombobox.addItem("GB18030") self.settingsButton.setProperty("class", "menuItem1") self.skinButton.setProperty("class", "menuItem2") self.aboutButton.setProperty("class", "menuItem3") self.functionalButton.setProperty("class", "menuItem4") # self.waveButton.setProperty("class", "menuItem5") self.settingsButton.setObjectName("menuItem") self.skinButton.setObjectName("menuItem") self.aboutButton.setObjectName("menuItem") self.functionalButton.setObjectName("menuItem") # self.waveButton.setObjectName("menuItem") menuLayout.addWidget(self.settingsButton) menuLayout.addWidget(self.skinButton) # menuLayout.addWidget(self.waveButton) menuLayout.addWidget(self.aboutButton) menuLayout.addStretch(0) menuLayout.addWidget(self.encodingCombobox) menuLayout.addWidget(self.functionalButton) # widgets receive and send area self.receiveArea = QTextEdit() self.sendArea = QTextEdit() self.clearReceiveButtion = QPushButton(parameters.strClearReceive) self.sendButtion = QPushButton(parameters.strSend) self.sendHistory = ComboBox() sendWidget = QWidget() sendAreaWidgetsLayout = QHBoxLayout() sendWidget.setLayout(sendAreaWidgetsLayout) buttonLayout = QVBoxLayout() buttonLayout.addWidget(self.clearReceiveButtion) buttonLayout.addStretch(1) buttonLayout.addWidget(self.sendButtion) sendAreaWidgetsLayout.addWidget(self.sendArea) sendAreaWidgetsLayout.addLayout(buttonLayout) sendReceiveLayout.addWidget(self.receiveArea) sendReceiveLayout.addWidget(sendWidget) sendReceiveLayout.addWidget(self.sendHistory) sendReceiveLayout.setStretch(0, 7) sendReceiveLayout.setStretch(1, 2) sendReceiveLayout.setStretch(2, 1) # widgets serial settings serialSettingsGroupBox = QGroupBox(parameters.strSerialSettings) serialSettingsLayout = QGridLayout() serialReceiveSettingsLayout = QGridLayout() serialSendSettingsLayout = QGridLayout() serialPortLabek = QLabel(parameters.strSerialPort) serailBaudrateLabel = QLabel(parameters.strSerialBaudrate) serailBytesLabel = QLabel(parameters.strSerialBytes) serailParityLabel = QLabel(parameters.strSerialParity) serailStopbitsLabel = QLabel(parameters.strSerialStopbits) self.serialPortCombobox = ComboBox() self.serailBaudrateCombobox = ComboBox() self.serailBaudrateCombobox.addItem("9600") self.serailBaudrateCombobox.addItem("19200") self.serailBaudrateCombobox.addItem("38400") self.serailBaudrateCombobox.addItem("57600") self.serailBaudrateCombobox.addItem("115200") self.serailBaudrateCombobox.setCurrentIndex(4) self.serailBaudrateCombobox.setEditable(True) self.serailBytesCombobox = ComboBox() self.serailBytesCombobox.addItem("5") self.serailBytesCombobox.addItem("6") self.serailBytesCombobox.addItem("7") self.serailBytesCombobox.addItem("8") self.serailBytesCombobox.setCurrentIndex(3) self.serailParityCombobox = ComboBox() self.serailParityCombobox.addItem("None") self.serailParityCombobox.addItem("Odd") self.serailParityCombobox.addItem("Even") self.serailParityCombobox.addItem("Mark") self.serailParityCombobox.addItem("Space") self.serailParityCombobox.setCurrentIndex(0) self.serailStopbitsCombobox = ComboBox() self.serailStopbitsCombobox.addItem("1") self.serailStopbitsCombobox.addItem("1.5") self.serailStopbitsCombobox.addItem("2") self.serailStopbitsCombobox.setCurrentIndex(0) self.checkBoxRts = QCheckBox("rts") self.checkBoxDtr = QCheckBox("dtr") self.serialOpenCloseButton = QPushButton(parameters.strOpen) serialSettingsLayout.addWidget(serialPortLabek,0,0) serialSettingsLayout.addWidget(serailBaudrateLabel, 1, 0) serialSettingsLayout.addWidget(serailBytesLabel, 2, 0) serialSettingsLayout.addWidget(serailParityLabel, 3, 0) serialSettingsLayout.addWidget(serailStopbitsLabel, 4, 0) serialSettingsLayout.addWidget(self.serialPortCombobox, 0, 1) serialSettingsLayout.addWidget(self.serailBaudrateCombobox, 1, 1) serialSettingsLayout.addWidget(self.serailBytesCombobox, 2, 1) serialSettingsLayout.addWidget(self.serailParityCombobox, 3, 1) serialSettingsLayout.addWidget(self.serailStopbitsCombobox, 4, 1) serialSettingsLayout.addWidget(self.checkBoxRts, 5, 0,1,1) serialSettingsLayout.addWidget(self.checkBoxDtr, 5, 1,1,1) serialSettingsLayout.addWidget(self.serialOpenCloseButton, 6, 0,1,2) serialSettingsGroupBox.setLayout(serialSettingsLayout) settingLayout.addWidget(serialSettingsGroupBox) # serial receive settings serialReceiveSettingsGroupBox = QGroupBox(parameters.strSerialReceiveSettings) self.receiveSettingsAscii = QRadioButton(parameters.strAscii) self.receiveSettingsHex = QRadioButton(parameters.strHex) self.receiveSettingsAscii.setChecked(True) self.receiveSettingsAutoLinefeed = QCheckBox(parameters.strAutoLinefeed) self.receiveSettingsAutoLinefeedTime = QLineEdit(parameters.strAutoLinefeedTime) self.receiveSettingsAutoLinefeed.setMaximumWidth(75) self.receiveSettingsAutoLinefeedTime.setMaximumWidth(75) serialReceiveSettingsLayout.addWidget(self.receiveSettingsAscii,1,0,1,1) serialReceiveSettingsLayout.addWidget(self.receiveSettingsHex,1,1,1,1) serialReceiveSettingsLayout.addWidget(self.receiveSettingsAutoLinefeed, 2, 0, 1, 1) serialReceiveSettingsLayout.addWidget(self.receiveSettingsAutoLinefeedTime, 2, 1, 1, 1) serialReceiveSettingsGroupBox.setLayout(serialReceiveSettingsLayout) settingLayout.addWidget(serialReceiveSettingsGroupBox) # serial send settings serialSendSettingsGroupBox = QGroupBox(parameters.strSerialSendSettings) self.sendSettingsAscii = QRadioButton(parameters.strAscii) self.sendSettingsHex = QRadioButton(parameters.strHex) self.sendSettingsAscii.setChecked(True) self.sendSettingsScheduledCheckBox = QCheckBox(parameters.strScheduled) self.sendSettingsScheduled = QLineEdit(parameters.strScheduledTime) self.sendSettingsScheduledCheckBox.setMaximumWidth(75) self.sendSettingsScheduled.setMaximumWidth(75) self.sendSettingsCFLF = QCheckBox(parameters.strCRLF) self.sendSettingsCFLF.setChecked(False) serialSendSettingsLayout.addWidget(self.sendSettingsAscii,1,0,1,1) serialSendSettingsLayout.addWidget(self.sendSettingsHex,1,1,1,1) serialSendSettingsLayout.addWidget(self.sendSettingsScheduledCheckBox, 2, 0, 1, 1) serialSendSettingsLayout.addWidget(self.sendSettingsScheduled, 2, 1, 1, 1) serialSendSettingsLayout.addWidget(self.sendSettingsCFLF, 3, 0, 1, 2) serialSendSettingsGroupBox.setLayout(serialSendSettingsLayout) settingLayout.addWidget(serialSendSettingsGroupBox) settingLayout.setStretch(0, 5) settingLayout.setStretch(1, 2.5) settingLayout.setStretch(2, 2.5) # right functional layout self.addButton = QPushButton(parameters.strAdd) functionalGroupBox = QGroupBox(parameters.strFunctionalSend) functionalGridLayout = QGridLayout() functionalGridLayout.addWidget(self.addButton,0,1) functionalGroupBox.setLayout(functionalGridLayout) sendFunctionalLayout.addWidget(functionalGroupBox) self.isHideFunctinal = True self.hideFunctional() # main window self.statusBarStauts = QLabel() self.statusBarStauts.setMinimumWidth(80) self.statusBarStauts.setText("<font color=%s>%s</font>" %("#008200", parameters.strReady)) self.statusBarSendCount = QLabel(parameters.strSend+"(bytes): "+"0") self.statusBarReceiveCount = QLabel(parameters.strReceive+"(bytes): "+"0") self.statusBar().addWidget(self.statusBarStauts) self.statusBar().addWidget(self.statusBarSendCount,2) self.statusBar().addWidget(self.statusBarReceiveCount,3) # self.statusBar() self.resize(800, 500) self.MoveToCenter() self.setWindowTitle(parameters.appName+" V"+str(helpAbout.versionMajor)+"."+str(helpAbout.versionMinor)) icon = QIcon() print("icon path:"+self.DataPath+"/"+parameters.appIcon) icon.addPixmap(QPixmap(self.DataPath+"/"+parameters.appIcon), QIcon.Normal, QIcon.Off) self.setWindowIcon(icon) if sys.platform == "win32": ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("comtool") self.show() print("config file path:",os.getcwd()+"comtool.settings.config") return
class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.cur_file = "" self.splitter = QSplitter() self.text_edit = QTextEdit("") self.preview = QWebEngineView() self.preview.setMinimumWidth(300) self.setWindowTitle("Markdown [*]") self.splitter.addWidget(self.text_edit) self.splitter.addWidget(self.preview) self.setCentralWidget(self.splitter) self.createMenus() self.createStatusBar() self.readSettings() self.text_edit.document().contentsChanged.connect( self.documentWasModified) self.text_edit.textChanged.connect(self.textChanged) def closeEvent(self, event): if self.maybeSave(): self.writeSettings() event.accept() else: event.ignore() def documentWasModified(self): self.setWindowModified(self.text_edit.document().isModified()) def createMenus(self): new_icon = QIcon("./assets/new.png") open_icon = QIcon("./assets/open.png") save_icon = QIcon("./assets/save.png") save_as_icon = QIcon("./assets/save_as.png") exit_icon = QIcon("./assets/exit.png") new_act = QAction(new_icon, "&New", self) new_act.setShortcuts(QKeySequence.New) new_act.setStatusTip("Create a new file") new_act.triggered.connect(self.newFile) open_act = QAction(open_icon, "&Open", self) open_act.setShortcuts(QKeySequence.Open) open_act.setStatusTip("Open an existing file") open_act.triggered.connect(self.open) save_act = QAction(save_icon, "&Save", self) save_act.setShortcuts(QKeySequence.Save) save_act.setStatusTip("Save the document to disk") save_act.triggered.connect(self.save) save_as_act = QAction(save_as_icon, "Save &As...", self) save_as_act.setShortcuts(QKeySequence.SaveAs) save_as_act.setStatusTip("Save the document under a new name") save_as_act.triggered.connect(self.saveAs) exit_act = QAction(exit_icon, "E&xit", self) exit_act.setShortcuts(QKeySequence.Quit) exit_act.setStatusTip("Exit the application") exit_act.triggered.connect(self.close) about_act = QAction("&About", self) about_act.triggered.connect(self.about) about_act.setStatusTip("Show the application's About box") file_menu = self.menuBar().addMenu("&File") file_menu.addAction(new_act) file_menu.addAction(open_act) file_menu.addAction(save_act) file_menu.addAction(save_as_act) file_menu.addSeparator() file_menu.addAction(exit_act) help_menu = self.menuBar().addMenu("&Help") help_menu.addAction(about_act) file_tool_bar = self.addToolBar("File") file_tool_bar.addAction(new_act) file_tool_bar.addAction(open_act) file_tool_bar.addAction(save_act) def createStatusBar(self): self.statusBar().showMessage("Ready") def about(self): QMessageBox.about( self, "About Markdown", "This app demonstrates how to " "write modern GUI applications using Qt, with a menu bar, " "toolbars, and a status bar.") def newFile(self): if self.maybeSave(): self.text_edit.clear() self.setCurrentFile("") def open(self): if self.maybeSave(): fileName = QFileDialog.getOpenFileName(self)[0] if fileName: self.loadFile(fileName) def save(self): if not self.cur_file: return self.saveAs() else: return self.saveFile(self.cur_file) def saveAs(self): dialog = QFileDialog(self) dialog.setWindowModality(Qt.WindowModal) dialog.setAcceptMode(QFileDialog.AcceptSave) if dialog.exec() != QDialog.Accepted: return False return self.saveFile(dialog.selectedFiles()[0]) def maybeSave(self): if not self.text_edit.document().isModified(): return True ret = QMessageBox.warning( self, "Qt Demo", "The document has been modified.\n" "Do you want to save your changes?", QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) if ret == QMessageBox.Save: return self.save() elif ret == QMessageBox.Cancel: return False return True def loadFile(self, fileName): with open(fileName, mode="r") as f: text = f.read() QApplication.setOverrideCursor(Qt.WaitCursor) self.setCurrentFile(fileName) self.text_edit.setPlainText(text) self.text_edit.document().setModified(False) self.setWindowModified(False) QApplication.restoreOverrideCursor() self.statusBar().showMessage("File loaded", 2000) def saveFile(self, fileName): QApplication.setOverrideCursor(Qt.WaitCursor) with open(fileName, "w") as f: f.write(self.text_edit.toPlainText()) QApplication.restoreOverrideCursor() self.setCurrentFile(fileName) self.text_edit.document().setModified(False) self.setWindowModified(False) self.statusBar().showMessage("File saved", 2000) def setCurrentFile(self, fileName): self.cur_file = fileName shown_name = self.cur_file if not self.cur_file: shown_name = "untitled.txt" self.setWindowFilePath(shown_name) def writeSettings(self): settings = QSettings(QCoreApplication.organizationName(), QCoreApplication.applicationName()) settings.setValue("geometry", self.saveGeometry()) def readSettings(self): settings = QSettings(QCoreApplication.organizationName(), QCoreApplication.applicationName()) geometry = settings.value("geometry", QByteArray()) if not geometry: availableGeometry = QApplication.desktop().availableGeometry(self) self.resize(availableGeometry.width() / 3, availableGeometry.height() / 2) self.move((availableGeometry.width() - self.width()) / 2, (availableGeometry.height() - self.height()) / 2) else: self.restoreGeometry(geometry) def textChanged(self): path = os.getcwd() html = "<html><head><link href=\"assets/pastie.css\" rel=\"stylesheet\" type=\"text/css\"/></head><body>" html += markdown2.markdown(self.text_edit.toPlainText(), ..., extras=["fenced-code-blocks"]) html += "</body></html>" self.preview.setHtml(html, baseUrl=QUrl("file://" + path + "/"))
class SessionUi(QTabWidget): TAB_MODULES = 0 TAB_RANGES = 1 TAB_DATA = 2 TAB_ASM = 3 def __init__(self, app, *__args): super().__init__(*__args) self.app = app self.setTabsClosable(True) self.setMovable(True) self.tabCloseRequested.connect(self.removeTab) self.setContentsMargins(2, 2, 2, 2) self.setStyleSheet(""" QListWidget:hover, QTableWidget:hover { border: 1px solid transparent; } QTabWidget QFrame{ border: 0; } QTabWidget::pane { border: 0px solid transparent; border-radius: 0px; padding: 0px; margin: 0px; } QTabWidget::pane:selected { background-color: transparent; border: 0px solid transparent; } QWidget { padding: 0; margin-top: 2px; margin-right: 2px; margin-left: 1px; } """) self.session_panel = QSplitter() self.modules_panel = None self.ranges_panel = None self.registers_panel = None self.memory_panel = None self.log_panel = None self.backtrace_panel = None self.hooks_panel = None self.contexts_panel = None self.data_panel = DataPanel(self.app) self.asm_panel = AsmPanel(self.app) self.session_panel.addWidget(self.build_left_column()) self.session_panel.addWidget(self.build_central_content()) self.session_panel.setHandleWidth(1) self.session_panel.setStretchFactor(0, 2) self.session_panel.setStretchFactor(1, 6) self.session_panel.setContentsMargins(0, 0, 0, 0) self.modules_panel = ModulesPanel(self.app) self.ranges_panel = RangesPanel(self.app) self.addTab(self.session_panel, 'session') bt = self.tabBar().tabButton(0, QTabBar.LeftSide) if not bt: bt = self.tabBar().tabButton(0, QTabBar.RightSide) if bt: bt.resize(0, 0) def add_main_tabs(self): self.add_dwarf_tab(SessionUi.TAB_MODULES) self.add_dwarf_tab(SessionUi.TAB_RANGES) def build_left_column(self): splitter = QSplitter() splitter.setHandleWidth(1) splitter.setOrientation(Qt.Vertical) splitter.setContentsMargins(0, 0, 0, 0) self.hooks_panel = HooksPanel(self.app) splitter.addWidget(self.hooks_panel) self.contexts_panel = ContextsPanel(self.app) splitter.addWidget(self.contexts_panel) self.backtrace_panel = BacktracePanel(self.app) splitter.addWidget(self.backtrace_panel) return splitter def build_central_content(self): main_panel = QSplitter(self) main_panel.setHandleWidth(1) main_panel.setOrientation(Qt.Vertical) main_panel.setContentsMargins(0, 0, 0, 0) self.registers_panel = RegistersPanel(self.app, 0, 4) main_panel.addWidget(self.registers_panel) self.memory_panel = MemoryPanel(self.app) main_panel.addWidget(self.memory_panel) self.log_panel = LogPanel(self.app) main_panel.addWidget(self.log_panel) main_panel.setStretchFactor(0, 1) main_panel.setStretchFactor(1, 3) main_panel.setStretchFactor(2, 1) return main_panel def on_script_loaded(self): self.add_main_tabs() def on_script_destroyed(self): for i in range(0, self.count()): if i > 0: self.removeTab(i) self.log_panel.clear() self.data_panel.clear() self.asm_panel.range = None self.hooks_panel.setRowCount(0) self.hooks_panel.resizeColumnsToContents() self.hooks_panel.horizontalHeader().setStretchLastSection(True) self.ranges_panel.setRowCount(0) self.ranges_panel.resizeColumnsToContents() self.ranges_panel.horizontalHeader().setStretchLastSection(True) self.modules_panel.setRowCount(0) self.modules_panel.resizeColumnsToContents() self.modules_panel.horizontalHeader().setStretchLastSection(True) self.contexts_panel.setRowCount(0) self.contexts_panel.resizeColumnsToContents() self.contexts_panel.horizontalHeader().setStretchLastSection(True) self.backtrace_panel.setRowCount(0) self.backtrace_panel.resizeColumnsToContents() self.backtrace_panel.horizontalHeader().setStretchLastSection(True) self.registers_panel.setRowCount(0) self.registers_panel.resizeColumnsToContents() self.registers_panel.horizontalHeader().setStretchLastSection(True) self.memory_panel.on_script_destroyed() def close_tab(self, index): self.removeTab(index) def add_dwarf_tab(self, tab_id, request_focus=False): if tab_id == SessionUi.TAB_DATA: self.addTab(self.data_panel, 'data') if request_focus: self.setCurrentWidget(self.hooks_panel) elif tab_id == SessionUi.TAB_MODULES: self.addTab(self.modules_panel, 'modules') if request_focus: self.setCurrentWidget(self.modules_panel) elif tab_id == SessionUi.TAB_RANGES: self.addTab(self.ranges_panel, 'ranges') if request_focus: self.setCurrentWidget(self.ranges_panel) elif tab_id == SessionUi.TAB_ASM: self.addTab(self.asm_panel, 'asm') if request_focus: self.setCurrentWidget(self.asm_panel) def add_search_tab(self, search_panel_widget, search_label): if len(search_label) > 5: search_label = search_label[:4] + '...' self.addTab(search_panel_widget, 'search - %s' % search_label) self.setCurrentWidget(search_panel_widget) def disasm(self, ptr=0, _range=None): self.add_dwarf_tab(SessionUi.TAB_ASM, True) if _range: self.asm_panel.disasm(_range=_range) else: self.asm_panel.read_memory(ptr) def request_session_ui_focus(self): self.setCurrentWidget(self.session_panel)
def setup(self): self.setupUi(self) loadAct = QAction('&Open', self) loadAct.setShortcut('Ctrl+O') loadAct.setStatusTip('Load data') loadAct.triggered.connect(lambda: self.onLoadClicked(0)) surfAct = QAction('&Open Surface', self) surfAct.setShortcut('Ctrl+S') surfAct.setStatusTip('Surf data') surfAct.triggered.connect(lambda: self.onLoadClicked(1)) exitAct = QAction('&Exit', self) exitAct.setShortcut('ALT+F4') exitAct.setStatusTip('Exit application') exitAct.triggered.connect(self.close) menubar = self.menuBar() fileMenu = menubar.addMenu('&File') fileMenu.addAction(loadAct) fileMenu.addAction(surfAct) fileMenu.addAction(exitAct) self.vtk_widgets = [ Viewer2D(self.vtk_panel, 0), Viewer2D(self.vtk_panel, 1), Viewer2D(self.vtk_panel, 2) ] # Make all views share the same cursor object for i in range(3): self.vtk_widgets[i].viewer.SetResliceCursor( self.vtk_widgets[0].viewer.GetResliceCursor()) # Cursor representation (anti-alias) for i in range(3): for j in range(3): prop = self.vtk_widgets[i].viewer.GetResliceCursorWidget( ).GetResliceCursorRepresentation().GetResliceCursorActor( ).GetCenterlineProperty(j) renderLinesAsTubes(prop) # Make 3D viewer picker = vtk.vtkCellPicker() picker.SetTolerance(0.005) ipwProp = vtk.vtkProperty() ren = vtk.vtkRenderer() interactor = QVTKRenderWindowInteractor() # Gradient background ren.SetBackground(245.0 / 255.0, 245.0 / 255.0, 245.0 / 255.0) ren.SetBackground2(170.0 / 255.0, 170.0 / 255.0, 170.0 / 255.0) ren.GradientBackgroundOn() interactor.GetRenderWindow().AddRenderer(ren) self.vtk_widgets.append(interactor) # Create plane widgets self.planeWidget = [] for i in range(3): pw = vtk.vtkImagePlaneWidget() pw.SetInteractor(interactor) pw.SetPicker(picker) pw.RestrictPlaneToVolumeOn() color = [0.0, 0.0, 0.0] color[i] = 1 pw.GetPlaneProperty().SetColor(color) pw.SetTexturePlaneProperty(ipwProp) pw.TextureInterpolateOn() pw.SetResliceInterpolateToLinear() pw.DisplayTextOn() pw.SetDefaultRenderer(ren) prop = pw.GetPlaneProperty() renderLinesAsTubes(prop) pw.SetPlaneProperty(prop) prop = pw.GetSelectedPlaneProperty() renderLinesAsTubes(prop) pw.SetSelectedPlaneProperty(prop) prop = pw.GetCursorProperty() renderLinesAsTubes(prop) pw.SetCursorProperty(prop) prop = pw.GetTextProperty() prop.SetColor(black) pw.Modified() # Set background for 2D views for j in range(3): color[j] = color[j] / 4.0 self.vtk_widgets[i].viewer.GetRenderer().SetBackground(color) self.vtk_widgets[i].interactor.Disable() self.planeWidget.append(pw) # Annotation cornerAnnotation = vtk.vtkCornerAnnotation() cornerAnnotation.SetLinearFontScaleFactor(2) cornerAnnotation.SetNonlinearFontScaleFactor(1) cornerAnnotation.SetMaximumFontSize(20) cornerAnnotation.SetText(vtk.vtkCornerAnnotation.UpperLeft, '3D') cornerAnnotation.GetTextProperty().SetColor(1, 1, 1) cornerAnnotation.SetWindowLevel( self.vtk_widgets[0].viewer.GetWindowLevel()) ren.AddViewProp(cornerAnnotation) self.establishCallbacks() # Show widgets but hide non-existing data for i in range(3): self.vtk_widgets[i].show() self.vtk_widgets[i].viewer.GetImageActor().SetVisibility(False) # Layouts horz_layout0 = QHBoxLayout() vert_splitter = QSplitter(Qt.Vertical) horz_splitter0 = QSplitter(Qt.Horizontal) horz_splitter0.addWidget(self.vtk_widgets[0]) horz_splitter0.addWidget(self.vtk_widgets[1]) vert_splitter.addWidget(horz_splitter0) horz_splitter1 = QSplitter(Qt.Horizontal) horz_splitter1.addWidget(self.vtk_widgets[2]) horz_splitter1.addWidget(self.vtk_widgets[3]) vert_splitter.addWidget(horz_splitter1) horz_layout0.addWidget(vert_splitter) horz_layout0.setContentsMargins(0, 0, 0, 0) self.vtk_panel.setLayout(horz_layout0) vert_layout = QVBoxLayout() # Sagittal/Coronal/Axial planes - not used horz_layout1 = QHBoxLayout() self.btnSagittal = QPushButton("S") self.btnSagittal.setCheckable(True) self.btnSagittal.setChecked(True) horz_layout1.addWidget(self.btnSagittal) self.btnCoronal = QPushButton("C") self.btnCoronal.setCheckable(True) self.btnCoronal.setChecked(True) horz_layout1.addWidget(self.btnCoronal) self.btnAxial = QPushButton("A") self.btnAxial.setCheckable(True) self.btnAxial.setChecked(True) horz_layout1.addWidget(self.btnAxial) self.btnSagittal.clicked.connect(self.togglePlanes) self.btnCoronal.clicked.connect(self.togglePlanes) self.btnAxial.clicked.connect(self.togglePlanes) verticalSpacer = QSpacerItem(10, 10, QSizePolicy.Minimum, QSizePolicy.Expanding) vert_layout.addSpacerItem(verticalSpacer) # Misalignment groupBox = QGroupBox("Misalignment") vert_layout.addWidget(groupBox) mis_layout = QVBoxLayout() # Local and reset horzSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Minimum) self.btnLocal = QCheckBox("local") self.btnReset = QPushButton("Reset") self.btnReset.clicked.connect(self.onResetOffset) # Misalignment buttons horz_layout4 = QHBoxLayout() horz_layout4.addWidget(self.btnLocal) horz_layout4.addSpacerItem(horzSpacer) horz_layout4.addWidget(self.btnReset) mis_layout.addItem(horz_layout4) # Misalignment sliders [(self.sliderTX, self.btnTransX), (self.sliderTY, self.btnTransY), (self.sliderTZ, self.btnTransZ), (self.sliderRX, self.btnRotX), (self.sliderRY, self.btnRotY), (self.sliderRZ, self.btnRotZ) ] = self.createMisAlignment(mis_layout, self.onOrientationClicked) groupBox.setLayout(mis_layout) # Movement groupBox = QGroupBox("Movement") vert_layout.addWidget(groupBox) groupLayout = QVBoxLayout() # Local and reset horzSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Minimum) # TODO: Return values self.btnMoveLocal = QCheckBox("local") self.btnReset1 = QPushButton("Reset") self.btnReset1.clicked.connect(self.onResetMovement) # Movement sliders layout = QHBoxLayout() layout.addWidget(self.btnMoveLocal) layout.addSpacerItem(horzSpacer) layout.addWidget(self.btnReset1) groupLayout.addItem(layout) [ (self.sliderMTX, self.sliderMTY, self.sliderMTZ), (self.sliderMRX, self.sliderMRY, self.sliderMRZ) ] = self.createMovement(groupLayout, self.onSliderPressed, self.onMove) groupBox.setLayout(groupLayout) self.frame.setLayout(vert_layout)
def initUi(self): layout = QGridLayout() horizontal_splitter = QSplitter(Qt.Horizontal) left_groupbox = QGroupBox('left group box') right_groupbox = QGroupBox('right group box') horizontal_splitter.addWidget(left_groupbox) horizontal_splitter.addWidget(right_groupbox) vertical_splitter_1 = QSplitter(Qt.Vertical) horizontal_layout_left = QHBoxLayout() left_groupbox_1 = QGroupBox('left top group box') left_groupbox_2 = QGroupBox('left bottom group box') vertical_splitter_1.addWidget(left_groupbox_1) vertical_splitter_1.addWidget(left_groupbox_2) horizontal_layout_left.addWidget(vertical_splitter_1) left_groupbox.setLayout(horizontal_layout_left) vertical_splitter_2 = QSplitter(Qt.Vertical) horizontal_layout_right = QHBoxLayout() right_groupbox_1 = QGroupBox('right top group box') right_groupbox_2 = QGroupBox('right bottom group box') vertical_splitter_2.addWidget(right_groupbox_1) vertical_splitter_2.addWidget(right_groupbox_2) horizontal_layout_right.addWidget(vertical_splitter_2) right_groupbox.setLayout(horizontal_layout_right) layout.addWidget(horizontal_splitter) self.setLayout(layout)
def __init__(self, app, *__args): super().__init__(*__args) self.app = app self.setTabsClosable(True) self.setMovable(True) self.tabCloseRequested.connect(self.removeTab) self.setContentsMargins(2, 2, 2, 2) self.setStyleSheet(""" QListWidget:hover, QTableWidget:hover { border: 1px solid transparent; } QTabWidget QFrame{ border: 0; } QTabWidget::pane { border: 0px solid transparent; border-radius: 0px; padding: 0px; margin: 0px; } QTabWidget::pane:selected { background-color: transparent; border: 0px solid transparent; } QWidget { padding: 0; margin-top: 2px; margin-right: 2px; margin-left: 1px; } """) self.session_panel = QSplitter() self.modules_panel = None self.ranges_panel = None self.registers_panel = None self.memory_panel = None self.log_panel = None self.backtrace_panel = None self.hooks_panel = None self.contexts_panel = None self.data_panel = DataPanel(self.app) self.asm_panel = AsmPanel(self.app) self.session_panel.addWidget(self.build_left_column()) self.session_panel.addWidget(self.build_central_content()) self.session_panel.setHandleWidth(1) self.session_panel.setStretchFactor(0, 2) self.session_panel.setStretchFactor(1, 6) self.session_panel.setContentsMargins(0, 0, 0, 0) self.modules_panel = ModulesPanel(self.app) self.ranges_panel = RangesPanel(self.app) self.addTab(self.session_panel, 'session') bt = self.tabBar().tabButton(0, QTabBar.LeftSide) if not bt: bt = self.tabBar().tabButton(0, QTabBar.RightSide) if bt: bt.resize(0, 0)
class Window(QStackedWidget): """ Defines the look and characteristics of the application's main window. """ title = "Mu" icon = "icon" _zoom_in = pyqtSignal(int) _zoom_out = pyqtSignal(int) def set_clipboard(self, clipboard): self.clipboard = clipboard def zoom_in(self): """ Handles zooming in. """ self._zoom_in.emit(2) def zoom_out(self): """ Handles zooming out. """ self._zoom_out.emit(2) def connect_zoom(self, widget): """ Connects a referenced widget to the zoom related signals. """ self._zoom_in.connect(widget.zoomIn) self._zoom_out.connect(widget.zoomOut) @property def current_tab(self): """ Returns the currently focussed tab. """ return self.tabs.currentWidget() def get_load_path(self, folder): """ Displays a dialog for selecting a file to load. Returns the selected path. Defaults to start in the referenced folder. """ path, _ = QFileDialog.getOpenFileName(self.widget, 'Open file', folder, '*.py *.hex') logger.debug('Getting load path: {}'.format(path)) return path def get_save_path(self, folder): """ Displays a dialog for selecting a file to save. Returns the selected path. Defaults to start in the referenced folder. """ path, _ = QFileDialog.getSaveFileName(self.widget, 'Save file', folder) logger.debug('Getting save path: {}'.format(path)) return path def get_microbit_path(self, folder): """ Displays a dialog for locating the location of the BBC micro:bit in the host computer's filesystem. Returns the selected path. Defaults to start in the referenced folder. """ path = QFileDialog.getExistingDirectory(self.widget, 'Locate BBC micro:bit', folder, QFileDialog.ShowDirsOnly) logger.debug('Getting micro:bit path: {}'.format(path)) return path def add_tab(self, path, text): """ Adds a tab with the referenced path and text to the editor. """ new_tab = EditorPane(path, text, self.api) new_tab_index = self.tabs.addTab(new_tab, new_tab.label) @new_tab.modificationChanged.connect def on_modified(): self.tabs.setTabText(new_tab_index, new_tab.label) self.tabs.setCurrentIndex(new_tab_index) self.connect_zoom(new_tab) self.set_theme(self.theme) new_tab.setFocus() @property def tab_count(self): """ Returns the number of active tabs. """ return self.tabs.count() @property def widgets(self): """ Returns a list of references to the widgets representing tabs in the editor. """ return [self.tabs.widget(i) for i in range(self.tab_count)] @property def modified(self): """ Returns a boolean indication if there are any modified tabs in the editor. """ for widget in self.widgets: if widget.isModified(): return True return False def add_filesystem(self, home): """ Adds the file system pane to the application. """ self.fs = FileSystemPane(self.splitter, home) self.splitter.addWidget(self.fs) self.splitter.setSizes([66, 33]) self.fs.setFocus() self.connect_zoom(self.fs) def add_repl(self, repl): """ Adds the REPL pane to the application. """ self.repl = REPLPane(port=repl.port, clipboard=self.clipboard, theme=self.theme) self.splitter.addWidget(self.repl) self.splitter.setSizes([66, 33]) self.repl.setFocus() self.connect_zoom(self.repl) def remove_filesystem(self): """ Removes the file system pane from the application. """ self.fs.setParent(None) self.fs.deleteLater() self.fs = None def remove_repl(self): """ Removes the REPL pane from the application. """ self.repl.setParent(None) self.repl.deleteLater() self.repl = None def set_theme(self, theme): """ Sets the theme for the REPL and editor tabs. """ self.setStyleSheet(DAY_STYLE) self.theme = theme new_theme = DayTheme new_icon = 'theme' if theme == 'night': new_theme = NightTheme new_icon = 'theme_day' self.setStyleSheet(NIGHT_STYLE) for widget in self.widgets: widget.set_theme(new_theme) self.button_bar.slots['theme'].setIcon(load_icon(new_icon)) if hasattr(self, 'repl') and self.repl: self.repl.set_theme(theme) def show_message(self, message, information=None, icon=None, parent=None): """ Displays a modal message to the user. If information is passed in this will be set as the additional informative text in the modal dialog. Since this mechanism will be used mainly for warning users that something is awry the default icon is set to "Warning". It's possible to override the icon to one of the following settings: NoIcon, Question, Information, Warning or Critical. """ message_box = QMessageBox(parent) message_box.setText(message) message_box.setWindowTitle('Mu') if information: message_box.setInformativeText(information) if icon and hasattr(message_box, icon): message_box.setIcon(getattr(message_box, icon)) else: message_box.setIcon(message_box.Warning) logger.debug(message) logger.debug(information) message_box.exec() def show_confirmation(self, message, information=None, icon=None, parent=None): """ Displays a modal message to the user to which they need to confirm or cancel. If information is passed in this will be set as the additional informative text in the modal dialog. Since this mechanism will be used mainly for warning users that something is awry the default icon is set to "Warning". It's possible to override the icon to one of the following settings: NoIcon, Question, Information, Warning or Critical. """ message_box = QMessageBox(parent) message_box.setText(message) message_box.setWindowTitle('Mu') if information: message_box.setInformativeText(information) if icon and hasattr(message_box, icon): message_box.setIcon(getattr(message_box, icon)) else: message_box.setIcon(message_box.Warning) message_box.setStandardButtons(message_box.Cancel | message_box.Ok) message_box.setDefaultButton(message_box.Cancel) logger.debug(message) logger.debug(information) return message_box.exec() def update_title(self, filename=None): """ Updates the title bar of the application. If a filename (representing the name of the file currently the focus of the editor) is supplied, append it to the end of the title. """ title = self.title if filename: title += ' - ' + filename self.setWindowTitle(title) def autosize_window(self): """ Makes the editor 80% of the width*height of the screen and centres it. """ screen = QDesktopWidget().screenGeometry() w = int(screen.width() * 0.8) h = int(screen.height() * 0.8) self.resize(w, h) size = self.geometry() self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2) def reset_annotations(self): """ Resets the state of annotations on the current tab. """ self.current_tab.reset_annotations() def annotate_code(self, feedback): """ Given a list of annotations about the code in the current tab, add the annotations to the editor window so the user can make appropriate changes. """ self.current_tab.annotate_code(feedback) def setup(self, theme, api=None): """ Sets up the window. Defines the various attributes of the window and defines how the user interface is laid out. """ self.theme = theme self.api = api if api else [] # Give the window a default icon, title and minimum size. self.setWindowIcon(load_icon(self.icon)) self.update_title() self.setMinimumSize(926, 600) self.widget = QWidget() self.splitter = QSplitter(Qt.Vertical) widget_layout = QVBoxLayout() self.widget.setLayout(widget_layout) self.button_bar = ButtonBar(self.widget) widget_layout.addWidget(self.button_bar) widget_layout.addWidget(self.splitter) self.tabs = FileTabs() self.splitter.addWidget(self.tabs) self.addWidget(self.widget) self.setCurrentWidget(self.widget) self.set_theme(theme) self.show() self.autosize_window()
class MainWidget(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): #init Text edit self.textEdit = TextEdit(self) self.textEdit.textChanged.connect(self.textChanged) self.bTextChanged = False self.bTextSaved = True self.bCursorPosChanged = False #init Tool bar self.toolBar = ToolBar(self) initToolBar(self) #init textSplitter self.textSplitter = QSplitter(Qt.Horizontal, self) self.textSplitter.addWidget(self.textEdit) #init textBrowser self.bShowPW = False self.textBrowser = None #init timer self.timer = None #init layout self.centerVBox = QVBoxLayout() self.centerVBox.addWidget(self.textSplitter) self.centerVBox.addWidget(self.toolBar) self.centerVBox.setSpacing(0) self.centerVBox.setContentsMargins(0, 0, 0, 0) self.setLayout(self.centerVBox) #init tile self.updateWindowTitle() #init position screen = QDesktopWidget().screenGeometry() self.setGeometry(screen.width() / 4, screen.height() / 6, screen.width() / 2, screen.height() * 2 / 3) self.show() # Text Edit def textChanged(self): if self.bTextChanged == False: self.bTextChanged = True if self.bTextSaved == True: self.bTextSaved = False def resetTextChangedFlag(self): self.bTextChanged = False def isTextChanged(self): return self.bTextChanged def resetTextSavedFlag(self): self.bTextSaved = True def isTextSaved(self): return self.bTextSaved def cursorPosChanged(self): if self.bCursorPosChanged == False: self.bCursorPosChanged = True def resetCursorPosChangedFlag(self): self.bCursorPosChanged = False def isCursorPosChanged(self): return self.bCursorPosChanged def getPlainText(self): return self.textEdit.toPlainText() def setPlainText(self, data): self.textEdit.setPlainText(data) # Text Browser def togglePreviewWindow(self): self.setUpdatesEnabled(False) if self.bShowPW: self.hideTextBrowser() else: self.showTextBrowser() self.setUpdatesEnabled(True) self.update() def showTextBrowser(self): self.bShowPW = True if self.textBrowser == None: self.textBrowser = TextBrowser(self) #create the timer for flush textBrowser self.createTimerForRefreshTextBrowser() #text splitter add textbrowser self.textSplitter.addWidget(self.textBrowser) #sync the position of textedit to textbrowser self.textEdit.cursorPositionChanged.connect(self.cursorPosChanged) self.textBrowser.show() def hideTextBrowser(self): self.bShowPW = False self.timer.stop() self.textBrowser.hide() def createTimerForRefreshTextBrowser(self): if self.timer == None: self.timer = QTimer(self) self.timer.setSingleShot(False) self.timer.timeout.connect(self.fleshTextBrowser) self.timer.start(TimerInterval) else: self.timer.start() def fleshTextBrowser(self): if self.isTextChanged(): self.setUpdatesEnabled(False) data = self.textEdit.toPlainText() self.textBrowser.setText(data) self.resetTextChangedFlag() #Avoid resync the textbrowser when user is inputting if self.isCursorPosChanged(): self.syncTextBrowserPosition() self.resetCursorPosChangedFlag() self.setUpdatesEnabled(True) elif self.isCursorPosChanged(): self.syncTextBrowserPosition() self.resetCursorPosChangedFlag() def syncTextBrowserPosition(self): browserSB = self.textBrowser.verticalScrollBar() maximum2 = browserSB.maximum() if maximum2 == 0: #without scrollbar return minimum2 = browserSB.minimum() pageStep2 = browserSB.pageStep() #scrollbar area textSB = self.textEdit.verticalScrollBar() maximum = textSB.maximum() destPos = 0 if maximum == 0: pos = self.textEdit.textCursor().position() length = len(self.textEdit.toPlainText()) if length == 0: return destPos = int((maximum2 - minimum2 + pageStep2) * float(pos / length) + minimum2 - float(pageStep2 / 2)) else: curSBPos = textSB.value() minimum = textSB.minimum() pageStep = textSB.pageStep() #cursor position cursorRect = self.textEdit.cursorRect() yPos = cursorRect.center().y() #viewport's height vpHeight = self.textEdit.viewport().height() destPos = int((maximum2 - minimum2 + pageStep2) * ( (curSBPos + pageStep * float(yPos / vpHeight) - minimum2) / (maximum - minimum + pageStep)) + minimum2 - float(pageStep2 / 2)) #Ajust the result if destPos < minimum2: destPos = minimum2 elif destPos > maximum2: destPos = maximum2 browserSB.setValue(destPos) # main widget def updateWindowTitle(self): curFileName = getCurrentFileName() if curFileName != STR_NULL: self.setWindowTitle(curFileName) else: self.setWindowTitle(SoftWareName) def closeEvent(self, event): saveCurrentFile() event.accept()
class ControllerWidget(QWidget): """ Used to merge spectrum, table, TIC, error plot and sequenceIons widgets together. """ def __init__(self, *args, **kwargs): QWidget.__init__(self, *args, **kwargs) self.mainlayout = QHBoxLayout(self) self.isAnnoOn = True self.clickedRT = None self.seleTableRT = None self.mzs = np.array([]) self.ppm = np.array([]) self.colors = np.array([]) self.scanIDDict = {} self.curr_table_index = None self.filteredIonFragments = [] self.peakAnnoData = None def clearLayout(self, layout): for i in reversed(range(layout.count())): layout.itemAt(i).widget().setParent(None) def loadFileMzML(self, file_path): self.isAnnoOn = False self.msexperimentWidget = QSplitter(Qt.Vertical) # data processing scans = self.readMS(file_path) # set Widgets self.spectrum_widget = SpectrumWidget() self.scan_widget = ScanTableWidget(scans) self.seqIons_widget = SequenceIonsWidget() self.error_widget = ErrorWidget() self.tic_widget = TICWidget() self.drawTic(scans) # connected signals self.scan_widget.sigScanClicked.connect(self.updateWidgetDataFromRow) self.tic_widget.sigRTClicked.connect(self.ticToTable) self.msexperimentWidget.addWidget(self.tic_widget) self.msexperimentWidget.addWidget(self.seqIons_widget) self.msexperimentWidget.addWidget(self.spectrum_widget) self.msexperimentWidget.addWidget(self.error_widget) self.msexperimentWidget.addWidget(self.scan_widget) self.mainlayout.addWidget(self.msexperimentWidget) # set widget sizes, where error plot is set smaller widget_height = self.msexperimentWidget.sizeHint().height() size_list = [ widget_height, widget_height, widget_height, widget_height * 0.5, widget_height ] self.msexperimentWidget.setSizes(size_list) # default : first row selected. self.scan_widget.table_view.selectRow(0) def loadFileIdXML(self, file_path): prot_ids = [] pep_ids = [] pyopenms.IdXMLFile().load(file_path, prot_ids, pep_ids) Ions = {} # extract ID data from file for peptide_id in pep_ids: pep_mz = peptide_id.getMZ() pep_rt = peptide_id.getRT() for hit in peptide_id.getHits(): pep_seq = str(hit.getSequence().toString()) if "." in pep_seq: pep_seq = pep_seq[3:-1] else: pep_seq = pep_seq[2:-1] for anno in hit.getPeakAnnotations(): ion_charge = anno.charge ion_mz = anno.mz ion_label = anno.annotation Ions[ion_label] = [ion_mz, ion_charge] self.scanIDDict[round(pep_rt, 3)] = { "m/z": pep_mz, "PepSeq": pep_seq, "PepIons": Ions, } Ions = {} self.saveIdData() def saveIdData(self): # save ID data in table (correct rows) for later usage rows = self.scan_widget.table_model.rowCount(self.scan_widget) for row in range(0, rows - 1): tableRT = round( self.scan_widget.table_model.index(row, 2).data(), 3) if tableRT in self.scanIDDict: index_seq = self.scan_widget.table_model.index(row, 6) self.scan_widget.table_model.setData( index_seq, self.scanIDDict[tableRT]["PepSeq"], Qt.DisplayRole) index_ions = self.scan_widget.table_model.index(row, 7) # data needs to be a string, but reversible -> # using json.dumps() self.scan_widget.table_model.setData( index_ions, json.dumps(self.scanIDDict[tableRT]["PepIons"]), Qt.DisplayRole, ) def readMS(self, file_path): # read MzML files exp = pyopenms.MSExperiment() pyopenms.MzMLFile().load(file_path, exp) return exp def drawTic(self, scans): self.tic_widget.setTIC(scans.getTIC()) def ticToTable(self, rt): # connect Tic info to table, and select specific row self.clickedRT = round(rt * 60, 3) if self.clickedRT != self.seleTableRT: self.scan_widget.table_view.selectRow(self.findClickedRT()) def findClickedRT(self): # find clicked RT in the scan table rows = self.scan_widget.table_model.rowCount(self.scan_widget) for row in range(0, rows - 1): if self.clickedRT == round( self.scan_widget.table_model.index(row, 2).data(), 3): index = self.scan_widget.table_model.index(row, 2) try: self.curr_table_index \ = self.scan_widget.proxy.mapFromSource(index) # use proxy to get from filtered model index return self.curr_table_index.row() except ValueError: print("could not found ModelIndex of row") # for the future calculate ppm and add it to the table def errorData(self, ions_data): if ions_data not in "-": ions_data_dict = json.loads(ions_data) if ions_data_dict != {}: self.colors, self.mzs = self.filterColorsMZIons(ions_data_dict) mzs_size = len(self.mzs) self.ppm = np.random.randint(0, 3, size=mzs_size) self.error_widget.setMassErrors( self.mzs, self.ppm, self.colors) # works for a static np.array else: self.error_widget.clear() else: self.error_widget.clear() def filterColorsMZIons( self, ions_data_dict ): # create color/mz array by distinguishing between prefix & suffix ions self.peakAnnoData = ({}) # key is ion annotation (e.g. b2): # [mz, color distinguishing prefix, suffix] colors = [] mzs = [] col_red = (255, 0, 0) # suffix col_blue = (0, 0, 255) # prefix for fragData in self.filteredIonFragments: anno = fragData[0] if anno[0] in "abc": colors.append(col_blue) mzs.append(ions_data_dict[anno][0]) self.peakAnnoData[fragData[1]] = [ ions_data_dict[anno][0], col_blue ] elif anno[0] in "xyz": colors.append(col_red) mzs.append(ions_data_dict[anno][0]) self.peakAnnoData[fragData[1]] = [ ions_data_dict[anno][0], col_red ] return np.array(colors), np.array(mzs) def updateWidgetDataFromRow( self, index ): # after clicking on a new row, update spectrum, error plot, peptideSeq # current row RT value self.seleTableRT = round(index.siblingAtColumn(2).data(), 3) # set new spectrum with setting that all peaks should be displayed self.spectrum_widget.setSpectrum(self.scan_widget.curr_spec, zoomToFullRange=True) # only draw sequence with given ions for MS2 and error plot if index.siblingAtColumn(0).data() == "MS2": self.drawSeqIons( index.siblingAtColumn(6).data(), index.siblingAtColumn(7).data()) self.errorData(index.siblingAtColumn(7).data()) if (self.peakAnnoData is not None ): # peakAnnoData created with existing ions in errorData # (bc of coloring) self.spectrum_widget.setPeakAnnotations( self.createPeakAnnotation()) self.spectrum_widget.redrawPlot() else: self.spectrum_widget._clear_peak_annotations() self.spectrum_widget.redrawPlot() # otherwise delete old data elif index.siblingAtColumn(0).data() == "MS1": self.seqIons_widget.clear() self.error_widget.clear() self.peakAnnoData = None self.spectrum_widget._clear_peak_annotations() self.spectrum_widget.redrawPlot() def createPeakAnnotation(self): pStructList = [] # for the future -> # check clashes like in the TIC widget and then add labels # (should be done in SpectrumWidget) for anno, data in self.peakAnnoData.items(): mz, anno_color = data[0], data[1] index = self.find_nearest_Index(self.spectrum_widget._mzs, mz) pStructList.append( PeakAnnoStruct( mz=self.spectrum_widget._mzs[index], intensity=self.spectrum_widget._ints[index], text_label=anno, symbol=None, symbol_color=anno_color, )) return pStructList def find_nearest_Index(self, array, value): array = np.asarray(array) idx = (np.abs(array - value)).argmin() return idx def drawSeqIons(self, seq, ions): # generate provided peptide sequence seq = re.sub(r"\([^)]*\)", "", seq) # remove content in brackets -> easier usage # only draw sequence for M2 with peptide and ion data if seq not in "-" and ions not in "-": self.seqIons_widget.setPeptide(seq) # transform string data back to a dict ions_dict = json.loads(ions) if ions_dict != {}: self.suffix, self.prefix = self.filterIonsPrefixSuffixData( ions_dict) self.seqIons_widget.setPrefix(self.prefix) self.seqIons_widget.setSuffix(self.suffix) else: # no ions data self.prefix, self.suffix = {}, {} self.seqIons_widget.setPrefix(self.prefix) self.seqIons_widget.setSuffix(self.suffix) self.peakAnnoData = None else: self.seqIons_widget.clear() self.peakAnnoData = None def filterIonsPrefixSuffixData( self, ions): # filter raw ion data and return suffix and prefix dicts suffix = {} prefix = {} ions_anno = list(ions.keys()) # annotation(s) of raw ion data (used as key(s)) self.filteredIonFragments = [] for anno in ions_anno: if anno[1].isdigit() and anno[0] in "abcyxz": index, anno_short = self.filterAnnotationIon(anno) if ((index in suffix) and (anno[0] in "yxz") and (anno_short not in suffix[index])): # avoid double annos e.g. y14 suffix[index].append(anno_short) elif ((index in prefix) and (anno[0] in "abc") and (anno_short not in prefix[index])): prefix[index].append(anno_short) elif anno[0] in "yxz": # non existing keys suffix[index] = [anno_short] elif anno[0] in "abc": # non existing keys prefix[index] = [anno_short] return suffix, prefix def filterAnnotationIon(self, fragment_anno): # filter from raw ion data annotation index # and filtered annotation name (e.g. y2) index = [s for s in re.findall(r"-?\d+\.?\d*", fragment_anno)][0] ion_anno = fragment_anno.split(index)[0] + index self.filteredIonFragments.append((fragment_anno, ion_anno)) return int(index), ion_anno
def initUI(self): hbox = QHBoxLayout() # 프레임 설 : 위, 아래 통으로 하나 // 가운데는 왼쪽, 오른쪽 나누어짐 # 상단에 배치할 프레임 top = QFrame() top.setFrameShape(QFrame.Box) # 가운데 왼쪽에 배치할 프레임 midleft = QFrame() midleft.setFrameShape(QFrame.StyledPanel) # 가운데 오른쪽에 배치할 프레임 midright = QFrame() midright.setFrameShape(QFrame.Panel) # 아래에 배치할 프레임 bottom = QFrame() bottom.setFrameShape(QFrame.WinPanel) bottom.setFrameShadow(QFrame.Sunken) # 쪼개지는 방향 정함 splitter1 = QSplitter(Qt.Horizontal) # 가로로 쪼개기! splitter1.addWidget(midleft) splitter1.addWidget(midright) splitter2 = QSplitter(Qt.Vertical) splitter2.addWidget(top) splitter2.addWidget(splitter1) splitter2.addWidget(bottom) hbox.addWidget(splitter2) self.setLayout(hbox) self.setGeometry(300, 300, 300, 200) self.setWindowTitle('QSplitter') self.show()
class EmailViewerPageView(QWidget): def __init__(self, parent=None): super().__init__(parent) self.c = EmailViewerPageController() self.c.on_viewemail.connect(self.update_content) self.c.on_clearview.connect(self.clear_content) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.splitter = QSplitter() self._web_engine = QWebEngineView(self) self._web_engine.setMinimumWidth(330) self._web_engine.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Expanding) self.email_page = self._web_engine.page() self.splitter.addWidget(self._web_engine) attachment_model = AttachmentListModel() self.attachments = AttachmentsView(self) self.attachments.setMaximumWidth(300) self.attachments.set_model(attachment_model) self._attachments_collapsed = False self.splitter.addWidget(self.attachments) layout.addWidget(self.splitter) self.setLayout(layout) def resizeEvent(self, event): super().resizeEvent(event) # TODO: Fix the splitter not resizing when _web_engine gets smaller than minimumSize. # Inspect sizes() for that, check if _web_engines size is less than minimumSize and # somehow update the splitter's handle, it just has to be touched in order for it to resize # to the proper size. # !!! NOTE: First call to sizes returns [0, 0]. page_size, attachments_size = self.splitter.sizes() if page_size == 0 and attachments_size == 0: return elif page_size < self._web_engine.minimumWidth( ) and not self._attachments_collapsed: self.splitter.setSizes((self.splitter.width(), 0)) self._attachments_collapsed = True elif self._attachments_collapsed: splitter_width = self.splitter.width() size1 = self._web_engine.minimumWidth() size2 = self.attachments.sizeHint().width() if splitter_width > size1 + size2: self.splitter.setSizes((splitter_width - size2, size2)) self._attachments_collapsed = False def update_content(self, body, attachments, error=None): if error: err_dialog = ErrorReportDialog(error) err_dialog.exec_() return self.attachments.clear_attachments() self.email_page.runJavaScript( f'document.open(); document.write(""); document.write(`{body}`); document.close();' ) self.attachments.append_attachments(attachments) def clear_content(self, flag): self.attachments.clear_attachments() self.email_page.runJavaScript( 'document.open(); document.write(""); document.close();')