def init_tray(self): """ Initializes the systray menu """ traymenu = QMenu("Menu") self.tray.setContextMenu(traymenu) self.tray.show() self.tray.activated.connect(self.tray_click) self.tray.setToolTip("Pomodori: "+str(self.pom.pomodori)) set_timer_tray = QLineEdit() set_timer_tray.setPlaceholderText("Set timer") set_timer_tray.textChanged.connect(lambda: self.update_timer_text(set_timer_tray.text())) traywidget = QWidgetAction(set_timer_tray) traywidget.setDefaultWidget(set_timer_tray) traymenu.addAction(traywidget) start_timer_action = QAction("&Start Timer", self) start_timer_action.triggered.connect(self.start_timer_click) traymenu.addAction(start_timer_action) exit_action = QAction("&Exit", self) exit_action.triggered.connect(QCoreApplication.instance().quit) traymenu.addAction(exit_action)
def initUI(self): self.setPopupMode(QToolButton.MenuButtonPopup) self.menu = QMenu(self) self.setMenu(self.menu) self.setFixedSize(*self.BUTTON_SIZE) self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.listWidget = self.createListWidget() self.listWidget.installEventFilter(self) action = QWidgetAction(self) action.setDefaultWidget(self.listWidget) self.menu.addAction(action) self.updateIcon()
def TitledMenu(titles, padding=5, with_separator=True): """ :param title: the title for menu :param padding: the padding defaults to 5 px :param with_separator: if true adds a separator :return: the QMenu with a title """ menu = QMenu() for title in titles: label = QLabel(title) label.setStyleSheet("padding: {}px; background-color: rgba(0, 0, 0, 0);".format(padding)) title_widget = QWidgetAction(menu) title_widget.setDefaultWidget(label) menu.addAction(title_widget) if with_separator: menu.addSeparator() return menu
def setup_context_menu(self): """ :return: """ self.custMenu = QMenu("Options") self.gridMenu = QMenu('Grid') # Grid Menu: # ----------------------------------------------------------- # Y-Grid checkbox self.xGrid_Checkbox = QCheckBox() self.xGrid_Checkbox.stateChanged.connect(self.contextMenu_xGrid_toogle) self.xGrid_Checkbox.setText('X-Grid') self.xGrid_Action = QWidgetAction(self.__plotWidget__) self.xGrid_Action.setDefaultWidget(self.xGrid_Checkbox) self.gridMenu.addAction(self.xGrid_Action) # Check config for startup state if self.__show_grid_x__: self.xGrid_Checkbox.setChecked(True) # X-Grid checkbox self.yGrid_Checkbox = QCheckBox() self.yGrid_Checkbox.stateChanged.connect(self.contextMenu_yGrid_toogle) self.yGrid_Checkbox.setText('Y-Grid') self.yGrid_Action = QWidgetAction(self.__plotWidget__) self.yGrid_Action.setDefaultWidget(self.yGrid_Checkbox) self.gridMenu.addAction(self.yGrid_Action) # Check config for startup state if self.__show_grid_y__: self.yGrid_Checkbox.setChecked(True) # add Menus self.custMenu.addMenu(self.gridMenu) self.__plotWidget__.getPlotItem().getViewBox().menu.clear() self.__plotWidget__.getPlotItem().ctrlMenu = [self.pl_create_control_context_menu(), self.custMenu]
def createCheckBoxes(self): #Create checkbox data_unique = [] self.table=QTableWidget() self.table.setColumnCount(1) self.table.verticalHeader().hide() self.table.horizontalHeader().hide() self.table.horizontalHeader().setStretchLastSection(True) self.table.setRowCount(self.rowCount()) #Assign the action a create the list of checkbox self.checkBoxs = [] checkBox = QCheckBox("Seleccionar todo", self.menu) checkableAction = QWidgetAction(self.menu) checkableAction.setDefaultWidget(checkBox) self.menu.addAction(checkableAction) checkBox.setChecked(Qt.Checked) checkBox.stateChanged.connect(self.slotSelect) j=0 for i in range(self.rowCount()): if not self.isRowHidden(i): item = self.item(i, self.col ) if item.text() not in data_unique: data_unique.append(item.text()) it = QTableWidgetItem(item.text()) it.setFlags(Qt.ItemIsUserCheckable |Qt.ItemIsEnabled) it.setCheckState(Qt.Checked) self.checkBoxs.append(it) j=j+1 #Sort the element of the list self.checkBoxs=sorted(self.checkBoxs, key=lambda it: it.text()) # self.sort(self.checkBoxs[i]) j=0 for i in range(len(self.checkBoxs)): #print(self.checkBoxs[i].text()) self.table.setItem(j,0, self.checkBoxs[i]) j=j+1 self.table.update() self.table.setRowCount(len(self.checkBoxs)) checkableAction = QWidgetAction(self.menu) checkableAction.setDefaultWidget(self.table) self.menu.addAction(checkableAction)
def create_widget_action(self, icon, text, data=None): act = QWidgetAction(self) act.setText(text) if data is not None: act.setData(data) widget = QWidget(self) layout = QHBoxLayout() layout.setContentsMargins(13, -1, -1, 11) layout.setSpacing(13) lb_icon = QLabel(widget) lb_icon.resize(18, 18) lb_text = QLabel(text, widget) if icon != "": lb_icon.setPixmap(QPixmap(icon)) widget.setStyleSheet("QWidget:hover{background:#ededef}") layout.addWidget(lb_icon) layout.addWidget(lb_text) layout.addStretch() widget.setLayout(layout) act.setDefaultWidget(widget) return act
def context_menu(self): menu = QMenu() font_box = QFontComboBox() font_box.setCurrentFont(self.post_text_font) font_box.currentFontChanged.connect( lambda: self.set_post_text_font(font=font_box.currentFont())) font_box.currentFontChanged.connect(menu.close) font_box_label = QLabel('Font:') layout = QHBoxLayout() layout.addWidget(font_box_label) layout.addWidget(font_box) font_box_widget = QWidget(self) font_box_widget.setLayout(layout) font_box_item = QWidgetAction(self) font_box_item.setDefaultWidget(font_box_widget) font_size_box = QComboBox() font_size_box.addItems(str(x) for x in range(4, 30)) font_size_box.setCurrentText(str(self.post_text_font_size)) font_size_label = QLabel('Font Size:') size_layout = QHBoxLayout() size_layout.addWidget(font_size_label) size_layout.addWidget(font_size_box) font_size_widget = QWidget(self) font_size_widget.setLayout(size_layout) font_size_box.currentIndexChanged.connect( lambda: self.set_post_text_font(size=int(font_size_box.currentText( )))) font_size_box.currentIndexChanged.connect(menu.close) font_size_item = QWidgetAction(self) font_size_item.setDefaultWidget(font_size_widget) menu.addAction(font_box_item) menu.addAction(font_size_item) menu.addSeparator() if not self.stand_alone: menu.addAction('Detach Text Box', lambda: self.detach_signal.emit()) menu.exec_(QCursor.pos())
def on_view_horizontalHeader_sectionClicked(self, index): self.menu = QMenu(self) self.col = index self.createCheckBoxes() #Accept and cancel button btn = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self.menu) btn.accepted.connect(self.menuClose) btn.rejected.connect(self.menu.close) checkableAction = QWidgetAction(self.menu) checkableAction.setDefaultWidget(btn) self.menu.addAction(checkableAction) ##Clear Button btnClr = QPushButton(QIcon(),"Limpiar Filtro", self.menu) btnClr.clicked.connect(self.clearFilter) checkableAction = QWidgetAction(self.menu) checkableAction.setDefaultWidget(btnClr) self.menu.addAction(checkableAction) headerPos = self.mapToGlobal(self.horizontalHeader().pos()) posY = headerPos.y() + self.horizontalHeader().height() posX = headerPos.x() + self.horizontalHeader().sectionPosition(index) self.menu.exec_(QPoint(posX, posY))
def __init__(self): super().__init__() arguments = self.parseArguments() self.DEBUG = arguments.debug os.chdir(os.path.dirname(os.path.realpath(__file__))) self.MIN_WIDTH = 600 self.MIN_HEIGHT = 350 self.setMinimumWidth(self.MIN_WIDTH) self.setMinimumHeight(self.MIN_HEIGHT) self.ROOT_FOLDER = os.path.expanduser("~/.florodoro/") self.HISTORY_FILE_PATH = self.ROOT_FOLDER + "history" + ("" if not self.DEBUG else "-debug") + ".yaml" self.CONFIGURATION_FILE_PATH = self.ROOT_FOLDER + "config" + ("" if not self.DEBUG else "-debug") + ".yaml" self.history = History(self.HISTORY_FILE_PATH) self.SOUNDS_FOLDER = "sounds/" self.PLANTS_FOLDER = "plants/" self.IMAGE_FOLDER = "images/" self.TEXT_COLOR = self.palette().text().color() self.BREAK_COLOR = "#B37700" self.APP_NAME = "Florodoro" self.STUDY_ICON = qtawesome.icon('fa5s.book', color=self.TEXT_COLOR) self.BREAK_ICON = qtawesome.icon('fa5s.coffee', color=self.BREAK_COLOR) self.CONTINUE_ICON = qtawesome.icon('fa5s.play', color=self.TEXT_COLOR) self.PAUSE_ICON = qtawesome.icon('fa5s.pause', color=self.TEXT_COLOR) self.RESET_ICON = qtawesome.icon('fa5s.undo', color=self.TEXT_COLOR) self.PLANTS = [GreenTree, DoubleGreenTree, OrangeTree, CircularFlower] self.PLANT_NAMES = ["Spruce", "Double spruce", "Maple", "Flower"] self.MAX_PLANT_AGE = 90 # maximum number of minutes to make the plant optimal in size self.WIDGET_SPACING = 10 self.MAX_TIME = 180 self.STEP = 5 self.INITIAL_TEXT = "Start!" self.menuBar = QMenuBar(self) self.presets_menu = self.menuBar.addMenu('&Presets') self.presets = { "Classic": (25, 5, 4), "Extended": (45, 12, 2), "Sitcomodoro": (65, 25, 1), } for name in self.presets: study_time, break_time, cycles = self.presets[name] self.presets_menu.addAction( QAction(f"{name} ({study_time} : {break_time} : {cycles})", self, triggered=partial(self.load_preset, study_time, break_time, cycles))) self.DEFAULT_PRESET = "Classic" self.options_menu = self.menuBar.addMenu('&Options') self.notify_menu = self.options_menu.addMenu("&Notify") self.sound_action = QAction("&Sound", self, checkable=True, checked=not self.DEBUG, triggered=lambda _: self.volume_slider.setDisabled( not self.sound_action.isChecked())) self.notify_menu.addAction(self.sound_action) self.volume_slider = QSlider(Qt.Horizontal, minimum=0, maximum=100, value=85) slider_action = QWidgetAction(self) slider_action.setDefaultWidget(SpacedQWidget(self.volume_slider)) self.notify_menu.addAction(slider_action) self.popup_action = QAction("&Pop-up", self, checkable=True, checked=True) self.notify_menu.addAction(self.popup_action) self.menuBar.addAction( QAction( "&Statistics", self, triggered=lambda: self.statistics.show() if self.statistics.isHidden() else self.statistics.hide() ) ) self.menuBar.addAction( QAction( "&About", self, triggered=lambda: QMessageBox.information( self, "About", "This application was created by Tomáš Sláma. It is heavily inspired by the Android app Forest, " "but with all of the plants generated procedurally. It's <a href='https://github.com/xiaoxiae/Florodoro'>open source</a> and licensed " "under MIT, so do as you please with the code and anything else related to the project.", ), ) ) self.plant_menu = self.options_menu.addMenu("&Plants") self.overstudy_action = QAction("Overstudy", self, checkable=True) self.options_menu.addAction(self.overstudy_action) self.plant_images = [] self.plant_checkboxes = [] # dynamically create widgets for each plant for plant, name in zip(self.PLANTS, self.PLANT_NAMES): self.plant_images.append(tempfile.NamedTemporaryFile(suffix=".svg")) tmp = plant() tmp.set_max_age(1) tmp.set_age(1) tmp.save(self.plant_images[-1].name, 200, 200) setattr(self.__class__, name, QAction(self, icon=QIcon(self.plant_images[-1].name), text=name, checkable=True, checked=True)) action = getattr(self.__class__, name) self.plant_menu.addAction(action) self.plant_checkboxes.append(action) # the current plant that we're growing # if set to none, no plant is growing self.plant = None self.menuBar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum) main_vertical_layout = QVBoxLayout(self) main_vertical_layout.setContentsMargins(0, 0, 0, 0) main_vertical_layout.setSpacing(0) main_vertical_layout.addWidget(self.menuBar) self.canvas = Canvas(self) self.statistics = Statistics(self.history) font = self.font() font.setPointSize(100) self.main_label = QLabel(self, alignment=Qt.AlignCenter) self.main_label.setFont(font) self.main_label.setText(self.INITIAL_TEXT) font.setPointSize(26) self.cycle_label = QLabel(self) self.cycle_label.setAlignment(Qt.AlignTop) self.cycle_label.setMargin(20) self.cycle_label.setFont(font) main_horizontal_layout = QHBoxLayout(self) self.study_time_spinbox = QSpinBox(self, prefix="Study for: ", suffix="min.", minimum=1, maximum=self.MAX_TIME, singleStep=self.STEP) self.break_time_spinbox = QSpinBox(self, prefix="Break for: ", suffix="min.", minimum=1, maximum=self.MAX_TIME, singleStep=self.STEP, styleSheet=f'color:{self.BREAK_COLOR};') self.cycles_spinbox = QSpinBox(self, prefix="Cycles: ", minimum=1, value=1) # keep track of remaining number of cycles and the starting number of cycles self.remaining_cycles = 0 self.total_cycles = 0 # whether we're currently studying self.is_study_ongoing = False # whether we notified the user already during overstudy self.already_notified_during_overstudy = False stacked_layout = QStackedLayout(self, stackingMode=QStackedLayout.StackAll) stacked_layout.addWidget(self.main_label) stacked_layout.addWidget(self.cycle_label) stacked_layout.addWidget(self.canvas) main_vertical_layout.addLayout(stacked_layout) self.setStyleSheet("") self.study_button = QPushButton(self, clicked=self.start, icon=self.STUDY_ICON) self.break_button = QPushButton(self, clicked=self.start_break, icon=self.BREAK_ICON) self.pause_button = QPushButton(self, clicked=self.toggle_pause, icon=self.PAUSE_ICON) self.reset_button = QPushButton(self, clicked=self.reset, icon=self.RESET_ICON) main_horizontal_layout.addWidget(self.study_time_spinbox) main_horizontal_layout.addWidget(self.break_time_spinbox) main_horizontal_layout.addWidget(self.cycles_spinbox) main_horizontal_layout.addWidget(self.study_button) main_horizontal_layout.addWidget(self.break_button) main_horizontal_layout.addWidget(self.pause_button) main_horizontal_layout.addWidget(self.reset_button) main_vertical_layout.addLayout(main_horizontal_layout) self.setLayout(main_vertical_layout) self.study_timer_frequency = 1 / 60 * 1000 self.study_timer = QTimer(self, interval=int(self.study_timer_frequency), timeout=self.decrease_remaining_time) self.player = QMediaPlayer(self) self.setWindowIcon(QIcon(self.IMAGE_FOLDER + "icon.svg")) self.setWindowTitle(self.APP_NAME) # set initial UI state self.reset() # a list of name, getter and setter things to load/save when the app opens/closes # also dynamically get settings for selecting/unselecting plants self.CONFIGURATION_ATTRIBUTES = [("study-time", self.study_time_spinbox.value, self.study_time_spinbox.setValue), ("break-time", self.break_time_spinbox.value, self.break_time_spinbox.setValue), ("cycles", self.cycles_spinbox.value, self.cycles_spinbox.setValue), ("sound", self.sound_action.isChecked, self.sound_action.setChecked), ("sound-volume", self.volume_slider.value, self.volume_slider.setValue), ("pop-ups", self.popup_action.isChecked, self.popup_action.setChecked), ("overstudy", self.overstudy_action.isChecked, self.overstudy_action.setChecked)] + \ [(name.lower(), getattr(self.__class__, name).isChecked, getattr(self.__class__, name).setChecked) for _, name in zip(self.PLANTS, self.PLANT_NAMES)] # load the default preset self.load_preset(*self.presets[self.DEFAULT_PRESET]) self.load_settings() self.show()
def show_header_menu(self, col: int): """Pop up a mini entry menu for filtering on a column.""" key = self._model._HEADERS[col] if key not in ["name", "flagging"] or self._block_header_menu: self._block_header_menu = False return self._filter_menu = QMenu(self.parent()) self._filter_menu.aboutToHide.connect( self._check_mouse_on_header_menu_hide) def get_filter_cb(key, f): def cb(): self.add_filter.emit(key, f) self._block_header_menu = False return cb if key == "flagging": group = QActionGroup(self) group.setExclusive(True) for filter_string in ["All", "F", "NF"]: action = QAction(filter_string, group, checkable=True) if filter_string == "All" and not self._state.flagging_filter: action.setChecked(True) filter_string = "" elif filter_string == self._state.flagging_filter: action.setChecked(True) self._filter_menu.addAction(action) action.triggered.connect(get_filter_cb(key, filter_string)) elif key == "name": # Make button for resetting filter (show all). all_action = QAction("All", checkable=True) if not self._model._filters["name"]: all_action.setChecked(True) all_action.triggered.connect(get_filter_cb(key, None)) self._filter_menu.addAction(all_action) # add to menu self._filter_menu.addSeparator( ) # patch highlighting with mouse movement ## Make entry bar for name filter. # Create the entry bar with the existing filter as the text. if self._state.name_hint: # Name in entry bar, if any. text = self._state.name_hint else: # If no name in entry bar, name currently filtered by. text = self._state.name_filter entry = QLineEdit(text, self) entry.selectAll() # select all the text # Set focus to the entry bar when the menu is opened. self._filter_menu.aboutToShow.connect(entry.setFocus) def set_name_filter(): self.add_filter.emit(key, entry.text().strip()) self._filter_menu.hide() self._block_header_menu = False entry.returnPressed.connect( set_name_filter) # enter applies filter name_action = QWidgetAction( self._filter_menu) # to contain QLineEdit name_action.setDefaultWidget(entry) # set widget on QWidgetAction self._filter_menu.addAction(name_action) # add to menu self._filter_menu.index = col # Display menu in appropriate position, below header in column 'col' headerPos = self.mapToGlobal(self._header.pos()) posY = headerPos.y() + self._header.height() posX = headerPos.x() + self._header.sectionPosition(col) pos = QPoint(posX, posY) self._filter_menu.exec_(pos) # modal dialog self.resizeRowsToContents()
def setupZoomWidget(self): self.zoom = QWidgetAction(self) self.zoomWidget = ZoomWidget() self.zoom.setDefaultWidget(self.zoomWidget) self.zoomWidget.setEnabled(False)
def configure_menuBar(self): menubar = self.menuBar() menubar_items = { '&File': [ ("&New File", "Ctrl+N", self.add_new_tab), ("&Open File", "Ctrl+O", self.file_open), ("&Save File", "Ctrl+S", self.file_save), ("&Save File as", "Ctrl+Shift+S", self.save_as), ("&Print", "Ctrl+P", self.print_document), None, ("&Quit", "Ctrl+Q", self.quit), ], '&Edit': [ ("&Cut", "Ctrl+X", self.cut_document), ("&Copy", "Ctrl+C", self.copy_document), ("&Paste", "Ctrl+V", self.paste_document), None, ("&Undo", "Ctrl+Z", self.undo_document), ("&Redo", "Ctrl+Y", self.redo_document) ], '&View': [ ("&Fullscreen", "F11", self.fullscreen), None, ("&Align Left", "", self.align_left), ("&Align Right", "", self.align_right), ("&Align Center", "", self.align_center), ("&Align Justify", "", self.align_justify) ], '&About': [ ("&About Us", "Ctrl+H", self.about), None, ("&Help", "", self.help) ] } for menuitem, actions in menubar_items.items(): menu = menubar.addMenu(menuitem) for act in actions: if act: text, shortcut, callback = act action = QAction(text, self) action.setShortcut(shortcut) action.triggered.connect(callback) menu.addAction(action) else: menu.addSeparator() # Font Family Input fontBox = QFontComboBox(self) fontBox.currentFontChanged.connect(self.fontfamily) fontSize = QComboBox(self) fontSize.setEditable(True) fontSize.setMinimumContentsLength(3) fontSize.activated.connect(self.fontsize) # Font Sizes fontSizes = [ '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '18', '20', '22', '24', '26', '28', '32', '36', '40', '44', '48', '54', '60', '66', '72', '80', '88', '96' ] fontSize.addItems(fontSizes) font_family = QWidgetAction(self) font_family.setDefaultWidget(fontBox) # Settings Menubar settings = menubar.addMenu('&Font Settings') menu_font = settings.addMenu("&Font") menu_font.addAction(font_family) font_size = QWidgetAction(self) font_size.setDefaultWidget(fontSize) menu_size = settings.addMenu("&Font Size") menu_size.addAction(font_size)
def __init__(self, font, parent=None): super().__init__(parent) auxiliaryWidth = self.fontMetrics().width('0') * 8 self.leftTextField = MetricsSequenceEdit(font, self) self.leftTextField.setMaximumWidth(auxiliaryWidth) self.textField = MetricsSequenceComboBox(font, self) # XXX: had to use Maximum because Preferred did extend the widget(?) self.textField.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Maximum) self.rightTextField = MetricsSequenceEdit(font, self) self.rightTextField.setMaximumWidth(auxiliaryWidth) self.leftTextField.textEdited.connect(self.textField.editTextChanged) self.rightTextField.textEdited.connect(self.textField.editTextChanged) self.textField.editTextChanged.connect(self._textChanged) self.comboBox = QComboBox(self) self.comboBox.setEditable(True) self.comboBox.setCompleter(None) self.comboBox.setValidator(QIntValidator(self)) for p in pointSizes: self.comboBox.addItem(str(p)) self.pointSizeChanged = self.comboBox.currentIndexChanged[str] self.configBar = QPushButton(self) self.configBar.setFlat(True) self.configBar.setIcon(QIcon(":settings.svg")) self.configBar.setStyleSheet("padding: 2px 0px; padding-right: 10px") self.toolsMenu = QMenu(self) self._showKerning = self.toolsMenu.addAction( self.tr("Show Kerning"), self._kerningVisibilityChanged) self._showKerning.setCheckable(True) self._showMetrics = self.toolsMenu.addAction( self.tr("Show Metrics"), self._controlsTriggered) self._showMetrics.setCheckable(True) self.toolsMenu.addSeparator() self._verticalFlip = self.toolsMenu.addAction( self.tr("Vertical Flip"), self._controlsTriggered) self._verticalFlip.setCheckable(True) self._wrapLines = self.toolsMenu.addAction( self.tr("Wrap Lines"), self._controlsTriggered) self._wrapLines.setCheckable(True) self.toolsMenu.addSeparator() action = self.toolsMenu.addAction(self.tr("Line Height:")) action.setEnabled(False) lineHeight = QWidgetAction(self.toolsMenu) self._lineHeightSlider = slider = QSlider(Qt.Horizontal, self) # QSlider works with integers so we'll just divide what comes out of it # by 100 slider.setMinimum(80) slider.setMaximum(160) slider.setValue(110) slider.valueChanged.connect(self._controlsTriggered) slider.valueChanged.connect(self._sliderLineHeightChanged) lineHeight.setDefaultWidget(slider) self.toolsMenu.addAction(lineHeight) self.configBar.setMenu(self.toolsMenu) self.addWidget(self.leftTextField) self.addWidget(self.textField) self.addWidget(self.rightTextField) self.addWidget(self.comboBox) self.addWidget(self.configBar) app = QApplication.instance() app.dispatcher.addObserver( self, "_currentGlyphChanged", "currentGlyphChanged") self.readSettings()
color = QColor('#29AB87') if self.ok else QColor(255, 0, 0, 128) painter = QPainter(self) painter.setBrush(color) painter.setPen(color) painter.drawRect(self.rect()) # TODO: Нарисовать график if __name__ == '__main__': app = QApplication([]) app.setQuitOnLastWindowClosed(False) tray = QSystemTrayIcon(QIcon(TRAY_ICON)) job_report_widget = JobReportWidget() job_report_widget.setFixedSize(230, 130) job_report_widget_action = QWidgetAction(job_report_widget) job_report_widget_action.setDefaultWidget(job_report_widget) menu = QMenu() menu.addAction(job_report_widget_action) tray.setContextMenu(menu) tray.activated.connect(lambda x: menu.exec(tray.geometry().center())) tray.setToolTip('Compass Plus. Рапорт учета рабочего времени') tray.show() app.exec()
class MovieWidget(QWidget): #------------------------------------------------------------------------------- # __init__() #------------------------------------------------------------------------------- def __init__(self, parent=None): super(MovieWidget, self).__init__(parent) mini = True self.parent = parent self.isVideoAvailable = False self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.mediaPlayer.videoAvailableChanged.connect( self.videoAvailableChanged) videoWidget = QVideoWidget(self) videoWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.setContextMenuPolicy(Qt.CustomContextMenu) # Context Menu self.customContextMenuRequested.connect(self.openContextMenu) self.contextMenu = QMenu() self.openAction = self.contextMenu.addAction("Open file") icon = QIcon(self.style().standardIcon(QStyle.SP_DialogOpenButton)) self.openAction.setIcon(icon) self.urlAction = self.contextMenu.addAction("Open stream") icon = QIcon(self.style().standardIcon(QStyle.SP_DirLinkIcon)) self.urlAction.setIcon(icon) self.playAction = self.contextMenu.addAction("Play/Pause") icon = QIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playAction.setEnabled(False) self.playAction.setIcon(icon) self.closeAction = self.contextMenu.addAction("Close") icon = QIcon(self.style().standardIcon(QStyle.SP_DialogCloseButton)) self.closeAction.setEnabled(False) self.closeAction.setIcon(icon) self.posSlider = QSlider(Qt.Horizontal) self.posSlider.setRange(0, 0) self.posSlider.sliderMoved.connect(self.setPosition) self.wac = QWidgetAction(self.contextMenu) self.wac.setDefaultWidget(self.posSlider) self.posAction = self.contextMenu.addAction(self.wac) self.lblFile = QLabel() self.wal = QWidgetAction(self.contextMenu) self.wal.setDefaultWidget(self.lblFile) self.posAction = self.contextMenu.addAction(self.wal) # Control box self.openButton = QPushButton() self.openButton.setIcon(self.style().standardIcon( QStyle.SP_DialogOpenButton)) self.openButton.clicked.connect(self.openFile) self.urlButton = QPushButton() self.urlButton.setIcon(self.style().standardIcon( QStyle.SP_DirLinkIcon)) self.urlButton.clicked.connect(self.openURL) self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.clicked.connect(self.play) self.positionSlider = QSlider(Qt.Horizontal) self.positionSlider.setRange(0, 0) self.positionSlider.sliderMoved.connect(self.setPosition) self.errorLabel = QLabel() self.errorLabel.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) # Create layouts to place inside widget controlLayout = QHBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) controlLayout.addWidget(self.openButton) controlLayout.addWidget(self.urlButton) controlLayout.addWidget(self.playButton) controlLayout.addWidget(self.positionSlider) vLayout = QVBoxLayout() vLayout.setContentsMargins(0, 0, 0, 0) vLayout.addWidget(videoWidget) if mini != True: vLayout.addLayout(controlLayout) vLayout.addWidget(self.errorLabel) self.setLayout(vLayout) # Set widget to contain window contents self.mediaPlayer.setVideoOutput(videoWidget) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.durationChanged.connect(self.durationChanged) self.mediaPlayer.error.connect(self.handleError) self.resize(180, 100) #------------------------------------------------------------------------------- # videoAvailableChanged() #------------------------------------------------------------------------------- def videoAvailableChanged(self, available): self.isVideoAvailable = available print("Video available %s" % str(available)) #------------------------------------------------------------------------------- # openContextMenu() #------------------------------------------------------------------------------- def openContextMenu(self, position): action = self.contextMenu.exec_(self.mapToGlobal(position)) if action == self.playAction: self.play() elif action == self.openAction: self.openFile() elif action == self.urlAction: self.openURL() elif action == self.closeAction: self.closeFile() #------------------------------------------------------------------------------- # openFile() #------------------------------------------------------------------------------- def openFile(self): fileName, _ = QFileDialog.getOpenFileName( self, "Open Media", QDir.homePath(), "All Files (*);;Movies (*.avi *.mp4);;Music (*.mp3 *.ogg)", options=QFileDialog.DontUseNativeDialog) if fileName != '': self.mediaSource = os.path.splitext(os.path.basename(fileName))[0] self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(fileName))) self.errorLabel.setText( os.path.splitext(os.path.basename(fileName))[0]) self.lblFile.setText(" " + self.mediaSource) self.playButton.setEnabled(True) self.playAction.setEnabled(True) self.closeAction.setEnabled(True) self.play() #------------------------------------------------------------------------------- # openURL() #------------------------------------------------------------------------------- def openURL(self): url, ok = QInputDialog.getText(self, 'Open Stream', 'URL of stream :') if ok: if url != '': self.mediaSource = url self.mediaPlayer.setMedia(QMediaContent(QUrl(url))) self.errorLabel.setText(url) self.lblFile.setText(" " + url) self.playButton.setEnabled(True) self.playAction.setEnabled(True) self.closeAction.setEnabled(True) self.play() #------------------------------------------------------------------------------- # closeFile() #------------------------------------------------------------------------------- def closeFile(self): self.pauseForce() self.mediaPlayer.setMedia(QMediaContent()) self.playButton.setEnabled(False) self.playAction.setEnabled(False) self.closeAction.setEnabled(False) self.lblFile.setText("") #------------------------------------------------------------------------------- # play() #------------------------------------------------------------------------------- def play(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() self.parent.bigDisplay(self.mediaSource) #------------------------------------------------------------------------------- # playForce() #------------------------------------------------------------------------------- def playForce(self): self.mediaPlayer.play() #------------------------------------------------------------------------------- # pauseForce() #------------------------------------------------------------------------------- def pauseForce(self): self.mediaPlayer.pause() #------------------------------------------------------------------------------- # mediaStateChanged() #------------------------------------------------------------------------------- def mediaStateChanged(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) self.playAction.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) else: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) self.playAction.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) #------------------------------------------------------------------------------- # positionChanged() #------------------------------------------------------------------------------- def positionChanged(self, position): self.posSlider.setValue(position) self.positionSlider.setValue(position) #------------------------------------------------------------------------------- # durationChanged() #------------------------------------------------------------------------------- def durationChanged(self, duration): self.posSlider.setRange(0, duration) self.positionSlider.setRange(0, duration) #------------------------------------------------------------------------------- # setPosition() #------------------------------------------------------------------------------- def setPosition(self, position): self.mediaPlayer.setPosition(position) #------------------------------------------------------------------------------- # handleError() #------------------------------------------------------------------------------- def handleError(self): self.playButton.setEnabled(False) self.errorLabel.setText("Error: " + self.mediaPlayer.errorString())
def initUI(self): self.display_min = 0 # 图像显示最大值(对应灰度值为255) self.display_max = 1 # 图像显示最小值(对应灰度值为0) self.display_x = 0 # 显示图像的x坐标 self.display_y = 0 # 显示图像的y坐标 self.display_z = 0 # 显示图像的z坐标 self.display_vol = -1 # 显示图像的volume序列 self.ratio = [1, 1, 1.25] # 显示图像的比例 self.idx_fname = -1 # 如果打开的是文件夹,则对应文件夹中实际显示的图像的序号,否则为-1 self.fname = "" # 显示图像/文件夹的路径 self.nii = "" # 对应图像的nii self.niilist = "" # 对应多个nii图像进行计算的结果 self.nii_display = "" # 显示用的nii数据(值转换为对应的0-255) self.pixmap_a = "" self.pixmap_c = "" self.pixmap_s = "" # 用于在子窗口显示的单幅图像*3 #显示图像的label self.label_axial = AxialLabel(self) self.label_axial.setStyleSheet("border: 1px solid black") # 设置label边框 self.label_axial.setScaledContents(True) # 设置图像自适应修改大小 self.label_axial.setMouseTracking(False) # 设置鼠标点击任意键时才捕捉鼠标位置 self.label_axial.mousePressEvent = self.click_a # 鼠标点击时修改显示的另两个视图位置 self.label_axial.mouseMoveEvent = self.click_a # 鼠标拖拽时修改显示的另两个试图位置 self.label_axial.mouseDoubleClickEvent = self.double_click_a # 鼠标进行双击时显示对应slice的图像 self.label_coronal = CoronalLabel(self) # 同上 self.label_coronal.setStyleSheet("border: 1px solid black") self.label_coronal.setScaledContents(True) self.label_coronal.setMouseTracking(False) self.label_coronal.mousePressEvent = self.click_c self.label_coronal.mouseMoveEvent = self.click_c self.label_coronal.mouseDoubleClickEvent = self.double_click_c self.label_sagittal = SagittalLabel(self) # 同上 self.label_sagittal.setStyleSheet("border: 1px solid black") self.label_sagittal.setScaledContents(True) self.label_sagittal.setMouseTracking(False) self.label_sagittal.mousePressEvent = self.click_s self.label_sagittal.mouseMoveEvent = self.click_s self.label_sagittal.mouseDoubleClickEvent = self.double_click_s # 显示图像信息的框架 self.grid_info = QGridLayout() # 设置信息总框架 # 显示图像文件路径 if self.lan == 0: self.label_name_dir = QLabel("Directory:", self) # 设置显示文件路径信息条目的label elif self.lan == 1: self.label_name_dir = QLabel("文件路径:", self) self.label_val_dir = QLineEdit(self) # 设置显示文件路径具体信息的label self.label_val_dir.setText(self.fname) # 显示图像数据类型 if self.lan == 0: self.label_name_datype = QLabel("Data Type:", self) elif self.lan == 1: self.label_name_datype = QLabel("数据类型:", self) self.label_val_datype = QLineEdit(self) self.label_val_datype.setEnabled(False) # 设置图像数据格式为不可修改 try: self.label_val_datype.setText(str(self.nii.header.get("datatype").dtype)) except AttributeError: pass # 显示图像维度信息 if self.lan == 0: self.label_name_diminfo = QLabel("Dim:", self) elif self.lan == 1: self.label_name_diminfo = QLabel("图像维度:", self) self.label_val_diminfo = QLineEdit(self) self.label_val_diminfo.setEnabled(False) # 设置图像维度信息为不可修改 try: self.label_val_diminfo.setText(str(self.nii.get_fdata().shape)) except AttributeError: pass if self.lan == 0: self.label_name_resinfo = QLabel("Resolution", self) elif self.lan == 1: self.label_name_resinfo = QLabel("分辨率:", self) self.label_val_resinfo = QLineEdit(self) self.label_val_resinfo.setEnabled(False) # 设置图像分辨率信息为不可修改 try: self.label_val_resinfo.setText("(" + str((self.nii.header.get("pixdim"))[1])+", "+str((self.nii.header.get("pixdim"))[2])+", "+str((self.nii.header.get("pixdim"))[3])+", "+str((self.nii.header.get("pixdim"))[0])+")") except AttributeError: pass # 显示图像显示比例 if self.lan == 0: self.label_name_disratio = QLabel("Display Ratio:", self) elif self.lan == 1: self.label_name_disratio = QLabel("显示比例:", self) self.grid_val_disratio = QGridLayout() self.label_ratio_1 = QLineEdit(self) self.label_ratio_2 = QLineEdit(self) self.label_ratio_3 = QLineEdit(self) if self.lan == 0: self.but_ratio = QPushButton("RESET", self) elif self.lan == 1: self.but_ratio = QPushButton("重置", self) self.label_ratio_1.setText(str(self.ratio[0])) self.label_ratio_2.setText(str(self.ratio[1])) self.label_ratio_3.setText(str(self.ratio[2])) self.label_ratio_1.editingFinished.connect(self.modify_ratio_1) # 修改显示比例后,调节显示比例 self.label_ratio_2.editingFinished.connect(self.modify_ratio_2) self.label_ratio_3.editingFinished.connect(self.modify_ratio_3) self.but_ratio.clicked.connect(self.reset_ratio) # 重置显示比例为默认值 # 显示图像对应slice if self.lan == 0: self.label_name_disvol = QLabel("Display volume:", self) elif self.lan == 1: self.label_name_disvol = QLabel("显示位置:", self) self.grid_val_disvol = QGridLayout() self.spin_x = QSpinBox(self) self.spin_y = QSpinBox(self) self.spin_z = QSpinBox(self) # self.combox_x = QLineEdit(self) # self.combox_y = QLineEdit(self) # self.combox_z = QLineEdit(self) self.combox_t = QComboBox(self) self.combox_t.activated.connect(self.switch_vol) # 点击下拉菜单切换显示的volume # self.combox_x.editingFinished.connect(self.modify_slice_x) # 通过在文本框中输入坐标来完成显示切换 # self.combox_y.editingFinished.connect(self.modify_slice_y) # self.combox_z.editingFinished.connect(self.modify_slice_z) self.spin_x.valueChanged.connect(self.modify_slice_x) self.spin_y.valueChanged.connect(self.modify_slice_y) self.spin_z.valueChanged.connect(self.modify_slice_z) self.spin_x.setWrapping(True) self.spin_y.setWrapping(True) self.spin_z.setWrapping(True) self.spin_x.setMinimum(1) self.spin_y.setMinimum(1) self.spin_z.setMinimum(1) self.spin_x.setMaximum(1) self.spin_y.setMaximum(1) self.spin_z.setMaximum(1) # 显示图像显示范围 if self.lan == 0: self.label_name_disrange = QLabel("Display range:", self) elif self.lan == 1: self.label_name_disrange = QLabel("显示范围:", self) self.grid_val_disrange = QGridLayout() self.label_val_min = QLineEdit(self) self.label_val_max = QLineEdit(self) if self.lan == 0: self.but_range = QPushButton("RESET", self) elif self.lan == 1: self.but_range = QPushButton("重置", self) self.label_val_min.editingFinished.connect(self.modify_min) # 修改显示范围后,对应修改显示范围 self.label_val_max.editingFinished.connect(self.modify_max) self.but_range.clicked.connect(self.reset_range) # 重置显示范围为默认值 # 安排组件位置 self.grid_val_disratio.addWidget(self.label_ratio_1, 0, 0) self.grid_val_disratio.addWidget(self.label_ratio_2, 0, 1) self.grid_val_disratio.addWidget(self.label_ratio_3, 0, 2) self.grid_val_disratio.addWidget(self.but_ratio, 0, 3) # self.grid_val_disvol.addWidget(self.combox_x, 0, 1) # self.grid_val_disvol.addWidget(self.combox_y, 0, 2) # self.grid_val_disvol.addWidget(self.combox_z, 0, 3) self.grid_val_disvol.addWidget(self.spin_x, 0, 1) self.grid_val_disvol.addWidget(self.spin_y, 0, 2) self.grid_val_disvol.addWidget(self.spin_z, 0, 3) self.grid_val_disvol.addWidget(self.combox_t, 0, 0) self.grid_val_disrange.addWidget(self.label_val_min, 0, 0) self.grid_val_disrange.addWidget(self.label_val_max, 0, 1) self.grid_val_disrange.addWidget(self.but_range, 0, 2) self.grid_info.addWidget(self.label_name_dir, 0, 0) self.grid_info.addWidget(self.label_val_dir, 0, 1) self.grid_info.addWidget(self.label_name_datype, 1, 0) self.grid_info.addWidget(self.label_val_datype, 1, 1) self.grid_info.addWidget(self.label_name_diminfo, 2, 0) self.grid_info.addWidget(self.label_val_diminfo, 2, 1) self.grid_info.addWidget(self.label_name_resinfo, 3, 0) self.grid_info.addWidget(self.label_val_resinfo, 3, 1) self.grid_info.addWidget(self.label_name_disratio, 4, 0) self.grid_info.addLayout(self.grid_val_disratio, 4, 1) self.grid_info.addWidget(self.label_name_disvol, 5, 0) self.grid_info.addLayout(self.grid_val_disvol, 5, 1) self.grid_info.addWidget(self.label_name_disrange, 6, 0) self.grid_info.addLayout(self.grid_val_disrange, 6, 1) # 设置菜单 if self.lan == 0: openAction = QAction('&Open Nii File...', self) # 将对应功能加入菜单栏对应子项中 openAction.setStatusTip('Select and open a Nifti file') elif self.lan == 1: openAction = QAction('打开nii文件...', self) # 将对应功能加入菜单栏对应子项中 openAction.setStatusTip('选择并打开一个Nifti格式文件') openAction.setShortcut('Ctrl+O') openAction.triggered.connect(self.OpenFile) if self.lan == 0: saveAction = QAction('&Save...', self) saveAction.setStatusTip('Save current nii file in display') elif self.lan == 1: saveAction = QAction('保存文件...', self) saveAction.setStatusTip('将正在显示的图像保存为nii文件') saveAction.setShortcut('Ctrl+S') saveAction.triggered.connect(self.SaveFile) if self.lan == 0: exitAction = QAction('&Quit', self) exitAction.setStatusTip('Exit') elif self.lan == 1: exitAction = QAction('退出', self) exitAction.setStatusTip('退出程序') exitAction.setShortcut('Ctrl+Q') exitAction.triggered.connect(qApp.quit) self.bul_displaych = 1 self.gapsizech = 4 self.thicknessch = 2 self.colorch = Qt.blue if self.lan == 0: crosshairMenu = QMenu('&Crosshair Settings', self) crosshairMenu.setStatusTip('Change settings with crosshair') ch_displayAction = QAction('Display Crosshair', self, checkable = True) ch_displayAction.setChecked(True) ch_displayAction.setStatusTip('Display crosshair in the image or not.') ch_gapsizeAction = QAction('Gap Size', self) ch_gapsizeAction.setStatusTip('Change gap size of crosshair') ch_thicknessAction = QAction('Thickness', self) ch_thicknessAction.setStatusTip('Change thickness of crosshair') ch_colorMenu = QMenu('Color', self) ch_colorMenu.setStatusTip('Change color of crosshair') ch_redAction = QWidgetAction(self) ch_redWidget = QLabel("Red") ch_redWidget.setStyleSheet("QLabel { color : red; padding: 4 4 4 30px;}QLabel:hover{background:#90c8f6;}") ch_redAction.setDefaultWidget(ch_redWidget) ch_blueAction = QWidgetAction(self) ch_blueWiget = QLabel("Blue") ch_blueWiget.setStyleSheet("QLabel {color:blue; padding: 4 4 4 30px}QLabel:hover{background:#90c8f6;}") ch_blueAction.setDefaultWidget(ch_blueWiget) ch_grayAction = QWidgetAction(self) ch_grayWiget = QLabel("Gray") ch_grayWiget.setStyleSheet("QLabel {color:gray; padding: 4 4 4 30px}QLabel:hover{background:#90c8f6;}") ch_grayAction.setDefaultWidget(ch_grayWiget) ch_cyanAction = QWidgetAction(self) ch_cyanWiget = QLabel("Cyan") ch_cyanWiget.setStyleSheet("QLabel {color:cyan; padding: 4 4 4 30px}QLabel:hover{background:#90c8f6;}") ch_cyanAction.setDefaultWidget(ch_cyanWiget) ch_blackAction = QWidgetAction(self) ch_blackWiget = QLabel("Black") ch_blackWiget.setStyleSheet("QLabel {color:black; padding: 4 4 4 30px}QLabel:hover{background:#90c8f6;}") ch_blackAction.setDefaultWidget(ch_blackWiget) ch_greenAction = QWidgetAction(self) ch_greenWiget = QLabel("Green") ch_greenWiget.setStyleSheet("QLabel {color:green; padding: 4 4 4 30px}QLabel:hover{background:#90c8f6;}") ch_greenAction.setDefaultWidget(ch_greenWiget) ch_whiteAction = QWidgetAction(self) ch_whiteWiget = QLabel("White") ch_whiteWiget.setStyleSheet("QLabel {color:white; padding: 4 4 4 30px}QLabel:hover{background:#90c8f6;}") ch_whiteAction.setDefaultWidget(ch_whiteWiget) ch_otherAction = QWidgetAction(self) ch_otherWiget = QLabel("Other...") ch_otherWiget.setStyleSheet("QLabel {color:black; padding: 4 4 4 30px}QLabel:hover{background:#90c8f6;}") ch_otherAction.setDefaultWidget(ch_otherWiget) elif self.lan == 1: crosshairMenu = QMenu('设置十字线', self) crosshairMenu.setStatusTip('更改十字线相关设置') ch_displayAction = QAction('显示十字线', self, checkable = True) ch_displayAction.setChecked(True) ch_displayAction.setStatusTip('是否在图像上显示十字线') ch_gapsizeAction = QAction('空隙尺寸', self) ch_gapsizeAction.setStatusTip('更改十字线中心的空隙大小') ch_thicknessAction = QAction('线条宽度', self) ch_thicknessAction.setStatusTip('更改十字线线条的宽度') ch_colorMenu = QMenu('线条颜色', self) ch_colorMenu.setStatusTip('更改十字线线条的颜色') ch_redAction = QWidgetAction(self) ch_redWidget = QLabel("红色") ch_redWidget.setStyleSheet("QLabel { color : red; padding: 4 4 4 30px;}QLabel:hover{background:#90c8f6;}") ch_redAction.setDefaultWidget(ch_redWidget) ch_blueAction = QWidgetAction(self) ch_blueWiget = QLabel("蓝色") ch_blueWiget.setStyleSheet("QLabel {color:blue; padding: 4 4 4 30px}QLabel:hover{background:#90c8f6;}") ch_blueAction.setDefaultWidget(ch_blueWiget) ch_grayAction = QWidgetAction(self) ch_grayWiget = QLabel("灰色") ch_grayWiget.setStyleSheet("QLabel {color:gray; padding: 4 4 4 30px}QLabel:hover{background:#90c8f6;}") ch_grayAction.setDefaultWidget(ch_grayWiget) ch_cyanAction = QWidgetAction(self) ch_cyanWiget = QLabel("青色") ch_cyanWiget.setStyleSheet("QLabel {color:cyan; padding: 4 4 4 30px}QLabel:hover{background:#90c8f6;}") ch_cyanAction.setDefaultWidget(ch_cyanWiget) ch_blackAction = QWidgetAction(self) ch_blackWiget = QLabel("黑色") ch_blackWiget.setStyleSheet("QLabel {color:black; padding: 4 4 4 30px}QLabel:hover{background:#90c8f6;}") ch_blackAction.setDefaultWidget(ch_blackWiget) ch_greenAction = QWidgetAction(self) ch_greenWiget = QLabel("绿色") ch_greenWiget.setStyleSheet("QLabel {color:green; padding: 4 4 4 30px}QLabel:hover{background:#90c8f6;}") ch_greenAction.setDefaultWidget(ch_greenWiget) ch_whiteAction = QWidgetAction(self) ch_whiteWiget = QLabel("白色") ch_whiteWiget.setStyleSheet("QLabel {color:white; padding: 4 4 4 30px}QLabel:hover{background:#90c8f6;}") ch_whiteAction.setDefaultWidget(ch_whiteWiget) ch_otherAction = QWidgetAction(self) ch_otherWiget = QLabel("更多...") ch_otherWiget.setStyleSheet("QLabel {color:black; padding: 4 4 4 30px}QLabel:hover{background:#90c8f6;}") ch_otherAction.setDefaultWidget(ch_otherWiget) crosshairMenu.addAction(ch_displayAction) crosshairMenu.addAction(ch_gapsizeAction) crosshairMenu.addAction(ch_thicknessAction) crosshairMenu.addMenu(ch_colorMenu) ch_colorMenu.addAction(ch_blackAction) ch_colorMenu.addAction(ch_blueAction) ch_colorMenu.addAction(ch_cyanAction) ch_colorMenu.addAction(ch_grayAction) ch_colorMenu.addAction(ch_greenAction) ch_colorMenu.addAction(ch_redAction) ch_colorMenu.addAction(ch_whiteAction) ch_colorMenu.addAction(ch_otherAction) ch_displayAction.triggered.connect(self.Display_ch) ch_gapsizeAction.triggered.connect(self.Gap_ch) ch_thicknessAction.triggered.connect(self.Thickness_ch) ch_redAction.triggered.connect(self.Setred_ch) ch_blackAction.triggered.connect(self.Setblack_ch) ch_blueAction.triggered.connect(self.Setblue_ch) ch_cyanAction.triggered.connect(self.Setcyan_ch) ch_grayAction.triggered.connect(self.Setgray_ch) ch_greenAction.triggered.connect(self.Setgreen_ch) ch_whiteAction.triggered.connect(self.Setwhite_ch) ch_otherAction.triggered.connect(self.Setother_ch) if self.lan == 0: nextAction = QAction('&Next File', self) nextAction.setStatusTip('Display next file') elif self.lan == 1: nextAction = QAction('下一个文件', self) nextAction.setStatusTip('显示下一个文件') nextAction.setShortcut('Page Down') nextAction.triggered.connect(self.NextFile) if self.lan == 0: prevAction = QAction('&Previous File', self) prevAction.setStatusTip('Display previous file') elif self.lan == 1: prevAction = QAction('上一个文件', self) prevAction.setStatusTip('显示上一个文件') prevAction.setShortcut('Page Up') prevAction.triggered.connect(self.PrevFile) if self.lan == 0: SegmentAction = QAction('&Segment', self) SegmentAction.setStatusTip('Segment image into grey matter, white matter and csf') elif self.lan == 1: SegmentAction = QAction('分割', self) SegmentAction.setStatusTip('将图像分割为灰质、白质、脑脊液三部分') SegmentAction.setShortcut('Ctrl+E') SegmentAction.triggered.connect(qApp.quit) if self.lan == 0: CoregisterAction = QAction('&Coregister', self) CoregisterAction.setStatusTip('Coregister target image with reference image') elif self.lan == 1: CoregisterAction = QAction('配准', self) CoregisterAction.setStatusTip('将目标图像与参考图像进行配准') CoregisterAction.setShortcut('Ctrl+C') CoregisterAction.triggered.connect(qApp.quit) if self.lan == 0: QCAction = QAction('&Quality Analysis', self) QCAction.setStatusTip('Analyse Quality of Current Image') elif self.lan == 1: QCAction = QAction('质量分析', self) QCAction.setStatusTip('分析当前图像的质量') QCAction.setShortcut('Ctrl+U') QCAction.triggered.connect(self.QCGui) if self.lan == 0: CalcbfAction = QAction('&Calculate CBF from ASL', self) CalcbfAction.setStatusTip('Calculate CBF image from different ASL images or DWI image') elif self.lan == 1: CalcbfAction = QAction('通过ASL计算CBF', self) CalcbfAction.setStatusTip('通过不同时间的ASL像或DWI像计算CBF图像') CalcbfAction.setShortcut('Ctrl+A') CalcbfAction.triggered.connect(self.CalculateCbf) if self.lan == 0: PVEAction = QAction('&Partial Volume Correlation', self) PVEAction.setStatusTip('Operate Partial Volume Correlation for CBF image') elif self.lan == 1: PVEAction = QAction('局部空间校正', self) PVEAction.setStatusTip('对CBF图像进行局部空间校正') PVEAction.setShortcut('Ctrl+P') PVEAction.triggered.connect(self.PVECbf) QToolTip.setFont(QFont('SansSerif', 10)) # 没用的字体 self.setGeometry(250, 100, 800, 650) # 修改窗口大小 self.setWindowTitle('Toolkit_Test') #修改程序显示标题 self.setWindowIcon(QIcon('source/images.jpg')) # 修改程序显示图标 self.setMinimumSize(300,300) # 设置允许修改到的最小窗口大小 # 显示状态栏,可用于显示菜单栏的备注 self.statusBar() menubar = self.menuBar() if self.lan == 0: fileMenu = menubar.addMenu('&File') # 为菜单栏增加子项 elif self.lan == 1: fileMenu = menubar.addMenu('文件') fileMenu.addAction(openAction) fileMenu.addAction(saveAction) fileMenu.addAction(exitAction) if self.lan == 0: dispMenu = menubar.addMenu('&Display') elif self.lan == 1: dispMenu = menubar.addMenu('显示') dispMenu.addMenu(crosshairMenu) dispMenu.addAction(prevAction) dispMenu.addAction(nextAction) if self.lan == 0: cbfMenu = menubar.addMenu('&Preprocess') elif self.lan == 1: cbfMenu = menubar.addMenu('预处理') cbfMenu.addAction(SegmentAction) cbfMenu.addAction(CoregisterAction) cbfMenu.addAction(QCAction) if self.lan == 0: calMenu = menubar.addMenu('&Calculation') elif self.lan == 1: calMenu = menubar.addMenu('计算') calMenu.addAction(CalcbfAction) calMenu.addAction(PVEAction)
class Plot(vip_base): """ style_codes: 0 : QtCore.Qt.SolidLine, 1 : QtCore.Qt.DashDotDotLine, 2 : QtCore.Qt.DashDotLine, 3 : QtCore.Qt.DashLine, 4 : QtCore.Qt.DotLine color_codes: 0 : (255, 255, 255), 1 : (255, 0 , 0 ), 2 : (0 , 255, 0 ), 3 : (0 , 0 , 255), 4 : (100, 100, 100) """ def __init__(self, debug=False): super(Plot, self).__init__() """ Function init :param config: :return: """ self.signals = {} self.__papi_debug__ = debug self.__buffer_size__ = None self.__downsampling_rate__ = 1 self.__tbuffer__ = [] self.__signals_have_same_length = True self.__append_at__ = 1 self.__new_added_data__ = 0 self.__input_size__ = 0 self.__rolling_plot__ = False self.__colors_selected__ = [] self.__styles_selected__ = [] self.__width_selected__ = [] self.__show_grid_x__ = None self.__show_grid_y__ = None self.__parameters__ = {} self.__update_intervall__ = None self.__last_time__ = None self.__last_plot_time__ = None self.__plotWidget__ = None self.__legend__ = None self.__stp_min_x = None self.__stp_max_x = None self.__stp_min_y = None self.__stp_max_y = None self.__stp_active__ = None self.__downsampling_rate_start__ = None; self.__downsampling_rate__ = None self.styles = { 0: QtCore.Qt.SolidLine, 1: QtCore.Qt.DashDotDotLine, 2: QtCore.Qt.DashDotLine, 3: QtCore.Qt.DashLine, 4: QtCore.Qt.DotLine } self.colors = { 0: (255, 255, 255), 1: (255, 0, 0 ), 2: (0, 255, 0 ), 3: (0, 0, 255), 4: (100, 100, 100) } def cb_initialize_plugin(self): """ Function initiate layer 0 :param config: :return: """ self.config = self.pl_get_current_config_ref() self.startup_config = self.pl_get_current_config() # --------------------------- # Read configuration # --------------------------- int_re = re.compile(r'(\d+)') self.__show_legend__ = self.config['show_legend']['value'] == '1' self.__show_grid_x__ = self.config['x-grid']['value'] == '1' self.__show_grid_y__ = self.config['y-grid']['value'] == '1' self.__rolling_plot__ = self.config['rolling_plot']['value'] == '1' self.__plot_over__ = self.pl_get_config_element('plot_over') self.__colors_selected__ = int_re.findall(self.config['color']['value']) self.__styles_selected__ = int_re.findall(self.config['style']['value']) self.__width_selected__ = int_re.findall(self.config['width']['value']) self.__buffer_size__ = int(int_re.findall(self.config['buffersize']['value'])[0]) self.__downsampling_rate__ = int(int_re.findall(self.config['downsampling_rate']['value'])[0]) self.__downsampling_rate_start__ = 0 self.__bgcolor = self.pl_get_config_element('bgcol') pos_re = re.compile(r'([0-9]+)') self.__legend_position__= pos_re.findall( self.pl_get_config_element('legend_position') ) # ---------------------------- # Set internal variables # ---------------------------- self.__tbuffer__ = collections.deque([0.0] * 0, self.__buffer_size__) # ---------------------------- # Set internal variables used for single timestamp plotting (stp) # ---------------------------- self.__stp_min_x = 0 self.__stp_max_x = 0 self.__stp_min_y = 0 self.__stp_max_y = 1 self.__stp_active__ = False # -------------------------------- # Create Layout and labels # -------------------------------- self.central_widget = QWidget() self.central_widget.setContentsMargins(0,0,0,0) self.label_widget = QWidget() self.label_widget.setContentsMargins(0,0,0,0) self.verticalLayout = QVBoxLayout() self.verticalLayout.setContentsMargins(0,0,0,0) self.verticalLayout.setSpacing(0) self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setContentsMargins(0,0,0,0) self.horizontalLayout.setSpacing(0) self.space_label = QLabel() self.space_label.setMargin(0) self.space_label.setAlignment(QtCore.Qt.AlignJustify) self.space_label.setStyleSheet("QLabel { background-color : black; color : grey;" "border : 0px solid black ; border-bottom-width : 5px }") self.time_label = QLabel() self.time_label.setMargin(0) self.time_label.setAlignment(QtCore.Qt.AlignJustify) self.time_label.setStyleSheet("QLabel { background-color : black; color : grey;" "border : 0px solid black ; border-bottom-width : 5px }") self.time_label.setMaximumWidth(55) self.unit_label = QLabel() self.unit_label.setMargin(0) self.unit_label.setAlignment(QtCore.Qt.AlignLeft) self.unit_label.setStyleSheet("QLabel { background-color : black; color : grey;" "border : 0px solid black ; border-bottom-width : 5px }") self.unit_label.setText('[s]') self.central_widget.setLayout(self.verticalLayout) self.label_widget.setLayout(self.horizontalLayout) # -------------------------------- # Create PlotWidget # -------------------------------- self.__plotWidget__ = PlotWidget() self.__plotWidget__.yRangeChanged.connect(self.plot_yrange_changed) self.__plotWidget__.setWindowTitle('PlotPerformanceTitle') self.__plotWidget__.showGrid(x=self.__show_grid_x__, y=self.__show_grid_y__) self.__plotWidget__.getPlotItem().getViewBox().disableAutoRange() self.__plotWidget__.getPlotItem().getViewBox().setYRange(0,6) self.__plotWidget__.getPlotItem().setDownsampling(auto=True) # ------------------------------ # Add Widget to Layout # ------------------------------ self.horizontalLayout.addWidget(self.space_label) self.horizontalLayout.addWidget(self.time_label) self.horizontalLayout.addWidget(self.unit_label) self.verticalLayout.addWidget(self.__plotWidget__) self.verticalLayout.addWidget(self.label_widget) if not self.__papi_debug__: # self.pl_set_widget_for_internal_usage(self.__plotWidget__) self.pl_set_widget_for_internal_usage(self.central_widget) self.__plotWidget__.getPlotItem().getViewBox().enableAutoRange(axis=pg.ViewBox.YAxis, enable=False) self.__plotWidget__.getPlotItem().getViewBox().enableAutoRange(axis=pg.ViewBox.XAxis, enable=False) self.__plotWidget__.getPlotItem().getViewBox().setMouseEnabled(x=False, y=True) # --------------------------- # Create Parameters # --------------------------- self.__parameters__['x-grid'] = \ DParameter('x-grid', self.config['x-grid']['value'], Regex='^(1|0){1}$') self.__parameters__['y-grid'] = \ DParameter('y-grid', self.config['y-grid']['value'], Regex='^(1|0){1}$') self.__parameters__['color'] = \ DParameter('color', self.config['color']['value'], Regex='^\[(\s*\d\s*)+\]') self.__parameters__['style'] = \ DParameter('style', self.config['style']['value'], Regex='^\[(\s*\d\s*)+\]') self.__parameters__['width'] = \ DParameter('width', self.config['width']['value'], Regex='^\[(\s*\d\s*)+\]') self.__parameters__['rolling'] = \ DParameter('rolling', self.config['rolling_plot']['value'], Regex='^(1|0){1}') self.__parameters__['downsampling_rate'] = \ DParameter('downsampling_rate', self.__downsampling_rate__, Regex='^\d+$') self.__parameters__['buffersize'] = \ DParameter('buffersize', self.__buffer_size__, Regex='^\d+$') self.__parameters__['yRange'] = \ DParameter('yRange', self.config['yRange']['value'], Regex='^\[(\d+\.\d+)\s+(\d+\.\d+)\]$') self.__parameters__['show_legend'] = \ DParameter('show_legend', self.config['show_legend']['value'], Regex=pc.REGEX_BOOL_BIN) self.__parameters__['legend_position'] = \ DParameter('legend_position', self.pl_get_config_element('legend_position'), Regex='\(([0-9]+),([0-9]+)\)') self.__parameters__['legend_position'].connect(self.parameter_callback_legend_position) if not self.__papi_debug__: self.pl_send_new_parameter_list(list(self.__parameters__.values())) # --------------------------- # Create Legend # --------------------------- if self.__show_legend__: self.__legend__ = self.__plotWidget__.getPlotItem().addLegend() else: self.__legend__ = None self.__last_time__ = current_milli_time() self.__update_intervall__ = 20 # in milliseconds self.__last_plot_time__ = 0 self.setup_context_menu() self.__plotWidget__.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.__plotWidget__.customContextMenuRequested.connect(self.showContextMenu) self.use_range_for_y(self.config['yRange']['value']) # ---------------------------- # Initiate for default plotting # ---------------------------- color_rgb = self.__bgcolor[1:-1] color_rgb = color_rgb.split(',') self.__plotWidget__.setBackground([int(color_rgb[0]),int(color_rgb[1]),int(color_rgb[2])]) self.initiate_update_plot() return True def cb_pause(self): """ Function pause :return: """ self.__plotWidget__.getPlotItem().getViewBox().setMouseEnabled(x=True, y=True) def cb_resume(self): """ Function resume :return: """ self.__plotWidget__.getPlotItem().getViewBox().setMouseEnabled(x=False, y=True) def cb_execute(self, Data=None, block_name = None, plugin_uname = None): """ Function cb_execute :param Data: :param block_name: :return: """ t = Data[self.__plot_over__] self.__input_size__ = len(t) self.__signals_have_same_length = True now = pg.ptime.time() for key in Data: if key not in [pc.CORE_TIME_SIGNAL, self.__plot_over__]: y = Data[key] if key in self.signals: if self.__downsampling_rate_start__ < len(y): ds_y = y[self.__downsampling_rate_start__::self.__downsampling_rate__] self.signals[key].add_data(ds_y) self.__signals_have_same_length &= (len(y) == len(t)) if self.__downsampling_rate_start__ >= len(t): self.__downsampling_rate_start__ -= len(t) else: ds_t = t[self.__downsampling_rate_start__::self.__downsampling_rate__] self.__downsampling_rate_start__ += self.__downsampling_rate__ - len(ds_t) self.__tbuffer__.extend(ds_t) self.__new_added_data__ += len(t) self.rolling_Checkbox.setDisabled(self.__stp_active__) if self.__input_size__ > 1 or self.__signals_have_same_length: if self.__stp_active__: self.initiate_update_plot() if current_milli_time() - self.__last_time__ > self.__update_intervall__ - self.__last_plot_time__: self.__last_time__ = current_milli_time() self.update_plot() self.__last_time__ = current_milli_time() self.__new_added_data__ = 0 else: if not self.__stp_active__ : self.initiate_update_plot_single_timestamp() if current_milli_time() - self.__last_time__ > self.__update_intervall__ - self.__last_plot_time__: self.__last_time__ = current_milli_time() self.update_plot_single_timestamp(Data) self.__last_time__ = current_milli_time() self.__new_added_data__ = 0 # print("Plot time: %0.5f sec" % (self.__last_plot_time__) ) def cb_set_parameter(self, name, value): """ Function set parameters :param name: :param value: :return: """ if name == 'x-grid': self.config['x-grid']['value'] = value self.__plotWidget__.showGrid(x=value == '1') self.xGrid_Checkbox.stateChanged.disconnect() self.xGrid_Checkbox.setChecked(value=='1') self.xGrid_Checkbox.stateChanged.connect(self.contextMenu_xGrid_toogle) if name == 'y-grid': self.config['y-grid']['value'] = value self.__plotWidget__.showGrid(y=value == '1') self.yGrid_Checkbox.stateChanged.disconnect() self.yGrid_Checkbox.setChecked(value=='1') self.yGrid_Checkbox.stateChanged.connect(self.contextMenu_yGrid_toogle) if name == 'downsampling_rate': self.config['downsampling_rate']['value'] = value self.__downsampling_rate__ = int(value) self.__new_added_data__ = 0 self.update_downsampling_rate() if name == 'rolling': self.clear() self.config['rolling_plot']['value'] = value self.update_rolling_plot() if name == 'color': self.clear() self.config['color']['value'] = value int_re = re.compile(r'(\d+)') self.__colors_selected__ = int_re.findall(self.config['color']['value']) self.update_pens() self.update_legend() if name == 'style': self.clear() self.config['style']['value'] = value int_re = re.compile(r'(\d+)') self.__styles_selected__ = int_re.findall(self.config['style']['value']) self.update_pens() self.update_legend() if name == 'width': self.clear() self.config['width']['value'] = value int_re = re.compile(r'(\d+)') self.__width_selected__ = int_re.findall(self.config['width']['value']) self.update_pens() self.update_legend() if name == 'show_legend': self.config['show_legend']['value'] = value if value == '0': if self.__legend__ is not None: self.__legend__.scene().removeItem(self.__legend__) del self.__legend__ self.__legend__ = None if value == '1': self.update_legend() if name == 'buffersize': self.config['buffersize']['value'] = value self.update_buffer_size(value) if name == 'yRange': self.config['yRange']['value'] = value self.use_range_for_y(value) # if name == 'legend_position': # self.pl_set_config_element('legend_position',value) # pos_re = re.compile(r'([0-9]+)') # self.__legend_position__ = pos_re.findall(value) # self.update_legend() # print('POS:', self.__parameters__['legend_position'].value) def update_pens(self): """ Function update pens :return: """ for signal_name in self.signals.keys(): signal_id = self.signals[signal_name].id new_pen = self.get_pen(signal_id) other_pen = self.get_pen(signal_id) o_color = other_pen.color() o_color.setAlpha(100) other_pen.setColor(o_color) self.signals[signal_name].pen = new_pen self.signals[signal_name].other_pen = other_pen def update_plot(self): """ Function update_plot :return: """ if len(self.__tbuffer__) == 0: return if not self.__rolling_plot__: tdata = list(self.__tbuffer__) if self.__rolling_plot__: tdata = list(range(0, len(self.__tbuffer__))) self.__append_at__ += self.signals[list(self.signals.keys())[0]].get_new_added_since_last_drawing() self.__append_at__ %= len(tdata) tdata = np.roll(tdata, -int(self.__append_at__)) now = pg.ptime.time() for signal_name in self.signals: # get all no more needed graphic items graphics = self.signals[signal_name].get_old_graphics() for graphic in graphics: self.__plotWidget__.removeItem(graphic) # Create new new graphic items self.signals[signal_name].create_graphics(tdata) # Get new created graphic item and paint them graphics = self.signals[signal_name].get_graphics() for graphic in graphics: self.__plotWidget__.addItem(graphic) self.__last_plot_time__ = pg.ptime.time()-now if self.__rolling_plot__: self.__plotWidget__.getPlotItem().getViewBox().setXRange(0, len(tdata)-1) self.time_label.setNum(self.__tbuffer__[-1]) else: self.__plotWidget__.getPlotItem().getViewBox().setXRange(tdata[0], tdata[-1]) # if self.__papi_debug__: # print("Plot time: %0.5f sec" % (self.__last_plot_time__) ) def initiate_update_plot(self): """ To all needed changes to use default plotting :return: """ self.__stp_active__ = False if self.__rolling_plot__: self.time_label.setHidden(False) else: self.time_label.setHidden(True) pass def initiate_update_plot_single_timestamp(self): """ To all needed changes to use single timestamp plotting :return: """ self.__stp_active__ = True self.time_label.setHidden(False) def update_plot_single_timestamp(self, data): """ Function update_plot_single_timestamp :return: """ self.__plotWidget__.clear() cur_max_y = 0 cur_min_y = 1000 for signal_name in data: if signal_name not in [pc.CORE_TIME_SIGNAL, self.__plot_over__]: signal_data = data[signal_name] if signal_name in self.signals: tdata = np.linspace(1, len(signal_data), len(signal_data)) if len(data[self.__plot_over__]) == len(signal_data): plot_axis = data[self.__plot_over__] tdata = np.linspace(1, plot_axis[-1], len(plot_axis)) plot_item = self.signals[signal_name] if len(tdata) == 1: graphic = GraphicItem(np.array([self.__stp_min_x, self.__stp_max_x]), np.array([signal_data[0], signal_data[0]]), 0, pen=plot_item.pen) else: graphic = GraphicItem(np.array(tdata), np.array(signal_data), 0, pen=plot_item.pen) self.__plotWidget__.addItem(graphic) self.__stp_max_x = max(self.__stp_max_x, max(tdata)) self.__stp_min_x = min(self.__stp_min_x, min(tdata)) cur_max_y = max(cur_max_y, max(signal_data)) cur_min_y = min(cur_min_y, min(signal_data)) self.__stp_max_y = cur_max_y self.__stp_min_y = cur_min_y self.__plotWidget__.getPlotItem().getViewBox().setXRange(self.__stp_min_x, self.__stp_max_x) self.time_label.setNum(data[CORE_TIME_SIGNAL][0]) def update_buffer_size(self, new_size): """ Function set buffer size :param new_size: :return: """ self.__buffer_size__ = int(new_size) start_size = len(self.__tbuffer__) for signal_name in self.signals: self.__tbuffer__ = collections.deque([0.0] * start_size, self.__buffer_size__) # COLLECTION plot_item = self.signals[signal_name] plot_item.max_elements = self.__buffer_size__ plot_item.clear() self.__plotWidget__.clear() self.update_rolling_plot() self.__new_added_data__ = 0 def cb_plugin_meta_updated(self): """ This function is called whenever meta information are changed. This enables the plot to handle more than one input for plotting. :return: """ dp_info = self.pl_get_dplugin_info() subscriptions = dp_info.get_subscribtions() changes = False current_signals = {} index = 0 for dpluginsub_id in subscriptions: for dblock_name in subscriptions[dpluginsub_id]: # get subscription for dblock subscription = subscriptions[dpluginsub_id][dblock_name] for signal_name in subscription.get_signals(): if signal_name not in [pc.CORE_TIME_SIGNAL, self.__plot_over__]: signal = subscription.get_dblock().get_signal_by_uname(signal_name) current_signals[signal_name] = {} current_signals[signal_name]['signal'] = signal current_signals[signal_name]['index'] = index index += 1 # ---------------------------- # Add new subscribed signals # ---------------------------- for signal_name in sorted(current_signals.keys()): if signal_name not in [pc.CORE_TIME_SIGNAL, self.__plot_over__]: if signal_name not in self.signals: signal = current_signals[signal_name]['signal'] self.add_plot_item(signal, current_signals[signal_name]['index']) changes = True # ------------------------------- # Remove unsubscribed signals # ------------------------------- for signal_name in self.signals.copy(): if signal_name not in current_signals: if self.__legend__ is not None: self.remove_plot_item(signal_name) changes = True if changes: self.update_pens() self.update_signals() self.update_legend() self.update_rolling_plot() self.update_downsampling_rate() self.update_parameters() else: self.update_signals() #self.update_legend() def add_plot_item(self, signal, signal_id): """ Create a new plot item object for a given signal and internal id :param signal: DSignal object :param signal_id: plot internal signal id :return: """ signal_name = signal.uname if signal_name not in self.signals: self.signals[signal_name] = {} plot_item = PlotItem(signal, signal_id, self.__buffer_size__) plot_item.set_downsampling_rate(self.__downsampling_rate__) self.signals[signal_name] = plot_item def remove_plot_item(self, signal_name): """ Remove the plot item object for a given signal_name. :param signal_name: :return: """ if signal_name in self.signals: plot_item = self.signals[signal_name] # Remove all graphic objects for graphic in plot_item.graphics: self.__plotWidget__.removeItem(graphic) # Remove from Legend self.__legend__.removeItem(plot_item.signal_name) del self.signals[signal_name] def get_pen(self, index): """ Function get pen :param index: :return: """ index = int(index) style_index = index % len(self.__styles_selected__) style_code = int(self.__styles_selected__[style_index]) width_index = index % len(self.__width_selected__) width_code = int(self.__width_selected__[width_index]) color_index = index % len(self.__colors_selected__) color_code = int(self.__colors_selected__[color_index]) if style_code in self.styles: style = self.styles[style_code] else: style = self.styles[0] if color_code in self.colors: color = self.colors[color_code] else: color = self.colors[0] if width_code < 0: width_code = 0 return pg.mkPen(color=color, style=style, width=width_code) def update_rolling_plot(self): """ Used to update the rolling plot by resolving all dependencies. The configuration for the rolling plot depends on the current value in self.config['rolling_plot']['value'] :return: """ value = self.config['rolling_plot']['value'] self.__rolling_plot__ = int(float(self.config['rolling_plot']['value'])) == int('1') self.rolling_Checkbox.stateChanged.disconnect() self.rolling_Checkbox.setChecked(value == '1') self.rolling_Checkbox.stateChanged.connect(self.contextMenu_rolling_toogled) self.clear() for signal_name in self.signals: self.signals[signal_name].rolling_plot = self.__rolling_plot__ self.initiate_update_plot() def update_parameters(self): parameter_style = self.__parameters__['style'] parameter_width = self.__parameters__['width'] parameter_color = self.__parameters__['color'] int_re = re.compile(r'(\d+)') # Styles current_styles = int_re.findall(parameter_style.value) original_style = int_re.findall(self.startup_config['style']['value']) # Width current_width = int_re.findall(parameter_width.value) original_width = int_re.findall(self.startup_config['width']['value']) # Color current_color = int_re.findall(parameter_color.value) original_color = int_re.findall(self.startup_config['color']['value']) min_len = min(len(current_styles), len(current_width), len(current_color)) if len(self.signals) < min_len: style_new = current_styles[0:len(self.signals)] width_new = current_width[0:len(self.signals)] color_new = current_color[0:len(self.signals)] else: style_new = current_styles width_new = current_width color_new = current_color if len(self.signals) < len(original_style): style_new.extend(original_style[min_len:min_len+len(self.signals)-1]) width_new.extend(original_width[min_len:min_len+len(self.signals)-1]) color_new.extend(original_color[min_len:min_len+len(self.signals)-1]) else: style_new.extend([0] * (len(self.signals)-len(original_style))) width_new.extend([0] * (len(self.signals)-len(original_style))) color_new.extend([0] * (len(self.signals)-len(original_style))) style_new = '[' + ' '.join(str(x) for x in style_new) + ']' width_new = '[' + ' '.join(str(x) for x in width_new) + ']' color_new = '[' + ' '.join(str(x) for x in color_new) + ']' parameter_style.value = str(style_new) parameter_width.value = str(width_new) parameter_color.value = str(color_new) self.control_api.do_set_parameter(self.__id__, parameter_style.name, parameter_style.value) self.control_api.do_set_parameter(self.__id__, parameter_width.name, parameter_width.value) self.control_api.do_set_parameter(self.__id__, parameter_color.name, parameter_color.value) def use_range_for_x(self, value): """ :param value: :return: """ reg = re.compile(r'(\d+\.\d+)') range = reg.findall(value) if len(range) == 2: #self.xRange_minEdit.setText(range[0]) #self.xRange_maxEdit.setText(range[1]) self.__plotWidget__.getPlotItem().getViewBox().setXRange(float(range[0]),float(range[1])) def use_range_for_y(self, value): """ :param value: :return: """ reg = re.compile(r'([-]{0,1}\d+\.\d+)') range = reg.findall(value) if len(range) == 2: self.yRange_minEdit.setText(range[0]) self.yRange_maxEdit.setText(range[1]) self.__plotWidget__.getPlotItem().getViewBox().setYRange(float(range[0]), float(range[1])) def setup_context_menu(self): """ :return: """ self.custMenu = QMenu("Options") self.axesMenu = QMenu('Y-Axis') self.gridMenu = QMenu('Grid') ##### Y-Range Actions self.yRange_Widget = QWidget() self.yRange_Layout = QVBoxLayout(self.yRange_Widget) self.yRange_Layout.setContentsMargins(2, 2, 2, 2) self.yRange_Layout.setSpacing(1) self.yAutoRangeButton = QPushButton() self.yAutoRangeButton.clicked.connect(self.contextMenu_yAutoRangeButton_clicked) self.yAutoRangeButton.setText('Use autorange') self.yRange_Layout.addWidget(self.yAutoRangeButton) ##### Y Line Edits # Layout self.yRange_EditWidget = QWidget() self.yRange_EditLayout = QHBoxLayout(self.yRange_EditWidget) self.yRange_EditLayout.setContentsMargins(2, 2, 2, 2) self.yRange_EditLayout.setSpacing(1) # get old values; reg = re.compile(r'(\d+\.\d+)') range = reg.findall(self.config['yRange']['value']) if len(range) == 2: y_min = range[0] y_max = range[1] else: y_min = '0.0' y_max = '1.0' rx = QRegExp(r'([-]{0,1}\d+\.\d+)') validator = QRegExpValidator(rx, self.__plotWidget__) # Min self.yRange_minEdit = QLineEdit() self.yRange_minEdit.setFixedWidth(80) self.yRange_minEdit.setText(y_min) self.yRange_minEdit.editingFinished.connect(self.contextMenu_yRange_toogle) self.yRange_minEdit.setValidator(validator) # Max self.yRange_maxEdit = QLineEdit() self.yRange_maxEdit.setFixedWidth(80) self.yRange_maxEdit.setText(y_max) self.yRange_maxEdit.editingFinished.connect(self.contextMenu_yRange_toogle) self.yRange_maxEdit.setValidator(validator) # addTo Layout self.yRange_EditLayout.addWidget(self.yRange_minEdit) self.yRange_EditLayout.addWidget(QLabel('<')) self.yRange_EditLayout.addWidget(self.yRange_maxEdit) self.yRange_Layout.addWidget(self.yRange_EditWidget) # build Action self.yRange_Action = QWidgetAction(self.__plotWidget__) self.yRange_Action.setDefaultWidget(self.yRange_Widget) ##### Rolling Plot self.rolling_Checkbox = QCheckBox() self.rolling_Checkbox.setText('Rolling plot') self.rolling_Checkbox.setChecked(self.config['rolling_plot']['value'] == '1') self.rolling_Checkbox.stateChanged.connect(self.contextMenu_rolling_toogled) self.rolling_Checkbox_Action = QWidgetAction(self.__plotWidget__) self.rolling_Checkbox_Action.setDefaultWidget(self.rolling_Checkbox) if self.__stp_active__: self.rolling_Checkbox.setDisabled(True) # show legend self.legend_Checkbox = QCheckBox() self.legend_Checkbox.setText('Show legend') self.legend_Checkbox.setChecked(self.config['show_legend']['value'] == '1') self.legend_Checkbox.stateChanged.connect(self.contextMenu_legend_toogled) self.legend_Checkbox_Action = QWidgetAction(self.__plotWidget__) self.legend_Checkbox_Action.setDefaultWidget(self.legend_Checkbox) ##### Build axes menu #self.axesMenu.addAction(self.xRange_Action) self.axesMenu.addSeparator().setText("Y-Range") self.axesMenu.addAction(self.yRange_Action) # Grid Menu: # ----------------------------------------------------------- # Y-Grid checkbox self.xGrid_Checkbox = QCheckBox() self.xGrid_Checkbox.stateChanged.connect(self.contextMenu_xGrid_toogle) self.xGrid_Checkbox.setText('X-Grid') self.xGrid_Action = QWidgetAction(self.__plotWidget__) self.xGrid_Action.setDefaultWidget(self.xGrid_Checkbox) self.gridMenu.addAction(self.xGrid_Action) # Check config for startup state if self.__show_grid_x__: self.xGrid_Checkbox.setChecked(True) # X-Grid checkbox self.yGrid_Checkbox = QCheckBox() self.yGrid_Checkbox.stateChanged.connect(self.contextMenu_yGrid_toogle) self.yGrid_Checkbox.setText('Y-Grid') self.yGrid_Action = QWidgetAction(self.__plotWidget__) self.yGrid_Action.setDefaultWidget(self.yGrid_Checkbox) self.gridMenu.addAction(self.yGrid_Action) # Check config for startup state if self.__show_grid_y__: self.yGrid_Checkbox.setChecked(True) # add Menus self.custMenu.addMenu(self.axesMenu) self.custMenu.addMenu(self.gridMenu) self.custMenu.addSeparator().setText("Rolling Plot") self.custMenu.addAction(self.rolling_Checkbox_Action) self.custMenu.addAction(self.legend_Checkbox_Action) self.__plotWidget__.getPlotItem().getViewBox().menu.clear() if not self.__papi_debug__: self.__plotWidget__.getPlotItem().ctrlMenu = [self.pl_create_control_context_menu(), self.custMenu] def showContextMenu(self): self.setup_context_menu() def contextMenu_yAutoRangeButton_clicked(self): mi = None ma = None if self.__stp_active__: mi = self.__stp_min_y ma = self.__stp_max_y else: for sig in self.signals: graphics = self.signals[sig].graphics buf = [] for graphic in graphics: buf.extend(graphic.y) ma_buf = max(buf) mi_buf = min(buf) if ma is not None: if ma_buf > ma: ma = ma_buf else: ma = ma_buf if mi is not None: if mi_buf < mi: mi = mi_buf else: mi = mi_buf ma = str(float(ma)) mi = str(float(mi)) self.yRange_maxEdit.setText(ma) self.yRange_minEdit.setText(mi) self.control_api.do_set_parameter(self.__id__, 'yRange', '[' +mi + ' ' + ma + ']') def contextMenu_rolling_toogled(self): if self.rolling_Checkbox.isChecked(): self.control_api.do_set_parameter(self.__id__, 'rolling', '1') else: self.control_api.do_set_parameter(self.__id__, 'rolling', '0') def contextMenu_legend_toogled(self): if self.legend_Checkbox.isChecked(): self.control_api.do_set_parameter(self.__id__, 'show_legend', '1') else: self.control_api.do_set_parameter(self.__id__, 'show_legend', '0') def contextMenu_xGrid_toogle(self): if self.xGrid_Checkbox.isChecked(): self.control_api.do_set_parameter(self.__id__, 'x-grid', '1') else: self.control_api.do_set_parameter(self.__id__, 'x-grid', '0') def contextMenu_yGrid_toogle(self): if self.yGrid_Checkbox.isChecked(): self.control_api.do_set_parameter(self.__id__, 'y-grid', '1') else: self.control_api.do_set_parameter(self.__id__, 'y-grid', '0') def contextMenu_yRange_toogle(self): mi = self.yRange_minEdit.text() ma = self.yRange_maxEdit.text() if float(mi) < float(ma): self.control_api.do_set_parameter(self.__id__, 'yRange', '[' + mi + ' ' + ma + ']') def update_signals(self): """ Used to update the signals as they are described in self.dplugin_info :return: """ dp_info = self.pl_get_dplugin_info() subscriptions = dp_info.get_subscribtions() for dpluginsub_id in subscriptions: for dblock_name in subscriptions[dpluginsub_id]: # get subscription for dblock subscription = subscriptions[dpluginsub_id][dblock_name] for signal_name in subscription.get_signals(): if signal_name not in [pc.CORE_TIME_SIGNAL, self.__plot_over__]: signal = subscription.get_dblock().get_signal_by_uname(signal_name) self.signals[signal_name].update_signal(signal) def update_legend(self): """ Used to update the legend. :return: """ if not self.__show_legend__: return if self.__legend__ is not None: self.__legend__.scene().removeItem(self.__legend__) del self.__legend__ self.__legend__ = None self.__legend__ = self.__plotWidget__.getPlotItem().addLegend() if not self.__papi_debug__: self.update_signals() for signal_name in sorted(self.signals.keys()): graphic = self.signals[signal_name].get_legend_item() if graphic is not None: signal = self.signals[signal_name].signal legend_name = signal.dname self.__legend__.addItem(graphic, legend_name) self.__legend__.setPos(int(self.__legend_position__[0]),int(self.__legend_position__[1])) def update_downsampling_rate(self): """ Used to update the downsampling rate by resolving all dependencies. The new downsampling rate is taken by using the private attribute __downsampling_rate__. :return: """ rate = self.__downsampling_rate__ self.__downsampling_rate_start__ = 0 self.__downsampling_rate__ = rate for signal_name in self.signals: self.signals[signal_name].set_downsampling_rate(rate) def plot_yrange_changed(self): viewbox = self.__plotWidget__.getPlotItem().getViewBox() [xRange, yRange] = viewbox.viewRange() self.control_api.do_update_parameter(self.__id__, 'yRange', '[' + str(yRange[0]) + ' ' + str(yRange[1]) + ']') self.config['yRange']['value'] = '[' + str(yRange[0]) + ' ' + str(yRange[1]) + ']' def cb_quit(self): """ Function quit plugin :return: """ print('PlotPerformance: will quit') def debug_papi(self): config = self.get_cb_plugin_configuration() config['yRange'] = { 'value': '[0.0 50.0]', 'regex': '(\d+\.\d+)', 'advanced': '1', 'display_text': 'y: range' } config['buffersize'] = { 'value': '1000', 'regex': '(\d+\.\d+)', 'advanced': '1', 'display_text': 'y: range' } config['downsampling_rate'] = { 'value': '10', 'regex': '(\d+\.\d+)', 'advanced': '1', 'display_text': 'y: range' } self.config = config self.__id__ = 0 self.cb_initialize_plugin(config) signal_1 = DSignal('signal_1') signal_2 = DSignal('signal_2') signal_3 = DSignal('signal_3') signal_4 = DSignal('signal_4') signal_5 = DSignal('signal_5') self.add_plot_item(signal_1, 1) self.add_plot_item(signal_2, 2) self.add_plot_item(signal_3, 3) self.add_plot_item(signal_4, 4) self.add_plot_item(signal_5, 5) self.update_pens() self.update_legend() pass def cb_get_plugin_configuration(self): """ Function get plugin configuration :return {}: """ config = { 'x-grid': { 'value': "0", 'regex': '^(1|0)$', 'type': 'bool', 'display_text': 'Grid-X', 'advanced': 'Style' }, 'y-grid': { 'value': "0", 'regex': '^(1|0)$', 'type': 'bool', 'display_text': 'Grid-Y', 'advanced': 'Style' }, 'color': { 'value': "[0 1 2 3 4]", 'regex': '^\[(\s*\d\s*)+\]', 'advanced': 'Style', 'display_text': 'Color' }, 'style': { 'value': "[0 0 0 0 0]", 'regex': '^\[(\s*\d\s*)+\]', 'advanced': 'Style', 'display_text': 'Style' }, 'width': { 'value': "[0 0 0 0 0]", 'regex': '^\[(\s*\d\s*)+\]', 'advanced': 'Style', 'display_text': 'Width' }, 'buffersize': { 'value': "100", 'regex': '^(\d+)$', 'advanced': 'Data', 'display_text': 'Buffersize' }, 'downsampling_rate': { 'value': "1", 'regex': '(\d+)', 'advanced': 'Data' }, 'rolling_plot': { 'value': '0', 'regex': '^(1|0)$', 'type': 'bool', 'advanced': 'Data', 'display_text': 'Rolling Plot' }, 'yRange': { 'value': '[0.0 1.0]', 'regex': '^\[(\d+\.\d+)\s+(\d+\.\d+)\]$', 'advanced': 'Data', 'display_text': 'y: range' }, 'show_legend' : { 'value' : '1', 'regex' : pc.REGEX_BOOL_BIN, 'display_text' : 'Enable/Disable legend', 'type' : pc.CFG_TYPE_BOOL, 'advanced': 'Style' }, 'legend_position' : { 'value' : '(10,10)', 'regex': '\(([0-9]+),([0-9]+)\)', 'tooltip' : 'Set (X,Y) position of legend', 'display_text' : 'Legend position', 'advanced': 'Style' }, 'bgcol':{ 'value':'(0,0,0)', 'type': pc.CFG_TYPE_COLOR, 'advanced': 'Style' }, 'plot_over' : { 'advanced' : 'Data', 'value' : pc.CORE_TIME_SIGNAL, 'display_text' : 'Plot signals over this x-axis' } } # http://www.regexr.com/ return config def clear(self): """ :return: """ self.__plotWidget__.clear() self.__tbuffer__.clear() for signal_name in self.signals: self.signals[signal_name].clear() def parameter_callback_legend_position(self, value): self.pl_set_config_element('legend_position',value) pos_re = re.compile(r'([0-9]+)') self.__legend_position__ = pos_re.findall(value) self.update_legend()
def setup_context_menu(self): """ :return: """ self.custMenu = QMenu("Options") self.axesMenu = QMenu('Y-Axis') self.gridMenu = QMenu('Grid') ##### Y-Range Actions self.yRange_Widget = QWidget() self.yRange_Layout = QVBoxLayout(self.yRange_Widget) self.yRange_Layout.setContentsMargins(2, 2, 2, 2) self.yRange_Layout.setSpacing(1) self.yAutoRangeButton = QPushButton() self.yAutoRangeButton.clicked.connect(self.contextMenu_yAutoRangeButton_clicked) self.yAutoRangeButton.setText('Use autorange') self.yRange_Layout.addWidget(self.yAutoRangeButton) ##### Y Line Edits # Layout self.yRange_EditWidget = QWidget() self.yRange_EditLayout = QHBoxLayout(self.yRange_EditWidget) self.yRange_EditLayout.setContentsMargins(2, 2, 2, 2) self.yRange_EditLayout.setSpacing(1) # get old values; reg = re.compile(r'(\d+\.\d+)') range = reg.findall(self.config['yRange']['value']) if len(range) == 2: y_min = range[0] y_max = range[1] else: y_min = '0.0' y_max = '1.0' rx = QRegExp(r'([-]{0,1}\d+\.\d+)') validator = QRegExpValidator(rx, self.__plotWidget__) # Min self.yRange_minEdit = QLineEdit() self.yRange_minEdit.setFixedWidth(80) self.yRange_minEdit.setText(y_min) self.yRange_minEdit.editingFinished.connect(self.contextMenu_yRange_toogle) self.yRange_minEdit.setValidator(validator) # Max self.yRange_maxEdit = QLineEdit() self.yRange_maxEdit.setFixedWidth(80) self.yRange_maxEdit.setText(y_max) self.yRange_maxEdit.editingFinished.connect(self.contextMenu_yRange_toogle) self.yRange_maxEdit.setValidator(validator) # addTo Layout self.yRange_EditLayout.addWidget(self.yRange_minEdit) self.yRange_EditLayout.addWidget(QLabel('<')) self.yRange_EditLayout.addWidget(self.yRange_maxEdit) self.yRange_Layout.addWidget(self.yRange_EditWidget) # build Action self.yRange_Action = QWidgetAction(self.__plotWidget__) self.yRange_Action.setDefaultWidget(self.yRange_Widget) ##### Rolling Plot self.rolling_Checkbox = QCheckBox() self.rolling_Checkbox.setText('Rolling plot') self.rolling_Checkbox.setChecked(self.config['rolling_plot']['value'] == '1') self.rolling_Checkbox.stateChanged.connect(self.contextMenu_rolling_toogled) self.rolling_Checkbox_Action = QWidgetAction(self.__plotWidget__) self.rolling_Checkbox_Action.setDefaultWidget(self.rolling_Checkbox) if self.__stp_active__: self.rolling_Checkbox.setDisabled(True) # show legend self.legend_Checkbox = QCheckBox() self.legend_Checkbox.setText('Show legend') self.legend_Checkbox.setChecked(self.config['show_legend']['value'] == '1') self.legend_Checkbox.stateChanged.connect(self.contextMenu_legend_toogled) self.legend_Checkbox_Action = QWidgetAction(self.__plotWidget__) self.legend_Checkbox_Action.setDefaultWidget(self.legend_Checkbox) ##### Build axes menu #self.axesMenu.addAction(self.xRange_Action) self.axesMenu.addSeparator().setText("Y-Range") self.axesMenu.addAction(self.yRange_Action) # Grid Menu: # ----------------------------------------------------------- # Y-Grid checkbox self.xGrid_Checkbox = QCheckBox() self.xGrid_Checkbox.stateChanged.connect(self.contextMenu_xGrid_toogle) self.xGrid_Checkbox.setText('X-Grid') self.xGrid_Action = QWidgetAction(self.__plotWidget__) self.xGrid_Action.setDefaultWidget(self.xGrid_Checkbox) self.gridMenu.addAction(self.xGrid_Action) # Check config for startup state if self.__show_grid_x__: self.xGrid_Checkbox.setChecked(True) # X-Grid checkbox self.yGrid_Checkbox = QCheckBox() self.yGrid_Checkbox.stateChanged.connect(self.contextMenu_yGrid_toogle) self.yGrid_Checkbox.setText('Y-Grid') self.yGrid_Action = QWidgetAction(self.__plotWidget__) self.yGrid_Action.setDefaultWidget(self.yGrid_Checkbox) self.gridMenu.addAction(self.yGrid_Action) # Check config for startup state if self.__show_grid_y__: self.yGrid_Checkbox.setChecked(True) # add Menus self.custMenu.addMenu(self.axesMenu) self.custMenu.addMenu(self.gridMenu) self.custMenu.addSeparator().setText("Rolling Plot") self.custMenu.addAction(self.rolling_Checkbox_Action) self.custMenu.addAction(self.legend_Checkbox_Action) self.__plotWidget__.getPlotItem().getViewBox().menu.clear() if not self.__papi_debug__: self.__plotWidget__.getPlotItem().ctrlMenu = [self.pl_create_control_context_menu(), self.custMenu]
def initToolbar(self, webview): pass ###使用QToolBar创建导航栏,并使用QAction创建按钮 # 添加导航栏 self.navigation_bar = QToolBar('Navigation') # 锁定导航栏 self.navigation_bar.setMovable(False) # 设定图标的大小 self.navigation_bar.setIconSize(QSize(2, 2)) # 添加导航栏到窗口中 self.addToolBar(self.navigation_bar) # 添加其它配置 self.navigation_bar.setObjectName("navigation_bar") self.navigation_bar.setCursor(Qt.ArrowCursor) # QAction类提供了抽象的用户界面action,这些action可以被放置在窗口部件中 # 添加前进、后退、停止加载和刷新的按钮 self.reload_icon = unichr(0xf2f9) self.stop_icon = unichr(0xf00d) # 后退按钮 self.back_action = QWidgetAction(self) self.back_button = QPushButton(unichr(0xf060), self, clicked=webview.back, font=fontawesome("far"), objectName='back_button') self.back_button.setToolTip("后退") self.back_button.setCursor(Qt.ArrowCursor) self.back_action.setDefaultWidget(self.back_button) # 前进按钮 self.next_action = QWidgetAction(self) self.next_button = QPushButton(unichr(0xf061), self, clicked=webview.forward, font=fontawesome("far"), objectName='next_button') self.next_button.setToolTip("前进") self.next_button.setCursor(Qt.ArrowCursor) self.next_action.setDefaultWidget(self.next_button) # 刷新与停止按钮 self.reload_action = QWidgetAction(self) self.reload_button = QPushButton(self.reload_icon, self, clicked=webview.reload, font=fontawesome("far"), objectName='reload_button') self.reload_button.setToolTip("刷新") self.reload_button.setCursor(Qt.ArrowCursor) self.reload_action.setDefaultWidget(self.reload_button) # 放大按钮 self.zoom_in_button = QPushButton(unichr(0xf067), self, clicked=self.zoom_in_func, font=fontawesome("far"), objectName='zoom_in_btn') self.zoom_in_button.setToolTip("放大") self.zoom_in_button.setCursor(Qt.ArrowCursor) # 缩小按钮 self.zoom_out_button = QPushButton(unichr(0xf068), self, clicked=self.zoom_out_func, font=fontawesome("far"), objectName='zoom_out_btn') self.zoom_out_button.setToolTip("缩小") self.zoom_out_button.setCursor(Qt.ArrowCursor) self.sf_label_rate = QLabel() self.sf_label_rate.setObjectName("sf_label_rate") self.sf_label_rate.setFixedWidth(30) self.sf_label_rate.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter) self.sf_label_rate.setProperty("class","qlabel") self.sf_label_rate.setText(str(int(self.webview.zoomFactor()*100))+"%") # 全屏按钮 self.full_screen_button = QPushButton(unichr(0xe140), self, clicked=self.full_screen_func, font=fontawesome("boot"), objectName='full_screen_button') self.full_screen_button.setToolTip("全屏") self.full_screen_button.setCursor(Qt.ArrowCursor) # 其它按钮 self.more_action = QWidgetAction(self) self.more_button = QPushButton(unichr(0xe235), self, clicked=self.moreMenuShow, font=fontawesome("boot"), objectName='more_button') self.more_button.setToolTip("页面控制及浏览器核心") self.more_button.setCursor(Qt.ArrowCursor) self.more_action.setDefaultWidget(self.more_button) # 首页按钮 self.index_action = QWidgetAction(self) self.index_button = QPushButton(unichr(0xf015), self, # clicked=self.zoom_out_func, font=fontawesome("far"), objectName='index_button') self.index_button.setToolTip("主页") self.index_button.setCursor(Qt.ArrowCursor) self.index_action.setDefaultWidget(self.index_button) # self.back_button.triggered.connect(webview.back) # self.next_button.triggered.connect(webview.forward) # self.reload_button.triggered.connect(webview.reload) # self.zoom_in_btn.triggered.connect(self.zoom_in_func) # self.zoom_out_btn.triggered.connect(self.zoom_out_func) # 将按钮添加到导航栏上 self.navigation_bar.addAction(self.back_action) self.navigation_bar.addAction(self.next_action) self.navigation_bar.addAction(self.reload_action) self.navigation_bar.addAction(self.index_action) # 添加URL地址栏 self.urlbar = QLineEdit() # 让地址栏能响应回车按键信号 self.urlbar.returnPressed.connect(self.navigate_to_url) # self.navigation_bar.addSeparator() self.navigation_bar.addWidget(self.urlbar) # self.navigation_bar.addSeparator() # self.navigation_bar.addAction(self.zoom_in_action) # self.navigation_bar.addAction(self.zoom_out_action) self.navigation_bar.addAction(self.more_action) # 让浏览器相应url地址的变化 webview.urlChanged.connect(self.renew_urlbar) webview.loadProgress.connect(self.processLoad) webview.loadStarted.connect(self.loadPage) webview.loadFinished.connect(self.loadFinish) webview.titleChanged.connect(self.renew_title) webview.iconChanged.connect(self.renew_icon) self.webBind() webview.show() self.navigation_bar.setIconSize(QSize(20, 20)) self.urlbar.setFont(QFont('SansSerif', 13))
class Browser(QMainWindow): def __init__(self, mainWin, webview=None): super().__init__(mainWin) self.showFullScreen() self.mainWin = mainWin self.webview = webview self.initUI() def initUI(self): global CREATE_BROWER # print("initUI") # self.setWindowFlags(Qt.FramelessWindowHint) # 去掉标题栏的代码 # 设置窗口标题 # self.setWindowTitle('LingBrowser') # 设置窗口图标 self.setWindowIcon(QIcon(':/icons/logo.png')) self.page = QWebEnginePage() self.page.settings().setAttribute(QWebEngineSettings.PluginsEnabled, True) # 支持视频播放 self.page.settings().setAttribute(QWebEngineSettings.JavascriptEnabled, True) self.page.settings().setAttribute(QWebEngineSettings.FullScreenSupportEnabled, True) if self.webview == None: # 初始化一个 tab self.webview = WebView(self) # self必须要有,是将主窗口作为参数,传给浏览器 self.page.setUrl(QUrl(HOME_PAGE)) self.page.windowCloseRequested.connect(self.on_windowCloseRequested) # 页面关闭请求 if CREATE_BROWER: CREATE_BROWER = False self.page.profile().downloadRequested.connect(self.on_downloadRequested) # 页面下载请求 self.t = WebEngineUrlRequestInterceptor() self.page.profile().setRequestInterceptor(self.t) self.webview.setPage(self.page) self.url = self.webview.page().url() self.initToolbar(self.webview) self.setCentralWidget(self.webview) self.center() def on_downloadRequested(self, downloadItem): # print("download..") # print(downloadItem.downloadFileName()) # print('isFinished', downloadItem.isFinished()) # print('isPaused', downloadItem.isPaused()) # print('isSavePageDownload', downloadItem.isSavePageDownload()) # print('path', downloadItem.path()) # print('url', downloadItem.url()) downloadFileName, ok2 = QFileDialog.getSaveFileName(self, "文件保存", downloadItem.path(), "All Files (*)") print(downloadItem.path()) downloadItem.setPath(downloadFileName) downloadItem.accept() downloadItem.finished.connect(self.on_downloadfinished) downloadItem.downloadProgress.connect(self.on_downloadProgress) def on_downloadfinished(self): print() def on_downloadProgress(self, int_1, int_2): rate = str(round(int_1 / int_2, 2) * 100).split(".")[0] self.mainWin.statusBarDownloadLabel.setText("文件下载 " + rate + "%") if int(rate) == 100: self.mainWin.statusBarDownloadLabel.setHidden(True) self.mainWin.statusBar.setHidden(True) else: self.mainWin.statusBarDownloadLabel.setHidden(False) self.mainWin.statusBar.setHidden(False) def on_windowCloseRequested(self): print("close tab") # self.webview.close() # del self.webview # sip.delete(self.webview) # self.webview # self.webview.page().profile().deleteLater() # self.deleteLater() pass def moreMenuShow(self): try: self.contextMenu = QMenu() self.contextMenu.setObjectName("moreMenu") self.contextMenu.setFont(fontawesome("far")) # self.actionA = self.contextMenu.addAction(self.zoom_in_action) # self.actionA = self.contextMenu.addAction(self.zoom_out_action) self.contextMenu.popup( QPoint(self.mainWin.x() + self.more_button.x() - 200, self.mainWin.y() + 75)) # 2菜单显示的位置 QCursor.pos() # print(self.more_button.x()) # print(self.more_button.y()) # print(self.frameGeometry()) # print(self.mainWin.x()) # print(self.mainWin.y()) self.contextMenu.setContentsMargins(25,0,0,0) self.contextMenu.addMenu("打印") self.contextMenu.addSeparator() # 缩放组合 sf_widget = QWidget(self) sf_widget.setProperty("class","qwidget") sf_widget.setObjectName("sf_widget") sf_widget.setContentsMargins(0,0,0,0) # sf_widget.setFixedHeight(20) sf_layout = QHBoxLayout() sf_layout.setContentsMargins(0,0,0,0) sf_widget.setLayout(sf_layout) sf_label = QLabel("缩放") sf_label.setObjectName("sf_item_label") sf_layout.addWidget(sf_label) sf_layout.addWidget(self.zoom_out_button) sf_layout.addWidget(self.sf_label_rate) sf_layout.addWidget(self.zoom_in_button) sf_layout.addWidget(self.full_screen_button) sf_action = QWidgetAction(self) sf_action.setDefaultWidget(sf_widget) self.actionA = self.contextMenu.addAction(sf_action) # self.actionA.triggered.connect(self.actionHandler) sf_layout.setSpacing(0) self.contextMenu.show() except Exception as e: print(e) def initToolbar(self, webview): pass ###使用QToolBar创建导航栏,并使用QAction创建按钮 # 添加导航栏 self.navigation_bar = QToolBar('Navigation') # 锁定导航栏 self.navigation_bar.setMovable(False) # 设定图标的大小 self.navigation_bar.setIconSize(QSize(2, 2)) # 添加导航栏到窗口中 self.addToolBar(self.navigation_bar) # 添加其它配置 self.navigation_bar.setObjectName("navigation_bar") self.navigation_bar.setCursor(Qt.ArrowCursor) # QAction类提供了抽象的用户界面action,这些action可以被放置在窗口部件中 # 添加前进、后退、停止加载和刷新的按钮 self.reload_icon = unichr(0xf2f9) self.stop_icon = unichr(0xf00d) # 后退按钮 self.back_action = QWidgetAction(self) self.back_button = QPushButton(unichr(0xf060), self, clicked=webview.back, font=fontawesome("far"), objectName='back_button') self.back_button.setToolTip("后退") self.back_button.setCursor(Qt.ArrowCursor) self.back_action.setDefaultWidget(self.back_button) # 前进按钮 self.next_action = QWidgetAction(self) self.next_button = QPushButton(unichr(0xf061), self, clicked=webview.forward, font=fontawesome("far"), objectName='next_button') self.next_button.setToolTip("前进") self.next_button.setCursor(Qt.ArrowCursor) self.next_action.setDefaultWidget(self.next_button) # 刷新与停止按钮 self.reload_action = QWidgetAction(self) self.reload_button = QPushButton(self.reload_icon, self, clicked=webview.reload, font=fontawesome("far"), objectName='reload_button') self.reload_button.setToolTip("刷新") self.reload_button.setCursor(Qt.ArrowCursor) self.reload_action.setDefaultWidget(self.reload_button) # 放大按钮 self.zoom_in_button = QPushButton(unichr(0xf067), self, clicked=self.zoom_in_func, font=fontawesome("far"), objectName='zoom_in_btn') self.zoom_in_button.setToolTip("放大") self.zoom_in_button.setCursor(Qt.ArrowCursor) # 缩小按钮 self.zoom_out_button = QPushButton(unichr(0xf068), self, clicked=self.zoom_out_func, font=fontawesome("far"), objectName='zoom_out_btn') self.zoom_out_button.setToolTip("缩小") self.zoom_out_button.setCursor(Qt.ArrowCursor) self.sf_label_rate = QLabel() self.sf_label_rate.setObjectName("sf_label_rate") self.sf_label_rate.setFixedWidth(30) self.sf_label_rate.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter) self.sf_label_rate.setProperty("class","qlabel") self.sf_label_rate.setText(str(int(self.webview.zoomFactor()*100))+"%") # 全屏按钮 self.full_screen_button = QPushButton(unichr(0xe140), self, clicked=self.full_screen_func, font=fontawesome("boot"), objectName='full_screen_button') self.full_screen_button.setToolTip("全屏") self.full_screen_button.setCursor(Qt.ArrowCursor) # 其它按钮 self.more_action = QWidgetAction(self) self.more_button = QPushButton(unichr(0xe235), self, clicked=self.moreMenuShow, font=fontawesome("boot"), objectName='more_button') self.more_button.setToolTip("页面控制及浏览器核心") self.more_button.setCursor(Qt.ArrowCursor) self.more_action.setDefaultWidget(self.more_button) # 首页按钮 self.index_action = QWidgetAction(self) self.index_button = QPushButton(unichr(0xf015), self, # clicked=self.zoom_out_func, font=fontawesome("far"), objectName='index_button') self.index_button.setToolTip("主页") self.index_button.setCursor(Qt.ArrowCursor) self.index_action.setDefaultWidget(self.index_button) # self.back_button.triggered.connect(webview.back) # self.next_button.triggered.connect(webview.forward) # self.reload_button.triggered.connect(webview.reload) # self.zoom_in_btn.triggered.connect(self.zoom_in_func) # self.zoom_out_btn.triggered.connect(self.zoom_out_func) # 将按钮添加到导航栏上 self.navigation_bar.addAction(self.back_action) self.navigation_bar.addAction(self.next_action) self.navigation_bar.addAction(self.reload_action) self.navigation_bar.addAction(self.index_action) # 添加URL地址栏 self.urlbar = QLineEdit() # 让地址栏能响应回车按键信号 self.urlbar.returnPressed.connect(self.navigate_to_url) # self.navigation_bar.addSeparator() self.navigation_bar.addWidget(self.urlbar) # self.navigation_bar.addSeparator() # self.navigation_bar.addAction(self.zoom_in_action) # self.navigation_bar.addAction(self.zoom_out_action) self.navigation_bar.addAction(self.more_action) # 让浏览器相应url地址的变化 webview.urlChanged.connect(self.renew_urlbar) webview.loadProgress.connect(self.processLoad) webview.loadStarted.connect(self.loadPage) webview.loadFinished.connect(self.loadFinish) webview.titleChanged.connect(self.renew_title) webview.iconChanged.connect(self.renew_icon) self.webBind() webview.show() self.navigation_bar.setIconSize(QSize(20, 20)) self.urlbar.setFont(QFont('SansSerif', 13)) def zoom_in_func(self): self.webview.setZoomFactor(self.webview.zoomFactor() + 0.1) self.sf_label_rate.setText(str(int(self.webview.zoomFactor()*100))+"%") def zoom_out_func(self): self.webview.setZoomFactor(self.webview.zoomFactor() - 0.1) self.sf_label_rate.setText(str(int(self.webview.zoomFactor()*100))+"%") def full_screen_func(self): self.navigation_bar.setHidden(True) self.mainWin.titleBar.setHidden(True) self.mainWin.showFullScreen() def on_network_call(self, info): print(info) pass def loadPage(self): # print("loadPage") # print(self.webview.objectName()) # self.renew_title("空页面") index = self.mainWin.tabWidget.currentIndex() self.mainWin.tabWidget.setTabIcon(index, QIcon(":icons/earth_128.png")) # self.reload_button.setDefaultWidget(self.stop_button_icon) self.reload_button.setText(self.stop_icon) self.reload_button.setToolTip("停止") def processLoad(self, rate): self.mainWin.statusBarLabelProgress.setValue(rate) self.mainWin.statusBarLabel.setText("网页加载") if rate == 0: self.mainWin.statusBarLabelProgress.setMaximum(0) self.mainWin.statusBarLabelProgress.setMinimum(0) else: self.mainWin.statusBarLabelProgress.setMaximum(0) self.mainWin.statusBarLabelProgress.setMinimum(100) if rate == 100: self.mainWin.statusBarLabelProgress.setHidden(True) self.mainWin.statusBarLabel.setHidden(True) self.mainWin.statusBar.setHidden(True) else: self.mainWin.statusBarLabelProgress.setHidden(False) self.mainWin.statusBarLabel.setHidden(False) self.mainWin.statusBar.setHidden(False) pass def loadFinish(self, isEnd): if isEnd: # print("load finished", isEnd) # self.reload_button.setDefaultWidget(self.reload_button_icon) self.reload_button.setText(self.reload_icon) self.reload_button.setToolTip("刷新") else: # print("load finished", isEnd) # print("load finished",isEnd) pass # index = self.webview.objectName() # title = self.page.title() # print("title", title) try: url = self.page.url().toString() except BaseException as base: url = self.webview.page().url().toString() # self.mainWin.tabWidget.setTabText(int(index), title if title else url) self.urlbar.setText(url) def webBind(self): # print("webBind") # self.back_button.disconnect() # self.next_button.disconnect() # self.stop_button.disconnect() # self.reload_button.disconnect() # self.add_button.disconnect() # self.back_button.triggered.connect(self.webview.back) # self.next_button.triggered.connect(self.webview.forward) # self.stop_button.triggered.connect(self.webview.stop) # self.reload_button.triggered.connect(self.webview.reload) # self.add_button.triggered.connect(self.mainWin.newTab) self.webview.urlChanged.connect(self.renew_urlbar) self.webview.titleChanged.connect(self.renew_title) self.webview.iconChanged.connect(self.renew_icon) def navigate_to_url(self): q = QUrl(self.urlbar.text()) if q.scheme() == '': q.setScheme('http') self.webview.setUrl(q) def renew_urlbar(self, url): # 将当前网页的链接更新到地址栏 # print("renew_urlbar") self.urlbar.setText(url.toString()) self.urlbar.setCursorPosition(0) # print("url", url)f def renew_title(self, title): # 将当前网页的标题更新到标签栏 index = self.webview.objectName() self.mainWin.tabWidget.setTabToolTip(int(index), title) title = " " + title[:11] + ".." if len(title) >= 12 else " " + title self.mainWin.tabWidget.setTabText(int(index), title) pass def renew_icon(self, icon): # 将当前网页的图标更新到标签栏 # print("renew_icon") index = self.webview.objectName() self.mainWin.tabWidget.setTabIcon(int(index), icon) def center(self): # print("center") qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) # 创建tab def create_tab(self, webview): # print("create_tab") self.tab = QWidget() self.mainWin.tabWidget.addTab(self.tab, "新标签页") self.mainWin.tabWidget.setCurrentWidget(self.tab) index = self.mainWin.tabWidget.currentIndex() # self.mainWin.tabWidget.setTabIcon(index, ":icons/logo.png") ##### self.Layout = QVBoxLayout(self.tab) self.Layout.setContentsMargins(0, 0, 0, 0) self.Layout.addWidget(Browser(self.mainWin, webview=webview)) webview.setObjectName(str(index)) self.mainWin.tab_[str(index)] = webview self.tab.setObjectName("tab_" + str(index))
def _menu(self, event) -> None: """Returns a new QMenu for system tray.""" menu = QMenu() menu.setAttribute(Qt.WA_DeleteOnClose) menu.addSeparator() parser_toggles = set() parsers = QMenu("Toggles") for parser in self._parsers: toggle: QAction = parsers.addAction(parser.name.title()) toggle.setCheckable(True) toggle.setChecked(profile.__dict__[parser.name].toggled) parser_toggles.add(toggle) parsers.addAction(toggle) menu.addMenu(parsers) menu.addSeparator() profiles = QMenu(profile.name if profile.name else "Profile") level_select = QWidgetAction(profiles) w = QWidget() layout = QHBoxLayout() spinbox = QSpinBox() spinbox.setMaximum(65) spinbox.setMinimum(1) spinbox.setMaximumWidth(100) spinbox.setValue(profile.spells.level) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(QLabel("Level"), stretch=1) layout.addWidget(spinbox, stretch=0) w.setLayout(layout) level_select.setDefaultWidget(w) profiles.addAction(level_select) menu.addMenu(profiles) menu.addSeparator() settings_action = menu.addAction("Settings") lock_toggle = menu.addAction( "Unlock Windows" if self._locked else "Lock Windows") # check online for new version new_version_text = "" if is_new_version_available(ONLINE_VERSION, CURRENT_VERSION): new_version_text = "Update Available {}".format(ONLINE_VERSION) else: new_version_text = "Version {}".format(CURRENT_VERSION) check_version_action = menu.addAction(new_version_text) menu.addSeparator() quit_action = menu.addAction("Quit") action = menu.exec(QCursor.pos()) # change level if it was changed if spinbox.value() != profile.spells.level: profile.spells.level = spinbox.value() if action == check_version_action: webbrowser.open("https://github.com/nomns/nparse/releases") elif action == settings_action: if not self._settings.isVisible(): self._settings.set_values() self._settings.setWindowTitle( f"Settings (Profile: {profile.name})") if self._settings.exec(): self._settings.save_settings() # Update required settings for parser in self._parsers: parser.settings_updated() if self._toggled: self._toggle() self._toggle() else: self._settings.set_values() # revert values else: self._settings.activateWindow() elif action == quit_action: if self._toggled: self._toggle() # save parser geometry self.save_geometry() app_config.save() profile.save() self._system_tray.setVisible(False) self.quit() elif action in parser_toggles: if not self._locked: self.lock_toggle() parser = [ parser for parser in self._parsers if parser.name == action.text().lower() ][0] parser.toggle() elif action == lock_toggle: self.lock_toggle()
def __init__(self, parent=None): super(MovieWidget, self).__init__(parent) mini = True self.parent = parent self.isVideoAvailable = False self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) self.mediaPlayer.videoAvailableChanged.connect( self.videoAvailableChanged) videoWidget = QVideoWidget(self) videoWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.setContextMenuPolicy(Qt.CustomContextMenu) # Context Menu self.customContextMenuRequested.connect(self.openContextMenu) self.contextMenu = QMenu() self.openAction = self.contextMenu.addAction("Open file") icon = QIcon(self.style().standardIcon(QStyle.SP_DialogOpenButton)) self.openAction.setIcon(icon) self.urlAction = self.contextMenu.addAction("Open stream") icon = QIcon(self.style().standardIcon(QStyle.SP_DirLinkIcon)) self.urlAction.setIcon(icon) self.playAction = self.contextMenu.addAction("Play/Pause") icon = QIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playAction.setEnabled(False) self.playAction.setIcon(icon) self.closeAction = self.contextMenu.addAction("Close") icon = QIcon(self.style().standardIcon(QStyle.SP_DialogCloseButton)) self.closeAction.setEnabled(False) self.closeAction.setIcon(icon) self.posSlider = QSlider(Qt.Horizontal) self.posSlider.setRange(0, 0) self.posSlider.sliderMoved.connect(self.setPosition) self.wac = QWidgetAction(self.contextMenu) self.wac.setDefaultWidget(self.posSlider) self.posAction = self.contextMenu.addAction(self.wac) self.lblFile = QLabel() self.wal = QWidgetAction(self.contextMenu) self.wal.setDefaultWidget(self.lblFile) self.posAction = self.contextMenu.addAction(self.wal) # Control box self.openButton = QPushButton() self.openButton.setIcon(self.style().standardIcon( QStyle.SP_DialogOpenButton)) self.openButton.clicked.connect(self.openFile) self.urlButton = QPushButton() self.urlButton.setIcon(self.style().standardIcon( QStyle.SP_DirLinkIcon)) self.urlButton.clicked.connect(self.openURL) self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.clicked.connect(self.play) self.positionSlider = QSlider(Qt.Horizontal) self.positionSlider.setRange(0, 0) self.positionSlider.sliderMoved.connect(self.setPosition) self.errorLabel = QLabel() self.errorLabel.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) # Create layouts to place inside widget controlLayout = QHBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) controlLayout.addWidget(self.openButton) controlLayout.addWidget(self.urlButton) controlLayout.addWidget(self.playButton) controlLayout.addWidget(self.positionSlider) vLayout = QVBoxLayout() vLayout.setContentsMargins(0, 0, 0, 0) vLayout.addWidget(videoWidget) if mini != True: vLayout.addLayout(controlLayout) vLayout.addWidget(self.errorLabel) self.setLayout(vLayout) # Set widget to contain window contents self.mediaPlayer.setVideoOutput(videoWidget) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.durationChanged.connect(self.durationChanged) self.mediaPlayer.error.connect(self.handleError) self.resize(180, 100)
def __evt_yeahdoc_contextMenu(self, p): """ context menu """ item = self.yeahdoclisttree.currentItem() if item == None or item.isDisabled(): pass else: menu = QMenu() # menu top action = QWidgetAction(self) title = item.text(0) if len(title) < 25: for i in range(len(title), 25): title = title + " " action.setDefaultWidget( QLabel(" <img src='%s'/> %s" % (getPath("iconDir", "yeahdoc/item.png"), title))) menu.addAction(action) menu.addSeparator() menu.addAction(self.__actions["__yeahdoc_open__"]) menu.addAction(self.__actions["__yeahdoc_edit__"]) # change class change_class_menu = QMenu() entry = YeahdocDatasSupply().bb_read1_simple(item.getMark()) current_categoryid = entry['categoryid'] for class_item in YeahdocDatasSupply().bc_list(): action = QAction(class_item["title"], self, \ triggered=lambda re, item=item, categoryid=str(class_item["id"]): \ self.__evt_change_category(categoryid, item)) action.setIcon(QIcon(getPath("iconDir", "yeahdoc/flag/%s" % str(class_item["img"])))) action.setIconVisibleInMenu(True) # mark current class id menu checked if class_item['id'] == current_categoryid: action.setCheckable(True) action.setChecked(True) action.setDisabled(True) change_class_menu.addAction(action) action = QAction(QIcon(getPath("iconDir", "yeahdoc/change.png")), QApplication.translate("YeahdocList", "Change Category"), self) action.setIconVisibleInMenu(True) action.setMenu(change_class_menu) menu.addAction(action) menu.addAction(self.__actions["__yeahdoc_star__"]) menu.addAction(self.__actions["__yeahdoc_rename__"]) menu.addAction(self.__actions["__yeahdoc_delete__"]) menu.addSeparator() setmode = True if entry['lock'] == 0 else False action = QWidgetAction(self) widget = QWidget() layout = QHBoxLayout() layout.setSpacing(0) layout.setMargin(0) widget.setLayout(layout) widgetMore = QWidget() widgetMore.setVisible(False) layoutMore = QHBoxLayout() layoutMore.setSpacing(0) layoutMore.setMargin(0) widgetMore.setLayout(layoutMore) layout.addWidget(QLabel("<img src='%s'/>" % getPath("iconDir", "yeahdoc/password.png"))) passwordMore = QPushButton( QApplication.translate("YeahdocEditor", "Encrypt") if setmode else QApplication.translate( "YeahdocEditor", "Decrypt")) passwordMore.setFlat(True) layout.addWidget(passwordMore) passwordInput = QLineEdit() passwordInput.setEchoMode(QLineEdit.Password) passwordInput.setMaximumWidth(70) layoutMore.addWidget(passwordInput) if setmode: passwordInputAgain = QLineEdit() passwordInputAgain.setEchoMode(QLineEdit.Password) passwordInputAgain.setMaximumWidth(70) layoutMore.addWidget(QLabel(QApplication.translate("YeahdocEditor", "Re"))) layoutMore.addWidget(passwordInputAgain) passwordSubmit = QPushButton("OK") passwordSubmit.setFlat(True) layoutMore.addWidget(passwordSubmit) layout.addWidget(widgetMore) layout.addItem(QSpacerItem(0, 20, QSizePolicy.Expanding, QSizePolicy.Expanding)) action.setDefaultWidget(widget) QObject.connect(passwordSubmit, SIGNAL("clicked ()"), lambda: self.__evt_password(setmode, passwordInput.text(), passwordInputAgain.text() if setmode else "")) QObject.connect(passwordMore, SIGNAL("clicked ()"), lambda: widgetMore.setVisible(not widgetMore.isVisible())) menu.addAction(action) # show it. menu.exec_(self.mapToGlobal(self.yeahdoclisttree.mapTo(self, p)))
class MainWindow(QtWidgets.QMainWindow): save_perspective_action: QAction perspective_list_action: QWidgetAction perspective_combo_box: QComboBox dock_manager: QtAds.CDockManager def __init__(self, parent=None): super().__init__(parent) self.save_perspective_action = None self.perspective_list_action = None self.perspective_combo_box = None self.dock_manager = None self.setup_ui() self.dock_manager = QtAds.CDockManager(self) self.perspective_combo_box.activated[str].connect( self.dock_manager.openPerspective) self.create_content() self.resize(800, 600) self.restore_state() self.restore_perspectives() def setup_ui(self): self.setObjectName("MainWindow") self.resize(400, 300) self.setDockOptions(QtWidgets.QMainWindow.AllowTabbedDocks) self.centralWidget = QtWidgets.QWidget(self) self.centralWidget.setObjectName("centralWidget") self.setCentralWidget(self.centralWidget) self.status_bar = QtWidgets.QStatusBar(self) self.status_bar.setObjectName("statusBar") self.setStatusBar(self.status_bar) self.menu_bar = QtWidgets.QMenuBar(self) self.menu_bar.setGeometry(QRect(0, 0, 400, 21)) self.menu_bar.setObjectName("menuBar") self.menu_file = QtWidgets.QMenu(self.menu_bar) self.menu_file.setObjectName("menuFile") self.menu_view = QtWidgets.QMenu(self.menu_bar) self.menu_view.setObjectName("menuView") self.menu_about = QtWidgets.QMenu(self.menu_bar) self.menu_about.setObjectName("menuAbout") self.setMenuBar(self.menu_bar) self.tool_bar = QtWidgets.QToolBar(self) self.tool_bar.setObjectName("toolBar") self.addToolBar(Qt.TopToolBarArea, self.tool_bar) self.action_exit = QtWidgets.QAction(self) self.action_exit.setObjectName("actionExit") self.action_save_state = QtWidgets.QAction(self) self.action_save_state.setObjectName("actionSaveState") self.action_save_state.triggered.connect(self.saveState) self.action_restore_state = QtWidgets.QAction(self) self.action_restore_state.setObjectName("actionRestoreState") self.action_restore_state.triggered.connect(self.restore_state) self.menu_file.addAction(self.action_exit) self.menu_file.addAction(self.action_save_state) self.menu_file.addAction(self.action_restore_state) self.menu_bar.addAction(self.menu_file.menuAction()) self.menu_bar.addAction(self.menu_view.menuAction()) self.menu_bar.addAction(self.menu_about.menuAction()) self.setWindowTitle("MainWindow") self.menu_file.setTitle("File") self.menu_view.setTitle("View") self.menu_about.setTitle("About") self.tool_bar.setWindowTitle("toolBar") self.action_exit.setText("Exit") self.action_save_state.setText("Save State") self.action_restore_state.setText("Restore State") self.create_actions() def create_actions(self): ''' Creates the toolbar actions ''' self.tool_bar.addAction(self.action_save_state) self.action_save_state.setIcon(self.style().standardIcon( QStyle.SP_DialogSaveButton)) self.tool_bar.addAction(self.action_restore_state) self.action_restore_state.setIcon(self.style().standardIcon( QStyle.SP_DialogOpenButton)) self.save_perspective_action = QAction("Save Perspective", self) self.save_perspective_action.triggered.connect(self.save_perspective) self.perspective_list_action = QWidgetAction(self) self.perspective_combo_box = QComboBox(self) self.perspective_combo_box.setSizeAdjustPolicy( QComboBox.AdjustToContents) self.perspective_combo_box.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.perspective_list_action.setDefaultWidget( self.perspective_combo_box) self.tool_bar.addSeparator() self.tool_bar.addAction(self.perspective_list_action) self.tool_bar.addAction(self.save_perspective_action) def create_content(self): ''' Fill the dock manager with dock widgets ''' # Test container docking view_menu = self.menu_view dock_widget = create_calendar_dock_widget(view_menu) dock_widget.setIcon(self.style().standardIcon( QStyle.SP_DialogOpenButton)) dock_widget.setFeature(QtAds.CDockWidget.DockWidgetClosable, False) self.dock_manager.addDockWidget(QtAds.LeftDockWidgetArea, dock_widget) self.dock_manager.addDockWidget( QtAds.LeftDockWidgetArea, create_long_text_label_dock_widget(view_menu)) file_system_widget = create_file_system_tree_dock_widget(view_menu) tool_bar = file_system_widget.createDefaultToolBar() tool_bar.addAction(self.action_save_state) tool_bar.addAction(self.action_restore_state) self.dock_manager.addDockWidget(QtAds.BottomDockWidgetArea, file_system_widget) file_system_widget = create_file_system_tree_dock_widget(view_menu) tool_bar = file_system_widget.createDefaultToolBar() tool_bar.addAction(self.action_save_state) tool_bar.addAction(self.action_restore_state) file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetMovable, False) top_dock_area = self.dock_manager.addDockWidget( QtAds.TopDockWidgetArea, file_system_widget) dock_widget = create_calendar_dock_widget(view_menu) dock_widget.setFeature(QtAds.CDockWidget.DockWidgetClosable, False) dock_widget.setTabToolTip("Tab ToolTip\nHodie est dies magna") self.dock_manager.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, top_dock_area) # Test dock area docking right_dock_area = self.dock_manager.addDockWidget( QtAds.RightDockWidgetArea, create_long_text_label_dock_widget(view_menu), top_dock_area) self.dock_manager.addDockWidget( QtAds.TopDockWidgetArea, create_long_text_label_dock_widget(view_menu), right_dock_area) bottom_dock_area = self.dock_manager.addDockWidget( QtAds.BottomDockWidgetArea, create_long_text_label_dock_widget(view_menu), right_dock_area) self.dock_manager.addDockWidget( QtAds.RightDockWidgetArea, create_long_text_label_dock_widget(view_menu), right_dock_area) self.dock_manager.addDockWidget( QtAds.CenterDockWidgetArea, create_long_text_label_dock_widget(view_menu), bottom_dock_area) def save_state(self): ''' Saves the dock manager state and the main window geometry ''' settings = QSettings("Settings.ini", QSettings.IniFormat) settings.setValue("mainWindow/Geometry", self.saveGeometry()) settings.setValue("mainWindow/State", self.saveState()) settings.setValue("mainWindow/DockingState", self.dock_manager.saveState()) def save_perspectives(self): ''' Save the list of perspectives ''' settings = QSettings("Settings.ini", QSettings.IniFormat) self.dock_manager.savePerspectives(settings) def restore_state(self): ''' Restores the dock manager state ''' settings = QSettings("Settings.ini", QSettings.IniFormat) geom = settings.value("mainWindow/Geometry") if geom is not None: self.restoreGeometry(geom) state = settings.value("mainWindow/State") if state is not None: self.restoreState(state) state = settings.value("mainWindow/DockingState") if state is not None: self.dock_manager.restore_state(state) def restore_perspectives(self): ''' Restore the perspective listo of the dock manager ''' settings = QSettings("Settings.ini", QSettings.IniFormat) self.dock_manager.loadPerspectives(settings) self.perspective_combo_box.clear() self.perspective_combo_box.addItems( self.dock_manager.perspectiveNames()) def save_perspective(self): perspective_name, ok = QInputDialog.getText(self, 'Save perspective', 'Enter unique name:') if ok and perspective_name: self.dock_manager.addPerspective(perspective_name) _ = QSignalBlocker(self.perspective_combo_box) self.perspective_combo_box.clear() self.perspective_combo_box.addItems( self.dock_manager.perspectiveNames()) self.perspective_combo_box.setCurrentText(perspective_name) self.save_perspectives()
def _initContextMenu(self): self._menu = [QMenu("Meter"), QMenu("Grid"), QMenu("Transform")] meter_menu = self._menu[0] cross_act = QWidgetAction(meter_menu) cross_act.setDefaultWidget(self._show_cross_cb) meter_menu.addAction(cross_act) grid_menu = self._menu[1] show_x_act = QWidgetAction(grid_menu) show_x_act.setDefaultWidget(self._show_x_grid_cb) grid_menu.addAction(show_x_act) show_y_act = QWidgetAction(grid_menu) show_y_act.setDefaultWidget(self._show_y_grid_cb) grid_menu.addAction(show_y_act) opacity_act = QWidgetAction(grid_menu) widget = QWidget() layout = QHBoxLayout() layout.addWidget(QLabel("Opacity")) layout.addWidget(self._grid_opacity_sld) widget.setLayout(layout) opacity_act.setDefaultWidget(widget) grid_menu.addAction(opacity_act) transform_menu = self._menu[2] log_x_act = QWidgetAction(transform_menu) log_x_act.setDefaultWidget(self._log_x_cb) transform_menu.addAction(log_x_act) log_y_act = QWidgetAction(transform_menu) log_y_act.setDefaultWidget(self._log_y_cb) transform_menu.addAction(log_y_act)
class SystemTray(QSystemTrayIcon): def __init__(self, parent=None): super(SystemTray, self).__init__(parent) self.createActions() self.EdgeAction() self.UploadAction() self.addActions() self.setContextMenu(self.menu) def showWidget(self): if w.isVisible(): w.hide() self.show_action.setIcon(QIcon(QPixmap("./icons/加号.png"))) else: w.showNormal() self.show_action.setIcon(QIcon(QPixmap("./icons/减号.png"))) def exitWidget(self): sys.exit(app.exec_()) def createActions(self): self.setIcon(QIcon('./icons/sandbox.png')) self.menu = QMenu(QApplication.desktop()) self.menu.setStyleSheet("QMenu{text-align:center}") self.show_action = QWidgetAction(self.menu) self.exit_action = QWidgetAction(self.menu) self.show_action.triggered.connect(self.showWidget) self.exit_action.triggered.connect(self.exitWidget) self.show_action.setIcon(QIcon(QPixmap("./icons/减号.png"))) self.show_action.setIconText("显示主界面") self.exit_action.setIcon(QIcon(QPixmap("./icons/关机.png"))) self.exit_action.setIconText("退出程序") def EdgeAction(self): edge_widget = QWidget() self.edge_action = QWidgetAction(self.menu) self.searchLine = QLineEdit() self.searchLine.setPlaceholderText('search in sandbox') self.searchButton = QPushButton() self.searchButton.setIcon(QIcon(QPixmap("./icons/search.png"))) self.searchButton.setObjectName("searchButton") self.searchButton.setIconSize(QSize(18, 18)) self.searchButton.setStyleSheet("QPushButton{border:2px}") self.searchButton.clicked.connect(self.searchInSanbox) layout = QGridLayout() layout.addWidget(self.searchLine, 1, 1) layout.addWidget(self.searchButton, 1, 0) edge_widget.setLayout(layout) self.edge_action.setDefaultWidget(edge_widget) def UploadAction(self): upload_widget = QWidget() self.upload_action = QWidgetAction(self.menu) self.upload_action.setIcon(QIcon(QPixmap("./icons/file.png"))) self.upload_action.setIconText("加载文件") self.upload_action.triggered.connect(self.getfile) # self.upload_button = QPushButton("加载文件") # self.upload_button.setIcon(QIcon(QPixmap("./icons/file.png"))) # self.upload_button.setIconSize(QSize(15,15)) # self.upload_button.setStyleSheet("QPushButton{border:2px}") # self.upload_button.clicked.connect(self.getfile) # layout = QVBoxLayout() # layout.addWidget(self.upload_button) # upload_widget.setLayout(layout) # self.upload_action.setDefaultWidget(upload_widget) def searchInSanbox(self): print('hello') url = self.searchLine.text() if url == '': url = 'https://www.baidu.com' # self.searchLine.setText(None) sendurl(url) def getfile(self): q_file = QFileDialog() q_file.setFileMode(QFileDialog.AnyFile) q_file.setFilter(QDir.Files) if q_file.exec(): filenames = q_file.selectedFiles() print(filenames[0]) s = filenames[0] sendfile(s) def addActions(self): self.menu.addAction(self.edge_action) self.menu.addAction(self.upload_action) self.menu.addAction(self.show_action) self.menu.addAction(self.exit_action)
def __init__(self, font, parent=None): super().__init__(parent) auxiliaryWidth = self.fontMetrics().width('0') * 8 self.leftTextField = MetricsSequenceEdit(font, self) self.leftTextField.setMaximumWidth(auxiliaryWidth) self.textField = MetricsSequenceComboBox(font, self) # XXX: had to use Maximum because Preferred did extend the widget(?) self.textField.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum) self.rightTextField = MetricsSequenceEdit(font, self) self.rightTextField.setMaximumWidth(auxiliaryWidth) self.leftTextField.textEdited.connect(self.textField.editTextChanged) self.rightTextField.textEdited.connect(self.textField.editTextChanged) self.textField.editTextChanged.connect(self._textChanged) self.comboBox = QComboBox(self) self.comboBox.setEditable(True) self.comboBox.setCompleter(None) self.comboBox.setValidator(QIntValidator(self)) for p in pointSizes: self.comboBox.addItem(str(p)) self.pointSizeChanged = self.comboBox.currentIndexChanged[str] self.configBar = QPushButton(self) self.configBar.setFlat(True) self.configBar.setIcon(QIcon(":settings.svg")) self.configBar.setStyleSheet("padding: 2px 0px; padding-right: 10px") self.toolsMenu = QMenu(self) self._showKerning = self.toolsMenu.addAction( self.tr("Show Kerning"), self._kerningVisibilityChanged) self._showKerning.setCheckable(True) self._showMetrics = self.toolsMenu.addAction(self.tr("Show Metrics"), self._controlsTriggered) self._showMetrics.setCheckable(True) self.toolsMenu.addSeparator() self._verticalFlip = self.toolsMenu.addAction(self.tr("Vertical Flip"), self._controlsTriggered) self._verticalFlip.setCheckable(True) self._wrapLines = self.toolsMenu.addAction(self.tr("Wrap Lines"), self._controlsTriggered) self._wrapLines.setCheckable(True) self.toolsMenu.addSeparator() action = self.toolsMenu.addAction(self.tr("Line Height:")) action.setEnabled(False) lineHeight = QWidgetAction(self.toolsMenu) self._lineHeightSlider = slider = QSlider(Qt.Horizontal, self) # QSlider works with integers so we'll just divide what comes out of it # by 100 slider.setMinimum(80) slider.setMaximum(160) slider.setValue(110) slider.valueChanged.connect(self._controlsTriggered) slider.valueChanged.connect(self._sliderLineHeightChanged) lineHeight.setDefaultWidget(slider) self.toolsMenu.addAction(lineHeight) self.configBar.setMenu(self.toolsMenu) self.addWidget(self.leftTextField) self.addWidget(self.textField) self.addWidget(self.rightTextField) self.addWidget(self.comboBox) self.addWidget(self.configBar) app = QApplication.instance() app.dispatcher.addObserver(self, "_currentGlyphChanged", "currentGlyphChanged") self.readSettings()
def get_widget_action(self, parent): wid_action = QWidgetAction(parent) wid_action.setDefaultWidget(self) return wid_action
class BeaglesMainWindow(QMainWindow, ActionCallbacks): def __init__(self): super(BeaglesMainWindow, self).__init__() self.io = SharedFlagIO(subprogram=True) def createActions(actions: list): nonlocal self action = partial(newAction, self) cmd = 'global {0}; {0} = action("{1}", {2}, {3}, "{4}", "{5}", {6}, {7})' for act in actions: _str = act action_str = getStr(_str) shortcut, checkable, enabled = [ str(i) for i in self.actionFile[_str] ] shortcut = '"{}"'.format( shortcut) if shortcut is not None else None detail = getStr(_str + "Detail") icon = _str callback = 'self.' + act cmd_string = cmd.format(_str, action_str, callback, shortcut, icon, detail, checkable, enabled) self.io.logger.debug(cmd_string) exec(cmd_string) with open('beagles/resources/actions/actions.json', 'r') as json_file: self.actionFile = json.load(json_file) actionList = list(self.actionFile.keys()) createActions(actionList) self.setup() def menu(self, title, actions=None): menu = self.menuBar().addMenu(title) if actions: addActions(menu, actions) return menu def toolbar(self, title, actions=None): toolbar = ToolBar(title) toolbar.setObjectName(u'%sToolBar' % title) toolbar.setMovable(False) toolbar.setFixedHeight(32) toolbar.setIconSize(QSize(30, 30)) toolbar.setToolButtonStyle(Qt.ToolButtonIconOnly) if actions: addActions(toolbar, actions) self.addToolBar(Qt.TopToolBarArea, toolbar) return toolbar def setup(self): self._beginner = True self.settings = Settings() self.settings.load() self.setupZoomWidget() self.setupActions() self.setupMenus() self.setupToolbar() self.setupFileDock() self.setupLabelDock() self.populateMenus() self.setupCanvasWidget() self.populateModeActions() def setupActions(self): # Auto saving : Enable auto saving if pressing next self.autoSaving = QAction(getStr('autoSaveMode'), self) self.autoSaving.setCheckable(True) self.autoSaving.setChecked(self.settings.get(SETTING_AUTO_SAVE, False)) # Sync single class mode from PR#106 self.singleClassMode = QAction(getStr('singleClsMode'), self) self.singleClassMode.setCheckable(True) self.singleClassMode.setChecked( self.settings.get(SETTING_SINGLE_CLASS, False)) # Add option to enable/disable labels being displayed at the top of bounding boxes self.displayLabelOption = QAction(getStr('displayLabel'), self) self.displayLabelOption.setShortcut("Ctrl+Shift+P") self.displayLabelOption.setCheckable(True) self.displayLabelOption.setChecked( self.settings.get(SETTING_PAINT_LABEL, False)) self.displayLabelOption.triggered.connect(self.togglePaintLabelsOption) self.drawSquaresOption = QAction('Draw Squares', self) self.drawSquaresOption.setShortcut('Ctrl+Shift+R') self.drawSquaresOption.setCheckable(True) self.drawSquaresOption.setChecked( self.settings.get(SETTING_DRAW_SQUARE, False)) self.drawSquaresOption.triggered.connect(self.toggleDrawSquare) # noinspection PyUnresolvedReferences zoomActions = (self.zoomWidget, zoomIn, zoomOut, zoomOrg, setFitWin, setFitWidth) # noinspection PyUnresolvedReferences self.actions = Struct( saveFile=saveFile, changeFormat=changeFormat, saveAs=saveAs, openFile=openFile, closeFile=closeFile, resetAll=resetAll, verifyImg=verifyImg, lineColor=boxLineColor, create=createShape, delBox=delBox, editLabel=editLabel, copySelectedShape=copySelectedShape, trainModel=trainModel, visualize=visualize, setCreateMode=setCreateMode, setEditMode=setEditMode, advancedMode=advancedMode, shapeLineColor=shapeLineColor, shapeFillColor=shapeFillColor, zoom=self.zoom, zoomIn=zoomIn, zoomOut=zoomOut, zoomOrg=zoomOrg, setFitWin=setFitWin, setFitWidth=setFitWidth, zoomActions=zoomActions, fileMenuActions=(openFile, openDir, impVideo, saveFile, saveAs, commitAnnotatedFrames, trainModel, visualize, closeFile, resetAll, close), beginner=(), advanced=(), editMenu=(editLabel, copySelectedShape, delBox, None, boxLineColor, self.drawSquaresOption), beginnerContext=(createShape, editLabel, copySelectedShape, delBox), advancedContext=(setCreateMode, setEditMode, editLabel, copySelectedShape, delBox, shapeLineColor, shapeFillColor), onLoadActive=(closeFile, createShape, setCreateMode, setEditMode), onShapesPresent=(saveAs, hideAll, showAll)) # noinspection PyUnresolvedReferences def populateModeActions(self): if self.beginner(): tool, menu = self.actions.beginner, self.actions.beginnerContext else: tool, menu = self.actions.advanced, self.actions.advancedContext self.tools.clear() addActions(self.tools, tool) self.canvas.menus[0].clear() addActions(self.canvas.menus[0], menu) self.menus.edit.clear() actions = (self.actions.create,) if self.beginner() \ else (self.actions.setCreateMode, self.actions.setEditMode, self.actions.verifyImg) addActions(self.menus.edit, actions + self.actions.editMenu) def setupMenus(self): labelMenu = QMenu() # noinspection PyUnresolvedReferences addActions(labelMenu, (editLabel, delBox)) self.menus = Struct(file=self.menu('&File'), edit=self.menu('&Edit'), view=self.menu('&View'), machine_learning=self.menu('&Machine Learning'), help=self.menu('&Help'), recentFiles=QMenu('Open &Recent'), labelList=labelMenu) # noinspection PyUnresolvedAttribute self.menus.file.aboutToShow.connect(self.updateFileMenu) def populateMenus(self): labels = self.dock.toggleViewAction() labels.setText(getStr('showHide')) labels.setShortcut('Ctrl+Shift+L') # noinspection PyUnresolvedReferences addActions(self.menus.file, (openFile, self.menus.recentFiles, openDir, changeSaveDir, impVideo, openAnnotation, saveFile, changeFormat, saveAs, closeFile, resetAll, close)) # noinspection PyUnresolvedReferences addActions(self.menus.help, (showTutorialDialog, showInfo)) # noinspection PyUnresolvedReferences addActions(self.menus.view, (self.autoSaving, self.singleClassMode, self.displayLabelOption, labels, advancedMode, None, prevImg, nextImg, None, hideAll, showAll, None, zoomIn, zoomOut, zoomOrg, None, setFitWin, setFitWidth)) # noinspection PyUnresolvedReferences addActions(self.menus.machine_learning, (commitAnnotatedFrames, trainModel, visualize, None)) def setupToolbar(self): self.tools = self.toolbar('Tools') # noinspection PyUnresolvedReferences self.actions.beginner = (openFile, openDir, changeSaveDir, saveFile, None, createShape, copySelectedShape, delBox, None, prevImg, nextImg, None, zoomIn, self.zoom, zoomOut, setFitWin, setFitWidth) # noinspection PyUnresolvedReferences self.actions.advanced = (openFile, saveFile, None, setCreateMode, setEditMode, verifyImg, None, hideAll, showAll, None, commitAnnotatedFrames, trainModel, visualize, impVideo) def setupFileDock(self): self.fileListWidget = QListWidget() self.fileListWidget.itemDoubleClicked.connect( self.fileitemDoubleClicked) filelistLayout = QVBoxLayout() filelistLayout.setContentsMargins(0, 0, 0, 0) filelistLayout.addWidget(self.fileListWidget) fileListContainer = QWidget() fileListContainer.setLayout(filelistLayout) self.filedock = QDockWidget(getStr('fileList'), self) self.filedock.setObjectName(getStr('files')) self.filedock.setWidget(fileListContainer) self.addDockWidget(Qt.LeftDockWidgetArea, self.filedock) self.filedock.setFeatures(QDockWidget.DockWidgetFloatable) def setupLabelDock(self): listLayout = QVBoxLayout() listLayout.setContentsMargins(0, 0, 0, 0) self.editButton = QToolButton() self.editButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) # noinspection PyUnresolvedReferences self.editButton.setDefaultAction(editLabel) # Create a widget for edit and diffc button self.difficultButton = QCheckBox(getStr('useDifficult')) self.difficultButton.setChecked(False) self.difficultButton.stateChanged.connect(self.buttonState) self.labelList = QListWidget() labelListContainer = QWidget() labelListContainer.setLayout(listLayout) self.labelList.itemActivated.connect(self.labelSelectionChanged) self.labelList.itemSelectionChanged.connect(self.labelSelectionChanged) self.labelList.itemDoubleClicked.connect(self.editLabel) # Connect to itemChanged to detect checkbox changes. self.labelList.itemChanged.connect(self.labelItemChanged) listLayout.addWidget(self.labelList) self.dock = QDockWidget(getStr('boxLabelText'), self) self.dock.setObjectName(getStr('labels')) self.dock.setWidget(labelListContainer) self.addDockWidget(Qt.RightDockWidgetArea, self.dock) self.dockFeatures = \ QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetFloatable # noinspection PyTypeChecker self.dock.setFeatures(self.dock.features() ^ self.dockFeatures) self.useDefaultLabelCheckbox = QCheckBox(getStr('useDefaultLabel')) self.useDefaultLabelCheckbox.setChecked(False) self.defaultLabelTextLine = QLineEdit() useDefaultLabelQHBoxLayout = QHBoxLayout() useDefaultLabelQHBoxLayout.addWidget(self.useDefaultLabelCheckbox) useDefaultLabelQHBoxLayout.addWidget(self.defaultLabelTextLine) useDefaultLabelContainer = QWidget() useDefaultLabelContainer.setLayout(useDefaultLabelQHBoxLayout) # Add some of widgets to listLayout listLayout.addWidget(self.editButton) listLayout.addWidget(self.difficultButton) listLayout.addWidget(useDefaultLabelContainer) self.lastLabel = None def setupZoomWidget(self): self.zoom = QWidgetAction(self) self.zoomWidget = ZoomWidget() self.zoom.setDefaultWidget(self.zoomWidget) self.zoomWidget.setEnabled(False) def setupCanvasWidget(self): action = partial(newAction, self) # Create and add a widget for showing current label items self.canvas = Canvas(parent=self) self.canvas.zoomRequest.connect(self.zoomRequest) self.canvas.setDrawingShapeToSquare( self.settings.get(SETTING_DRAW_SQUARE, False)) self.canvas.scrollRequest.connect(self.scrollRequest) self.canvas.newShape.connect(self.newShape) self.canvas.shapeMoved.connect(self.setDirty) self.canvas.selectionChanged.connect(self.shapeSelectionChanged) self.canvas.drawingPolygon.connect(self.toggleDrawingSensitive) # Custom context menu for the canvas widget: # noinspection PyUnresolvedReferences addActions(self.canvas.menus[0], self.actions.beginnerContext) addActions(self.canvas.menus[1], (action('&Copy here', self.copyShape), action('&Move here', self.moveShape))) def resetState(self): self.itemsToShapes.clear() self.shapesToItems.clear() self.labelList.clear() self.filePath = None self.imageData = None self.labelFile = None self.canvas.resetState() self.labelCoordinates.clear() def keyReleaseEvent(self, event): if event.key() == Qt.Key_Control: self.canvas.setDrawingShapeToSquare(False) def keyPressEvent(self, event): if event.key() == Qt.Key_Control: # Draw rectangle if Ctrl is pressed self.canvas.setDrawingShapeToSquare(True) def resizeEvent(self, event): if self.canvas and not self.image.isNull() \ and self.zoomMode != self.MANUAL_ZOOM: self.adjustScale() super(BeaglesMainWindow, self).resizeEvent(event) def closeEvent(self, event): for handler in self.io.logger.handlers: handler.doRollover() if not self.mayContinue(): event.ignore() if self.tb_process.pid() > 0: self.tb_process.kill() settings = self.settings # If it loads images from dir, don't load it at the beginning if self.dirname is None: settings[SETTING_FILENAME] = self.filePath if self.filePath else '' else: settings[SETTING_FILENAME] = '' settings[SETTING_WIN_SIZE] = self.size() settings[SETTING_WIN_POSE] = self.pos() settings[SETTING_WIN_STATE] = self.saveState() settings[SETTING_LINE_COLOR] = self.lineColor settings[SETTING_FILL_COLOR] = self.fillColor settings[SETTING_RECENT_FILES] = self.recentFiles settings[SETTING_ADVANCE_MODE] = not self._beginner if self.defaultSaveDir and os.path.exists(self.defaultSaveDir): settings[SETTING_SAVE_DIR] = str(self.defaultSaveDir) else: settings[SETTING_SAVE_DIR] = '' if self.lastOpenDir and os.path.exists(self.lastOpenDir): settings[SETTING_LAST_OPEN_DIR] = self.lastOpenDir else: settings[SETTING_LAST_OPEN_DIR] = '' settings[SETTING_AUTO_SAVE] = self.autoSaving.isChecked() settings[SETTING_SINGLE_CLASS] = self.singleClassMode.isChecked() settings[SETTING_PAINT_LABEL] = self.displayLabelOption.isChecked() settings[SETTING_DRAW_SQUARE] = self.drawSquaresOption.isChecked() settings.save()
def makePopupMenu(self): index = self.currentIndex() sel = self.getSelection() clipboard = qApp.clipboard() menu = QMenu(self) # Get index under cursor pos = self.viewport().mapFromGlobal(QCursor.pos()) mouseIndex = self.indexAt(pos) # Get index's title if mouseIndex.isValid(): title = mouseIndex.internalPointer().title() elif self.rootIndex().parent().isValid(): # mouseIndex is the background of an item, so we check the parent mouseIndex = self.rootIndex().parent() title = mouseIndex.internalPointer().title() else: title = qApp.translate("outlineBasics", "Root") if len(title) > 25: title = title[:25] + "…" # Open Item action self.actOpen = QAction(QIcon.fromTheme("go-right"), qApp.translate("outlineBasics", "Open {}".format(title)), menu) self.actOpen.triggered.connect(self.openItem) menu.addAction(self.actOpen) # Open item(s) in new tab if mouseIndex in sel and len(sel) > 1: actionTitle = qApp.translate("outlineBasics", "Open {} items in new tabs").format(len(sel)) self._indexesToOpen = sel else: actionTitle = qApp.translate("outlineBasics", "Open {} in a new tab").format(title) self._indexesToOpen = [mouseIndex] self.actNewTab = QAction(QIcon.fromTheme("go-right"), actionTitle, menu) self.actNewTab.triggered.connect(self.openItemsInNewTabs) menu.addAction(self.actNewTab) menu.addSeparator() # Add text / folder self.actAddFolder = QAction(QIcon.fromTheme("folder-new"), qApp.translate("outlineBasics", "New &Folder"), menu) self.actAddFolder.triggered.connect(self.addFolder) menu.addAction(self.actAddFolder) self.actAddText = QAction(QIcon.fromTheme("document-new"), qApp.translate("outlineBasics", "New &Text"), menu) self.actAddText.triggered.connect(self.addText) menu.addAction(self.actAddText) menu.addSeparator() # Copy, cut, paste, duplicate self.actCut = QAction(QIcon.fromTheme("edit-cut"), qApp.translate("outlineBasics", "C&ut"), menu) self.actCut.triggered.connect(self.cut) menu.addAction(self.actCut) self.actCopy = QAction(QIcon.fromTheme("edit-copy"), qApp.translate("outlineBasics", "&Copy"), menu) self.actCopy.triggered.connect(self.copy) menu.addAction(self.actCopy) self.actPaste = QAction(QIcon.fromTheme("edit-paste"), qApp.translate("outlineBasics", "&Paste"), menu) self.actPaste.triggered.connect(self.paste) menu.addAction(self.actPaste) # Rename / duplicate / remove items self.actDelete = QAction(QIcon.fromTheme("edit-delete"), qApp.translate("outlineBasics", "&Delete"), menu) self.actDelete.triggered.connect(self.delete) menu.addAction(self.actDelete) self.actRename = QAction(QIcon.fromTheme("edit-rename"), qApp.translate("outlineBasics", "&Rename"), menu) self.actRename.triggered.connect(self.rename) menu.addAction(self.actRename) menu.addSeparator() # POV self.menuPOV = QMenu(qApp.translate("outlineBasics", "Set POV"), menu) mw = mainWindow() a = QAction(QIcon.fromTheme("dialog-no"), qApp.translate("outlineBasics", "None"), self.menuPOV) a.triggered.connect(lambda: self.setPOV("")) self.menuPOV.addAction(a) self.menuPOV.addSeparator() menus = [] for i in [qApp.translate("outlineBasics", "Main"), qApp.translate("outlineBasics", "Secondary"), qApp.translate("outlineBasics", "Minor")]: m = QMenu(i, self.menuPOV) menus.append(m) self.menuPOV.addMenu(m) mpr = QSignalMapper(self.menuPOV) for i in range(mw.mdlCharacter.rowCount()): a = QAction(mw.mdlCharacter.icon(i), mw.mdlCharacter.name(i), self.menuPOV) a.triggered.connect(mpr.map) mpr.setMapping(a, int(mw.mdlCharacter.ID(i))) imp = toInt(mw.mdlCharacter.importance(i)) menus[2 - imp].addAction(a) mpr.mapped.connect(self.setPOV) menu.addMenu(self.menuPOV) # Status self.menuStatus = QMenu(qApp.translate("outlineBasics", "Set Status"), menu) # a = QAction(QIcon.fromTheme("dialog-no"), qApp.translate("outlineBasics", "None"), self.menuStatus) # a.triggered.connect(lambda: self.setStatus("")) # self.menuStatus.addAction(a) # self.menuStatus.addSeparator() mpr = QSignalMapper(self.menuStatus) for i in range(mw.mdlStatus.rowCount()): a = QAction(mw.mdlStatus.item(i, 0).text(), self.menuStatus) a.triggered.connect(mpr.map) mpr.setMapping(a, i) self.menuStatus.addAction(a) mpr.mapped.connect(self.setStatus) menu.addMenu(self.menuStatus) # Labels self.menuLabel = QMenu(qApp.translate("outlineBasics", "Set Label"), menu) mpr = QSignalMapper(self.menuLabel) for i in range(mw.mdlLabels.rowCount()): a = QAction(mw.mdlLabels.item(i, 0).icon(), mw.mdlLabels.item(i, 0).text(), self.menuLabel) a.triggered.connect(mpr.map) mpr.setMapping(a, i) self.menuLabel.addAction(a) mpr.mapped.connect(self.setLabel) menu.addMenu(self.menuLabel) menu.addSeparator() # Custom icons if self.menuCustomIcons: menu.addMenu(self.menuCustomIcons) else: self.menuCustomIcons = QMenu(qApp.translate("outlineBasics", "Set Custom Icon"), menu) a = QAction(qApp.translate("outlineBasics", "Restore to default"), self.menuCustomIcons) a.triggered.connect(lambda: self.setCustomIcon("")) self.menuCustomIcons.addAction(a) self.menuCustomIcons.addSeparator() txt = QLineEdit() txt.textChanged.connect(self.filterLstIcons) txt.setPlaceholderText("Filter icons") txt.setStyleSheet("QLineEdit { background: transparent; border: none; }") act = QWidgetAction(self.menuCustomIcons) act.setDefaultWidget(txt) self.menuCustomIcons.addAction(act) self.lstIcons = QListWidget() for i in customIcons(): item = QListWidgetItem() item.setIcon(QIcon.fromTheme(i)) item.setData(Qt.UserRole, i) item.setToolTip(i) self.lstIcons.addItem(item) self.lstIcons.itemClicked.connect(self.setCustomIconFromItem) self.lstIcons.setViewMode(self.lstIcons.IconMode) self.lstIcons.setUniformItemSizes(True) self.lstIcons.setResizeMode(self.lstIcons.Adjust) self.lstIcons.setMovement(self.lstIcons.Static) self.lstIcons.setStyleSheet("background: transparent; background: none;") self.filterLstIcons("") act = QWidgetAction(self.menuCustomIcons) act.setDefaultWidget(self.lstIcons) self.menuCustomIcons.addAction(act) menu.addMenu(self.menuCustomIcons) # Disabling stuff if not clipboard.mimeData().hasFormat("application/xml"): self.actPaste.setEnabled(False) if len(sel) == 0: self.actCopy.setEnabled(False) self.actCut.setEnabled(False) self.actRename.setEnabled(False) self.actDelete.setEnabled(False) self.menuPOV.setEnabled(False) self.menuStatus.setEnabled(False) self.menuLabel.setEnabled(False) self.menuCustomIcons.setEnabled(False) if len(sel) > 1: self.actRename.setEnabled(False) return menu
def makePopupMenu(self): index = self.currentIndex() sel = self.getSelection() clipboard = qApp.clipboard() menu = QMenu(self) # Get index under cursor pos = self.viewport().mapFromGlobal(QCursor.pos()) mouseIndex = self.indexAt(pos) # Get index's title if mouseIndex.isValid(): title = mouseIndex.internalPointer().title() elif self.rootIndex().parent().isValid(): # mouseIndex is the background of an item, so we check the parent mouseIndex = self.rootIndex().parent() title = mouseIndex.internalPointer().title() else: title = qApp.translate("outlineBasics", "Root") if len(title) > 25: title = title[:25] + "…" # Open Item action self.actOpen = QAction( QIcon.fromTheme("go-right"), qApp.translate("outlineBasics", "Open {}".format(title)), menu) self.actOpen.triggered.connect(self.openItem) menu.addAction(self.actOpen) # Open item(s) in new tab if mouseIndex in sel and len(sel) > 1: actionTitle = qApp.translate("outlineBasics", "Open {} items in new tabs").format( len(sel)) self._indexesToOpen = sel else: actionTitle = qApp.translate("outlineBasics", "Open {} in a new tab").format(title) self._indexesToOpen = [mouseIndex] self.actNewTab = QAction(QIcon.fromTheme("go-right"), actionTitle, menu) self.actNewTab.triggered.connect(self.openItemsInNewTabs) menu.addAction(self.actNewTab) menu.addSeparator() # Add text / folder self.actAddFolder = QAction( QIcon.fromTheme("folder-new"), qApp.translate("outlineBasics", "New &Folder"), menu) self.actAddFolder.triggered.connect(self.addFolder) menu.addAction(self.actAddFolder) self.actAddText = QAction(QIcon.fromTheme("document-new"), qApp.translate("outlineBasics", "New &Text"), menu) self.actAddText.triggered.connect(self.addText) menu.addAction(self.actAddText) menu.addSeparator() # Copy, cut, paste, duplicate self.actCut = QAction(QIcon.fromTheme("edit-cut"), qApp.translate("outlineBasics", "C&ut"), menu) self.actCut.triggered.connect(self.cut) menu.addAction(self.actCut) self.actCopy = QAction(QIcon.fromTheme("edit-copy"), qApp.translate("outlineBasics", "&Copy"), menu) self.actCopy.triggered.connect(self.copy) menu.addAction(self.actCopy) self.actPaste = QAction(QIcon.fromTheme("edit-paste"), qApp.translate("outlineBasics", "&Paste"), menu) self.actPaste.triggered.connect(self.paste) menu.addAction(self.actPaste) # Rename / duplicate / remove items self.actDelete = QAction(QIcon.fromTheme("edit-delete"), qApp.translate("outlineBasics", "&Delete"), menu) self.actDelete.triggered.connect(self.delete) menu.addAction(self.actDelete) self.actRename = QAction(QIcon.fromTheme("edit-rename"), qApp.translate("outlineBasics", "&Rename"), menu) self.actRename.triggered.connect(self.rename) menu.addAction(self.actRename) menu.addSeparator() # POV self.menuPOV = QMenu(qApp.translate("outlineBasics", "Set POV"), menu) mw = mainWindow() a = QAction(QIcon.fromTheme("dialog-no"), qApp.translate("outlineBasics", "None"), self.menuPOV) a.triggered.connect(lambda: self.setPOV("")) self.menuPOV.addAction(a) self.menuPOV.addSeparator() menus = [] for i in [ qApp.translate("outlineBasics", "Main"), qApp.translate("outlineBasics", "Secondary"), qApp.translate("outlineBasics", "Minor") ]: m = QMenu(i, self.menuPOV) menus.append(m) self.menuPOV.addMenu(m) mpr = QSignalMapper(self.menuPOV) for i in range(mw.mdlCharacter.rowCount()): a = QAction(mw.mdlCharacter.icon(i), mw.mdlCharacter.name(i), self.menuPOV) a.triggered.connect(mpr.map) mpr.setMapping(a, int(mw.mdlCharacter.ID(i))) imp = toInt(mw.mdlCharacter.importance(i)) menus[2 - imp].addAction(a) mpr.mapped.connect(self.setPOV) menu.addMenu(self.menuPOV) # Status self.menuStatus = QMenu(qApp.translate("outlineBasics", "Set Status"), menu) # a = QAction(QIcon.fromTheme("dialog-no"), qApp.translate("outlineBasics", "None"), self.menuStatus) # a.triggered.connect(lambda: self.setStatus("")) # self.menuStatus.addAction(a) # self.menuStatus.addSeparator() mpr = QSignalMapper(self.menuStatus) for i in range(mw.mdlStatus.rowCount()): a = QAction(mw.mdlStatus.item(i, 0).text(), self.menuStatus) a.triggered.connect(mpr.map) mpr.setMapping(a, i) self.menuStatus.addAction(a) mpr.mapped.connect(self.setStatus) menu.addMenu(self.menuStatus) # Labels self.menuLabel = QMenu(qApp.translate("outlineBasics", "Set Label"), menu) mpr = QSignalMapper(self.menuLabel) for i in range(mw.mdlLabels.rowCount()): a = QAction( mw.mdlLabels.item(i, 0).icon(), mw.mdlLabels.item(i, 0).text(), self.menuLabel) a.triggered.connect(mpr.map) mpr.setMapping(a, i) self.menuLabel.addAction(a) mpr.mapped.connect(self.setLabel) menu.addMenu(self.menuLabel) menu.addSeparator() # Custom icons if self.menuCustomIcons: menu.addMenu(self.menuCustomIcons) else: self.menuCustomIcons = QMenu( qApp.translate("outlineBasics", "Set Custom Icon"), menu) a = QAction(qApp.translate("outlineBasics", "Restore to default"), self.menuCustomIcons) a.triggered.connect(lambda: self.setCustomIcon("")) self.menuCustomIcons.addAction(a) self.menuCustomIcons.addSeparator() txt = QLineEdit() txt.textChanged.connect(self.filterLstIcons) txt.setPlaceholderText("Filter icons") txt.setStyleSheet("background: transparent; border: none;") act = QWidgetAction(self.menuCustomIcons) act.setDefaultWidget(txt) self.menuCustomIcons.addAction(act) self.lstIcons = QListWidget() for i in customIcons(): item = QListWidgetItem() item.setIcon(QIcon.fromTheme(i)) item.setData(Qt.UserRole, i) item.setToolTip(i) self.lstIcons.addItem(item) self.lstIcons.itemClicked.connect(self.setCustomIconFromItem) self.lstIcons.setViewMode(self.lstIcons.IconMode) self.lstIcons.setUniformItemSizes(True) self.lstIcons.setResizeMode(self.lstIcons.Adjust) self.lstIcons.setMovement(self.lstIcons.Static) self.lstIcons.setStyleSheet( "background: transparent; background: none;") self.filterLstIcons("") act = QWidgetAction(self.menuCustomIcons) act.setDefaultWidget(self.lstIcons) self.menuCustomIcons.addAction(act) menu.addMenu(self.menuCustomIcons) # Disabling stuff if not clipboard.mimeData().hasFormat("application/xml"): self.actPaste.setEnabled(False) if len(sel) == 0: self.actCopy.setEnabled(False) self.actCut.setEnabled(False) self.actRename.setEnabled(False) self.actDelete.setEnabled(False) self.menuPOV.setEnabled(False) self.menuStatus.setEnabled(False) self.menuLabel.setEnabled(False) self.menuCustomIcons.setEnabled(False) if len(sel) > 1: self.actRename.setEnabled(False) return menu
class MainWindow(MainWindowUI, MainWindowBase): save_perspective_action: QAction perspective_list_action: QWidgetAction perspective_combo_box: QComboBox dock_manager: QtAds.CDockManager def __init__(self, parent=None): super().__init__(parent) self.save_perspective_action = None self.perspective_list_action = None self.perspective_combo_box = None self.dock_manager = None self.setupUi(self) self.create_actions() # uncomment the following line if the tab close button should be # a QToolButton instead of a QPushButton # QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.configFlags() | QtAds.CDockManager.TabCloseButtonIsToolButton) # uncomment the following line if you want to use opaque undocking and # opaque splitter resizing #QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.DefaultOpaqueConfig); # uncomment the following line if you want a fixed tab width that does # not change if the visibility of the close button changes #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.RetainTabSizeWhenCloseButtonHidden, True) # uncomment the following line if you don't want close button on DockArea's title bar #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasCloseButton, false); # uncomment the following line if you don't want undock button on DockArea's title bar #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasUndockButton, false); # uncomment the following line if you don't want tabs menu button on DockArea's title bar #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasTabsMenuButton, false); # uncomment the following line if you don't want disabled buttons to appear on DockArea's title bar #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHideDisabledButtons, true); # uncomment the following line if you want to show tabs menu button on DockArea's title bar only when there are more than one tab and at least of them has elided title #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaDynamicTabsMenuButtonVisibility, true); # uncomment the following line if you want floating container to always show application title instead of active dock widget's title #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FloatingContainerHasWidgetTitle, false); # uncomment the following line if you want floating container to show active dock widget's icon instead of always showing application icon #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FloatingContainerHasWidgetIcon, true); # uncomment the following line if you want a central widget in the main dock container (the dock manager) without a titlebar # If you enable this code, you can test it in the demo with the Calendar 0 # dock widget. #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.HideSingleCentralWidgetTitleBar, true); # Now create the dock manager and its content self.dock_manager = QtAds.CDockManager(self) # Uncomment the following line to have the old style where the dock # area close button closes the active tab # QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.DockAreaHasCloseButton # | QtAds.CDockManager.DockAreaCloseButtonClosesTab) self.perspective_combo_box.activated[str].connect( self.dock_manager.openPerspective) self.create_content() # Default window geometry - center on screen self.resize(1280, 720) self.setGeometry( QStyle.alignedRect( Qt.LeftToRight, Qt.AlignCenter, self.frameSize(), QGuiApplication.primaryScreen().availableGeometry())) # self.restore_state() self.restore_perspectives() def create_content(self): # Test container docking view_menu = self.menuView dock_widget = create_calendar_dock_widget(view_menu) dock_widget.setFeature(QtAds.CDockWidget.DockWidgetClosable, False) special_dock_area = self.dock_manager.addDockWidget( QtAds.LeftDockWidgetArea, dock_widget) # For this Special Dock Area we want to avoid dropping on the center of it (i.e. we don't want this widget to be ever tabbified): special_dock_area.setAllowedAreas(QtAds.OuterDockAreas) # special_dock_area.setAllowedAreas(QtAds.LeftDockWidgetArea | QtAds.RightDockWidgetArea) # just for testing self.dock_manager.addDockWidget( QtAds.LeftDockWidgetArea, create_long_text_label_dock_widget(view_menu)) file_system_widget = create_file_system_tree_dock_widget(view_menu) tool_bar = file_system_widget.createDefaultToolBar() tool_bar.addAction(self.actionSaveState) tool_bar.addAction(self.actionRestoreState) file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetFloatable, False) append_feature_string_to_window_title(file_system_widget) self.dock_manager.addDockWidget(QtAds.BottomDockWidgetArea, file_system_widget) file_system_widget = create_file_system_tree_dock_widget(view_menu) tool_bar = file_system_widget.createDefaultToolBar() tool_bar.addAction(self.actionSaveState) tool_bar.addAction(self.actionRestoreState) file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetMovable, False) file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetFloatable, False) append_feature_string_to_window_title(file_system_widget) # Test custom factory - we inject a help button into the title bar QtAds.CDockComponentsFactory.setFactory(CCustomComponentsFactory()) top_dock_area = self.dock_manager.addDockWidget( QtAds.TopDockWidgetArea, file_system_widget) QtAds.CDockComponentsFactory.resetDefaultFactory() # We create a calendar widget and clear all flags to prevent the dock area # from closing dock_widget = create_calendar_dock_widget(view_menu) dock_widget.setTabToolTip("Tab ToolTip\nHodie est dies magna") dock_area = self.dock_manager.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, top_dock_area) # Now we add a custom button to the dock area title bar that will create # new editor widgets when clicked custom_button = QToolButton(dock_area) custom_button.setToolTip("Create Editor") custom_button.setIcon(svg_icon(":/adsdemo/images/plus.svg")) custom_button.setAutoRaise(True) title_bar = dock_area.titleBar() index = title_bar.indexOf(title_bar.tabBar()) title_bar.insertWidget(index + 1, custom_button) def on_button_clicked(): dock_widget = create_editor_widget(self.menuView) dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True) self.dock_manager.addDockWidgetTabToArea(dock_widget, dock_area) dock_widget.closeRequested.connect(self.on_editor_close_requested) custom_button.clicked.connect(on_button_clicked) # Test dock area docking right_dock_area = self.dock_manager.addDockWidget( QtAds.RightDockWidgetArea, create_long_text_label_dock_widget(view_menu), top_dock_area) self.dock_manager.addDockWidget( QtAds.TopDockWidgetArea, create_long_text_label_dock_widget(view_menu), right_dock_area) bottom_dock_area = self.dock_manager.addDockWidget( QtAds.BottomDockWidgetArea, create_long_text_label_dock_widget(view_menu), right_dock_area) self.dock_manager.addDockWidget( QtAds.CenterDockWidgetArea, create_long_text_label_dock_widget(view_menu), right_dock_area) self.dock_manager.addDockWidget( QtAds.CenterDockWidgetArea, create_long_text_label_dock_widget(view_menu), bottom_dock_area) action = self.menuTests.addAction("Set {} Floating".format( dock_widget.windowTitle())) action.triggered.connect(dock_widget.setFloating) action = self.menuTests.addAction("Set {} As Current Tab".format( dock_widget.windowTitle())) action.triggered.connect(dock_widget.setAsCurrentTab) action = self.menuTests.addAction("Raise {}".format( dock_widget.windowTitle())) action.triggered.connect(dock_widget.raise_) if ACTIVEX_AVAILABLE: flags = self.dock_manager.configFlags() if flags & QtAds.CDockManager.OpaqueUndocking: self.dock_manager.addDockWidget( QtAds.CenterDockWidgetArea, create_activex_widget(view_menu), right_dock_area) for dock_widget in self.dock_manager.dockWidgetsMap().values(): dock_widget.viewToggled.connect(self.on_view_toggled) dock_widget.visibilityChanged.connect( self.on_view_visibility_changed) def create_actions(self): self.toolBar.addAction(self.actionSaveState) self.toolBar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.actionSaveState.setIcon(svg_icon(":/adsdemo/images/save.svg")) self.toolBar.addAction(self.actionRestoreState) self.actionRestoreState.setIcon( svg_icon(":/adsdemo/images/restore.svg")) self.save_perspective_action = QAction("Create Perspective", self) self.save_perspective_action.setIcon( svg_icon(":/adsdemo/images/picture_in_picture.svg")) self.save_perspective_action.triggered.connect(self.save_perspective) self.perspective_list_action = QWidgetAction(self) self.perspective_combo_box = QComboBox(self) self.perspective_combo_box.setSizeAdjustPolicy( QComboBox.AdjustToContents) self.perspective_combo_box.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.perspective_list_action.setDefaultWidget( self.perspective_combo_box) self.toolBar.addSeparator() self.toolBar.addAction(self.perspective_list_action) self.toolBar.addAction(self.save_perspective_action) a = self.toolBar.addAction("Create Floating Editor") a.setProperty("Floating", True) a.setToolTip( "Creates floating dynamic dockable editor windows that are deleted on close" ) a.setIcon(svg_icon(":/adsdemo/images/note_add.svg")) a.triggered.connect(self.create_editor) self.menuTests.addAction(a) a = self.toolBar.addAction("Create Docked Editor") a.setProperty("Floating", False) a.setToolTip( "Creates a docked editor windows that are deleted on close") a.setIcon(svg_icon(":/adsdemo/images/docked_editor.svg")) a.triggered.connect(self.create_editor) self.menuTests.addAction(a) a = self.toolBar.addAction("Create Floating Table") a.setToolTip( "Creates floating dynamic dockable table with millions of entries") a.setIcon(svg_icon(":/adsdemo/images/grid_on.svg")) a.triggered.connect(self.create_table) self.menuTests.addAction(a) self.menuTests.addSeparator() a = self.menuTests.addAction("Show Status Dialog") a.triggered.connect(self.show_status_dialog) self.menuTests.addSeparator() def closeEvent(self, event: QCloseEvent): self.save_state() super().closeEvent(event) def on_actionSaveState_triggered(self, state: bool): qDebug("MainWindow::on_action_save_state_triggered") self.save_state() def on_actionRestoreState_triggered(self, state: bool): qDebug("MainWindow::on_action_restore_state_triggered") self.restore_state() def save_perspective(self): perspective_name, ok = QInputDialog.getText(self, "Save perspective", "Enter unique name:") if ok and perspective_name: self.dock_manager.addPerspective(perspective_name) _ = QSignalBlocker(self.perspective_combo_box) self.perspective_combo_box.clear() self.perspective_combo_box.addItems( self.dock_manager.perspectiveNames()) self.perspective_combo_box.setCurrentText(perspective_name) self.save_perspectives() def on_view_toggled(self, open: bool): dock_widget = self.sender() if dock_widget is None: return qDebug("{} view_toggled({})".format(dock_widget.objectName(), open)) def on_view_visibility_changed(self, visible: bool): dock_widget = self.sender() if dock_widget is None: return qDebug("{} visibility_changed({})".format(dock_widget.objectName(), visible)) def create_editor(self): sender = self.sender() floating = sender.property("Floating") print("Floating:", floating) dock_widget = create_editor_widget(self.menuView) dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True) dock_widget.closeRequested.connect(self.on_editor_close_requested) if floating: floating_widget = self.dock_manager.addDockWidgetFloating( dock_widget) floating_widget.move(QPoint(20, 20)) else: self.dock_manager.addDockWidget(QtAds.TopDockWidgetArea, dock_widget) def on_editor_close_requested(self): dock_widget = self.sender() result = QMessageBox.question( self, "Close Editor", "Editor {} contains unsaved changes? Would you like to close it?". format(dock_widget.windowTitle())) if result == QMessageBox.Yes: dock_widget.closeDockWidget() def create_table(self): dock_widget = create_table_widget(self.menuView) dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True) floating_widget = self.dock_manager.addDockWidgetFloating(dock_widget) floating_widget.move(QPoint(40, 40)) def show_status_dialog(self): dialog = CStatusDialog(self.dock_manager) dialog.exec_() def save_state(self): ''' Saves the dock manager state and the main window geometry ''' settings = QSettings("Settings.ini", QSettings.IniFormat) settings.setValue("mainWindow/Geometry", self.saveGeometry()) settings.setValue("mainWindow/State", self.saveState()) settings.setValue("mainWindow/DockingState", self.dock_manager.saveState()) def restore_state(self): ''' Restores the dock manager state ''' settings = QSettings("Settings.ini", QSettings.IniFormat) geom = settings.value("mainWindow/Geometry") if geom is not None: self.restoreGeometry(geom) state = settings.value("mainWindow/State") if state is not None: self.restoreState(state) state = settings.value("mainWindow/DockingState") if state is not None: self.dock_manager.restore_state(state) def save_perspectives(self): ''' Save the list of perspectives ''' settings = QSettings("Settings.ini", QSettings.IniFormat) self.dock_manager.savePerspectives(settings) def restore_perspectives(self): ''' Restore the perspective listo of the dock manager ''' settings = QSettings("Settings.ini", QSettings.IniFormat) self.dock_manager.loadPerspectives(settings) self.perspective_combo_box.clear() self.perspective_combo_box.addItems( self.dock_manager.perspectiveNames()) def save_perspective(self): perspective_name, ok = QInputDialog.getText(self, 'Save perspective', 'Enter unique name:') if ok and perspective_name: self.dock_manager.addPerspective(perspective_name) _ = QSignalBlocker(self.perspective_combo_box) self.perspective_combo_box.clear() self.perspective_combo_box.addItems( self.dock_manager.perspectiveNames()) self.perspective_combo_box.setCurrentText(perspective_name) self.save_perspectives()
def makePopupMenu(self): index = self.currentIndex() sel = self.getSelection() clipboard = qApp.clipboard() menu = QMenu(self) # Add / remove items self.actOpen = QAction(QIcon.fromTheme("go-right"), qApp.translate("outlineBasics", "Open Item"), menu) self.actOpen.triggered.connect(self.openItem) menu.addAction(self.actOpen) menu.addSeparator() # Add / remove items self.actAddFolder = QAction( QIcon.fromTheme("folder-new"), qApp.translate("outlineBasics", "New Folder"), menu) self.actAddFolder.triggered.connect(self.addFolder) menu.addAction(self.actAddFolder) self.actAddText = QAction(QIcon.fromTheme("document-new"), qApp.translate("outlineBasics", "New Text"), menu) self.actAddText.triggered.connect(self.addText) menu.addAction(self.actAddText) self.actDelete = QAction(QIcon.fromTheme("edit-delete"), qApp.translate("outlineBasics", "Delete"), menu) self.actDelete.triggered.connect(self.delete) menu.addAction(self.actDelete) menu.addSeparator() # Copy, cut, paste self.actCopy = QAction(QIcon.fromTheme("edit-copy"), qApp.translate("outlineBasics", "Copy"), menu) self.actCopy.triggered.connect(self.copy) menu.addAction(self.actCopy) self.actCut = QAction(QIcon.fromTheme("edit-cut"), qApp.translate("outlineBasics", "Cut"), menu) self.actCut.triggered.connect(self.cut) menu.addAction(self.actCut) self.actPaste = QAction(QIcon.fromTheme("edit-paste"), qApp.translate("outlineBasics", "Paste"), menu) self.actPaste.triggered.connect(self.paste) menu.addAction(self.actPaste) menu.addSeparator() # POV self.menuPOV = QMenu(qApp.translate("outlineBasics", "Set POV"), menu) mw = mainWindow() a = QAction(QIcon.fromTheme("dialog-no"), qApp.translate("outlineBasics", "None"), self.menuPOV) a.triggered.connect(lambda: self.setPOV("")) self.menuPOV.addAction(a) self.menuPOV.addSeparator() menus = [] for i in [ qApp.translate("outlineBasics", "Main"), qApp.translate("outlineBasics", "Secondary"), qApp.translate("outlineBasics", "Minor") ]: m = QMenu(i, self.menuPOV) menus.append(m) self.menuPOV.addMenu(m) mpr = QSignalMapper(self.menuPOV) for i in range(mw.mdlCharacter.rowCount()): a = QAction(mw.mdlCharacter.icon(i), mw.mdlCharacter.name(i), self.menuPOV) a.triggered.connect(mpr.map) mpr.setMapping(a, int(mw.mdlCharacter.ID(i))) imp = toInt(mw.mdlCharacter.importance(i)) menus[2 - imp].addAction(a) mpr.mapped.connect(self.setPOV) menu.addMenu(self.menuPOV) # Status self.menuStatus = QMenu(qApp.translate("outlineBasics", "Set Status"), menu) # a = QAction(QIcon.fromTheme("dialog-no"), qApp.translate("outlineBasics", "None"), self.menuStatus) # a.triggered.connect(lambda: self.setStatus("")) # self.menuStatus.addAction(a) # self.menuStatus.addSeparator() mpr = QSignalMapper(self.menuStatus) for i in range(mw.mdlStatus.rowCount()): a = QAction(mw.mdlStatus.item(i, 0).text(), self.menuStatus) a.triggered.connect(mpr.map) mpr.setMapping(a, i) self.menuStatus.addAction(a) mpr.mapped.connect(self.setStatus) menu.addMenu(self.menuStatus) # Labels self.menuLabel = QMenu(qApp.translate("outlineBasics", "Set Label"), menu) mpr = QSignalMapper(self.menuLabel) for i in range(mw.mdlLabels.rowCount()): a = QAction( mw.mdlLabels.item(i, 0).icon(), mw.mdlLabels.item(i, 0).text(), self.menuLabel) a.triggered.connect(mpr.map) mpr.setMapping(a, i) self.menuLabel.addAction(a) mpr.mapped.connect(self.setLabel) menu.addMenu(self.menuLabel) menu.addSeparator() # Custom icons self.menuCustomIcons = QMenu( qApp.translate("outlineBasics", "Set Custom Icon"), menu) a = QAction(qApp.translate("outlineBasics", "Restore to default"), self.menuCustomIcons) a.triggered.connect(lambda: self.setCustomIcon("")) self.menuCustomIcons.addAction(a) self.menuCustomIcons.addSeparator() txt = QLineEdit() txt.textChanged.connect(self.filterLstIcons) txt.setPlaceholderText("Filter icons") txt.setStyleSheet("background: transparent; border: none;") act = QWidgetAction(self.menuCustomIcons) act.setDefaultWidget(txt) self.menuCustomIcons.addAction(act) self.lstIcons = QListWidget() for i in customIcons(): item = QListWidgetItem() item.setIcon(QIcon.fromTheme(i)) item.setData(Qt.UserRole, i) item.setToolTip(i) self.lstIcons.addItem(item) self.lstIcons.itemClicked.connect(self.setCustomIconFromItem) self.lstIcons.setViewMode(self.lstIcons.IconMode) self.lstIcons.setUniformItemSizes(True) self.lstIcons.setResizeMode(self.lstIcons.Adjust) self.lstIcons.setMovement(self.lstIcons.Static) self.lstIcons.setStyleSheet( "background: transparent; background: none;") self.filterLstIcons("") act = QWidgetAction(self.menuCustomIcons) act.setDefaultWidget(self.lstIcons) self.menuCustomIcons.addAction(act) menu.addMenu(self.menuCustomIcons) # Disabling stuff if len(sel) > 0 and index.isValid() and not index.internalPointer().isFolder() \ or not clipboard.mimeData().hasFormat("application/xml"): self.actPaste.setEnabled(False) if len(sel) > 0 and index.isValid( ) and not index.internalPointer().isFolder(): self.actAddFolder.setEnabled(False) self.actAddText.setEnabled(False) if len(sel) == 0: self.actOpen.setEnabled(False) self.actCopy.setEnabled(False) self.actCut.setEnabled(False) self.actDelete.setEnabled(False) self.menuPOV.setEnabled(False) self.menuStatus.setEnabled(False) self.menuLabel.setEnabled(False) self.menuCustomIcons.setEnabled(False) return menu
class StaticPlot(vip_base): """ style_codes: 0 : QtCore.Qt.SolidLine, 1 : QtCore.Qt.DashDotDotLine, 2 : QtCore.Qt.DashDotLine, 3 : QtCore.Qt.DashLine, 4 : QtCore.Qt.DotLine color_codes: 0 : (255, 255, 255), 1 : (255, 0 , 0 ), 2 : (0 , 255, 0 ), 3 : (0 , 0 , 255), 4 : (100, 100, 100) """ def __init__(self): super(StaticPlot, self).__init__() """ Function init :param config: :return: """ self.__colors_selected__ = [] self.__styles_selected__ = [] self.__show_grid_x__ = None self.__show_grid_y__ = None self.__parameters__ = {} self.__plotWidget__ = None self.__legend__ = None self.styles = { 0: QtCore.Qt.SolidLine, 1: QtCore.Qt.DashDotDotLine, 2: QtCore.Qt.DashDotLine, 3: QtCore.Qt.DashLine, 4: QtCore.Qt.DotLine } self.colors = { 0: (255, 255, 255), 1: (255, 0, 0 ), 2: (0, 255, 0 ), 3: (0, 0, 255), 4: (100, 100, 100) } def cb_initialize_plugin(self): """ Function initiate layer 0 :param config: :return: """ self.config = self.pl_get_current_config_ref() # --------------------------- # Read configuration # --------------------------- int_re = re.compile(r'(\d+)') self.__show_grid_x__ = self.config['x-grid']['value'] == '1' self.__show_grid_y__ = self.config['y-grid']['value'] == '1' self.__colors_selected__ = int_re.findall(self.config['color']['value']) self.__styles_selected__ = int_re.findall(self.config['style']['value']) # ---------------------------- # Set internal variables used for single timestamp plotting (stp) # ---------------------------- self.__plotWidget__ = pg.PlotWidget() self.__plotWidget__.setWindowTitle('StaticPlot') self.__plotWidget__.showGrid(x=self.__show_grid_x__, y=self.__show_grid_y__) self.__plotWidget__.getPlotItem().getViewBox().disableAutoRange() self.__plotWidget__.getPlotItem().getViewBox().setYRange(0,6) self.pl_set_widget_for_internal_usage(self.__plotWidget__) # --------------------------- # Create Parameters # --------------------------- self.__parameters__['x-grid'] = \ DParameter('x-grid', '[0 1]', Regex='^(1|0){1}$') self.__parameters__['y-grid'] = \ DParameter('y-grid', '[0 1]', Regex='^(1|0){1}$') self.__parameters__['color'] = \ DParameter('color', self.config['color']['value'], Regex='^\[(\s*\d\s*)+\]') self.__parameters__['style'] = \ DParameter('style', self.config['style']['value'], Regex='^\[(\s*\d\s*)+\]') self.__parameters__['yRange'] = \ DParameter('yRange', '[0,1]', Regex='^\[(\d+\.\d+)\s+(\d+\.\d+)\]$') self.pl_send_new_parameter_list(list(self.__parameters__.values())) # --------------------------- # Create Legend # --------------------------- if self.config['show_legend']['value']=='1': self.__legend__ = pg.LegendItem((100, 40), offset=(40, 1)) # args are (size, offset) self.__legend__.setParentItem(self.__plotWidget__.graphicsItem()) self.setup_context_menu() self.__plotWidget__.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.__plotWidget__.customContextMenuRequested.connect(self.showContextMenu) self.read_json_data() return True def cb_pause(self): """ Function pause :return: """ pass def cb_resume(self): """ Function resume :return: """ pass def cb_execute(self, Data=None, block_name = None, plugin_uname = None): """ Function cb_execute :param **kwargs: :param Data: :param block_name: :return: """ pass def cb_set_parameter(self, name, value): """ Function set parameters :param name: :param value: :return: """ if name == 'x-grid': self.config['x-grid']['value'] = value self.__plotWidget__.showGrid(x=value == '1') self.xGrid_Checkbox.setChecked(value=='1') if name == 'y-grid': self.config['y-grid']['value'] = value self.__plotWidget__.showGrid(y=value == '1') self.yGrid_Checkbox.setChecked(value=='1') if name == 'color': self.clear() self.config['color']['value'] = value int_re = re.compile(r'(\d+)') self.__colors_selected__ = int_re.findall(self.config['color']['value']) if name == 'style': self.clear() self.config['style']['value'] = value int_re = re.compile(r'(\d+)') self.__styles_selected__ = int_re.findall(self.config['style']['value']) if name == 'yRange': self.use_range_for_y(value) if name == 'xRange': self.use_range_for_x(value) def read_json_data(self): json_str = self.config['json_data']['value'] axis_id = self.config['axis_identifier']['value'] data = json.loads(json_str) self.plot_data(data, axis_id) def plot_data(self, data, axis_id): """ Function update_plot_single_timestamp :return: """ self.clear() tdata = data[axis_id] x_min = min(tdata) x_max = max(tdata) y_min = None y_max = None counter = 0 for signal_name in data: if signal_name != axis_id: signal_data = data[signal_name] if y_max is not None: y_max = max(max(signal_data), y_max) else: y_max = max(signal_data) if y_min is not None: y_min = min(min(signal_data), y_min) else: y_min = min(signal_data) pen = self.get_pen(counter) graphic = GraphicItem(np.array(tdata), np.array(signal_data), 0, pen=pen) self.__plotWidget__.addItem(graphic) if self.__legend__ is not None: data_item = pg.PlotDataItem() data_item.setPen(pen) self.__legend__.addItem(data_item, signal_name) counter += 1 self.use_range_for_x("[{:2.2f} {:2.2f}]".format(x_min, x_max)) self.use_range_for_y("[{:2.2f} {:2.2f}]".format(y_min, y_max)) # self.__plotWidget__.getPlotItem().getViewBox().setXRange(x_min, x_max) def cb_plugin_meta_updated(self): """ This function is called whenever meta information are changed. This enables the plot to handle more than one input for plotting. :return: """ pass def get_pen(self, index): """ Function get pen :param index: :return: """ index = int(index) style_index = index % len(self.__styles_selected__) style_code = int(self.__styles_selected__[style_index]) color_index = index % len(self.__colors_selected__) color_code = int(self.__colors_selected__[color_index]) if style_code in self.styles: style = self.styles[style_code] else: style = self.styles[0] if color_code in self.colors: color = self.colors[color_code] else: color = self.colors[0] return pg.mkPen(color=color, style=style) def use_range_for_x(self, value): """ :param value: :return: """ reg = re.compile(r'(\d+\.\d+)') range = reg.findall(value) if len(range) == 2: self.__plotWidget__.getPlotItem().getViewBox().setXRange(float(range[0]),float(range[1])) def use_range_for_y(self, value): """ :param value: :return: """ reg = re.compile(r'([-]{0,1}\d+\.\d+)') range = reg.findall(value) if len(range) == 2: self.__plotWidget__.getPlotItem().getViewBox().setYRange(float(range[0]), float(range[1])) def setup_context_menu(self): """ :return: """ self.custMenu = QMenu("Options") self.gridMenu = QMenu('Grid') # Grid Menu: # ----------------------------------------------------------- # Y-Grid checkbox self.xGrid_Checkbox = QCheckBox() self.xGrid_Checkbox.stateChanged.connect(self.contextMenu_xGrid_toogle) self.xGrid_Checkbox.setText('X-Grid') self.xGrid_Action = QWidgetAction(self.__plotWidget__) self.xGrid_Action.setDefaultWidget(self.xGrid_Checkbox) self.gridMenu.addAction(self.xGrid_Action) # Check config for startup state if self.__show_grid_x__: self.xGrid_Checkbox.setChecked(True) # X-Grid checkbox self.yGrid_Checkbox = QCheckBox() self.yGrid_Checkbox.stateChanged.connect(self.contextMenu_yGrid_toogle) self.yGrid_Checkbox.setText('Y-Grid') self.yGrid_Action = QWidgetAction(self.__plotWidget__) self.yGrid_Action.setDefaultWidget(self.yGrid_Checkbox) self.gridMenu.addAction(self.yGrid_Action) # Check config for startup state if self.__show_grid_y__: self.yGrid_Checkbox.setChecked(True) # add Menus self.custMenu.addMenu(self.gridMenu) self.__plotWidget__.getPlotItem().getViewBox().menu.clear() self.__plotWidget__.getPlotItem().ctrlMenu = [self.pl_create_control_context_menu(), self.custMenu] def showContextMenu(self): self.setup_context_menu() def contextMenu_xGrid_toogle(self): if self.xGrid_Checkbox.isChecked(): self.control_api.do_set_parameter(self.__id__, 'x-grid', '1') else: self.control_api.do_set_parameter(self.__id__, 'x-grid', '0') def contextMenu_yGrid_toogle(self): if self.yGrid_Checkbox.isChecked(): self.control_api.do_set_parameter(self.__id__, 'y-grid', '1') else: self.control_api.do_set_parameter(self.__id__, 'y-grid', '0') def contextMenu_yRange_toogle(self): mi = self.yRange_minEdit.text() ma = self.yRange_maxEdit.text() if float(mi) < float(ma): self.control_api.do_set_parameter(self.__id__, 'yRange', '[' + float(mi) + ' ' + float(ma) + ']') def cb_quit(self): """ Function quit plugin :return: """ print('StaticPlot: will quit') def cb_get_plugin_configuration(self): """ Function get plugin configuration :return {}: """ config = { 'json_data' : { 'value' : '{"v1": [5, 6, 7, 8, 9 ], "v2": [ 0, 1, 2, 3, 4 ], ' '"v3": [ -5, -6, -7, -8, -9 ], "v4": [ 0, -1, -2, -3, -4 ], ' '"t": [ 0, 1, 2, 3, 4 ]}', 'tooltip' : 'Used as data source. Format: { "time" : [...], "y1" : [...], "y2" : [...]}' }, 'axis_identifier' : { 'value' : 't', 'tooltip' : 'Used to specify the identifier for the X-Axis e.g. time in json_data' }, 'show_legend' : { 'value' : pc.REGEX_BOOL_BIN, 'type' : pc.CFG_TYPE_BOOL }, 'x-grid': { 'value': "0", 'regex': pc.REGEX_BOOL_BIN, 'type': pc.CFG_TYPE_BOOL, 'display_text': 'Grid-X' }, 'y-grid': { 'value': "0", 'regex': pc.REGEX_BOOL_BIN, 'type': pc.CFG_TYPE_BOOL, 'display_text': 'Grid-Y' }, 'color': { 'value': "[0 1 2 3 4]", 'regex': '^\[(\s*\d\s*)+\]', 'advanced': '1', 'display_text': 'Color' }, 'style': { 'value': "[0 0 0 0 0]", 'regex': '^\[(\s*\d\s*)+\]', 'advanced': '1', 'display_text': 'Style' } } # http://www.regexr.com/ return config def clear(self): """ :return: """ self.__plotWidget__.clear()
def init_items(self): self.toolbar.setObjectName("main_toolbar") self.main_window.addToolBar(Qt.TopToolBarArea, self.toolbar) self.toolbar.setMovable(False) steps_menu = QMenu() for step in AVAILABLE_STEPS: s_action = QAction(step, self.main_window) s_action.triggered.connect( partial( self.main_window.default_page_controller. trigger_add_step_command, step, )) steps_menu.addAction(s_action) toolbar_new_step_action = QAction(QIcon(":/images/plus-48.png"), "New Step", self.main_window) toolbar_new_step_action.setMenu(steps_menu) self.toolbar.addAction(toolbar_new_step_action) self.toolbar.addSeparator() toolbar_environment_action = QAction( QIcon(":/images/environment-48.png"), "Configure Environments", self.main_window, ) toolbar_environment_action.triggered.connect( self.main_window.environment_view.show_dialog) self.toolbar.addAction(toolbar_environment_action) tool_bar_envs_list = QComboBox(self.main_window) tool_bar_envs_list.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) tool_bar_envs_list.setDuplicatesEnabled(False) tool_bar_envs_list.currentTextChanged.connect( self.main_window.environment_list_view. on_toolbar_selected_environment_changed) tool_bar_envs_list_action = QWidgetAction(self.main_window) tool_bar_envs_list_action.setText("Environmnents") tool_bar_envs_list_action.setDefaultWidget(tool_bar_envs_list) self.toolbar.addAction(tool_bar_envs_list_action) self.toolbar.addSeparator() spacer = QWidget(self.main_window) spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.toolbar.addWidget(spacer) toolbar_configure_action = QAction(QIcon(":/images/configure-48.png"), "Settings", self.main_window) toolbar_configure_action.triggered.connect( self.main_window.config_view.show_dialog) self.toolbar.addAction(toolbar_configure_action) toolbar_quit_action = QAction(QIcon(":/images/quit-48.png"), "Quit", self.main_window) toolbar_quit_action.triggered.connect(self.trigger_quit_application) self.toolbar.addAction(toolbar_quit_action)
class Plot(vip_base): """ style_codes: 0 : QtCore.Qt.SolidLine, 1 : QtCore.Qt.DashDotDotLine, 2 : QtCore.Qt.DashDotLine, 3 : QtCore.Qt.DashLine, 4 : QtCore.Qt.DotLine color_codes: 0 : (255, 255, 255), 1 : (255, 0 , 0 ), 2 : (0 , 255, 0 ), 3 : (0 , 0 , 255), 4 : (100, 100, 100) """ def __init__(self, debug=False): super(Plot, self).__init__() """ Function init :param config: :return: """ self.signals = {} self.__papi_debug__ = debug self.__buffer_size__ = None self.__downsampling_rate__ = 1 self.__tbuffer__ = [] self.__signals_have_same_length = True self.__append_at__ = 1 self.__new_added_data__ = 0 self.__input_size__ = 0 self.__rolling_plot__ = False self.__colors_selected__ = [] self.__styles_selected__ = [] self.__show_grid_x__ = None self.__show_grid_y__ = None self.__parameters__ = {} self.__update_intervall__ = None self.__last_time__ = None self.__last_plot_time__ = None self.__plotWidget__ = None self.__legend__ = None self.__stp_min_x = None self.__stp_max_x = None self.__stp_min_y = None self.__stp_max_y = None self.__stp_active__ = None self.__downsampling_rate_start__ = None; self.__downsampling_rate__ = None self.styles = { 0: QtCore.Qt.SolidLine, 1: QtCore.Qt.DashDotDotLine, 2: QtCore.Qt.DashDotLine, 3: QtCore.Qt.DashLine, 4: QtCore.Qt.DotLine } self.colors = { 0: (255, 255, 255), 1: (255, 0, 0 ), 2: (0, 255, 0 ), 3: (0, 0, 255), 4: (100, 100, 100) } def cb_initialize_plugin(self): """ Function initiate layer 0 :param config: :return: """ self.config = self.pl_get_current_config_ref() # --------------------------- # Read configuration # --------------------------- int_re = re.compile(r'(\d+)') self.__show_legend__ = self.config['show_legend']['value'] == '1' self.__show_grid_x__ = self.config['x-grid']['value'] == '1' self.__show_grid_y__ = self.config['y-grid']['value'] == '1' self.__rolling_plot__ = self.config['rolling_plot']['value'] == '1' self.__colors_selected__ = int_re.findall(self.config['color']['value']) self.__styles_selected__ = int_re.findall(self.config['style']['value']) self.__buffer_size__ = int(int_re.findall(self.config['buffersize']['value'])[0]) self.__downsampling_rate__ = int(int_re.findall(self.config['downsampling_rate']['value'])[0]) self.__downsampling_rate_start__ = 0 # ---------------------------- # Set internal variables # ---------------------------- self.__tbuffer__ = collections.deque([0.0] * 0, self.__buffer_size__) # ---------------------------- # Set internal variables used for single timestamp plotting (stp) # ---------------------------- self.__stp_min_x = 0 self.__stp_max_x = 0 self.__stp_min_y = 0 self.__stp_max_y = 1 self.__stp_active__ = False # -------------------------------- # Create Layout and labels # -------------------------------- self.central_widget = QWidget() self.central_widget.setContentsMargins(0,0,0,0) self.label_widget = QWidget() self.label_widget.setContentsMargins(0,0,0,0) self.verticalLayout = QVBoxLayout() self.verticalLayout.setContentsMargins(0,0,0,0) self.verticalLayout.setSpacing(0) self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setContentsMargins(0,0,0,0) self.horizontalLayout.setSpacing(0) self.space_label = QLabel() self.space_label.setMargin(0) self.space_label.setAlignment(QtCore.Qt.AlignJustify) self.space_label.setStyleSheet("QLabel { background-color : black; color : grey;" "border : 0px solid black ; border-bottom-width : 5px }") self.time_label = QLabel() self.time_label.setMargin(0) self.time_label.setAlignment(QtCore.Qt.AlignJustify) self.time_label.setStyleSheet("QLabel { background-color : black; color : grey;" "border : 0px solid black ; border-bottom-width : 5px }") self.time_label.setMaximumWidth(55) self.unit_label = QLabel() self.unit_label.setMargin(0) self.unit_label.setAlignment(QtCore.Qt.AlignLeft) self.unit_label.setStyleSheet("QLabel { background-color : black; color : grey;" "border : 0px solid black ; border-bottom-width : 5px }") self.unit_label.setText('[s]') self.central_widget.setLayout(self.verticalLayout) self.label_widget.setLayout(self.horizontalLayout) # -------------------------------- # Create PlotWidget # -------------------------------- self.__plotWidget__ = PlotWidget() self.__plotWidget__.yRangeChanged.connect(self.plot_yrange_changed) self.__plotWidget__.setWindowTitle('PlotPerformanceTitle') self.__plotWidget__.showGrid(x=self.__show_grid_x__, y=self.__show_grid_y__) self.__plotWidget__.getPlotItem().getViewBox().disableAutoRange() self.__plotWidget__.getPlotItem().getViewBox().setYRange(0,6) self.__plotWidget__.getPlotItem().setDownsampling(auto=True) # ------------------------------ # Add Widget to Layout # ------------------------------ self.horizontalLayout.addWidget(self.space_label) self.horizontalLayout.addWidget(self.time_label) self.horizontalLayout.addWidget(self.unit_label) self.verticalLayout.addWidget(self.__plotWidget__) self.verticalLayout.addWidget(self.label_widget) if not self.__papi_debug__: # self.pl_set_widget_for_internal_usage(self.__plotWidget__) self.pl_set_widget_for_internal_usage(self.central_widget) self.__plotWidget__.getPlotItem().getViewBox().enableAutoRange(axis=pg.ViewBox.YAxis, enable=False) self.__plotWidget__.getPlotItem().getViewBox().enableAutoRange(axis=pg.ViewBox.XAxis, enable=False) self.__plotWidget__.getPlotItem().getViewBox().setMouseEnabled(x=False, y=True) # --------------------------- # Create Parameters # --------------------------- self.__parameters__['x-grid'] = \ DParameter('x-grid', self.config['x-grid']['value'], Regex='^(1|0){1}$') self.__parameters__['y-grid'] = \ DParameter('y-grid', self.config['y-grid']['value'], Regex='^(1|0){1}$') self.__parameters__['color'] = \ DParameter('color', self.config['color']['value'], Regex='^\[(\s*\d\s*)+\]') self.__parameters__['style'] = \ DParameter('style', self.config['style']['value'], Regex='^\[(\s*\d\s*)+\]') self.__parameters__['rolling'] = \ DParameter('rolling', self.config['rolling_plot']['value'], Regex='^(1|0){1}') self.__parameters__['downsampling_rate'] = \ DParameter('downsampling_rate', self.__downsampling_rate__, Regex='^\d+$') self.__parameters__['buffersize'] = \ DParameter('buffersize', self.__buffer_size__, Regex='^\d+$') self.__parameters__['yRange'] = \ DParameter('yRange', self.config['yRange']['value'], Regex='^\[(\d+\.\d+)\s+(\d+\.\d+)\]$') self.__parameters__['show_legend'] = \ DParameter('show_legend', self.config['show_legend']['value'], Regex=pc.REGEX_BOOL_BIN) if not self.__papi_debug__: self.pl_send_new_parameter_list(list(self.__parameters__.values())) # --------------------------- # Create Legend # --------------------------- if self.__show_legend__: self.__legend__ = self.__plotWidget__.getPlotItem().addLegend() else: self.__legend__ = None self.__last_time__ = current_milli_time() self.__update_intervall__ = 20 # in milliseconds self.__last_plot_time__ = 0 self.setup_context_menu() self.__plotWidget__.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.__plotWidget__.customContextMenuRequested.connect(self.showContextMenu) self.use_range_for_y(self.config['yRange']['value']) # ---------------------------- # Initiate for default plotting # ---------------------------- self.initiate_update_plot() return True def cb_pause(self): """ Function pause :return: """ self.__plotWidget__.getPlotItem().getViewBox().setMouseEnabled(x=True, y=True) def cb_resume(self): """ Function resume :return: """ self.__plotWidget__.getPlotItem().getViewBox().setMouseEnabled(x=False, y=True) def cb_execute(self, Data=None, block_name = None, plugin_uname = None): """ Function cb_execute :param Data: :param block_name: :return: """ t = Data[CORE_TIME_SIGNAL] self.__input_size__ = len(t) self.__signals_have_same_length = True now = pg.ptime.time() for key in Data: if key != CORE_TIME_SIGNAL: y = Data[key] if key in self.signals: if self.__downsampling_rate_start__ < len(y): ds_y = y[self.__downsampling_rate_start__::self.__downsampling_rate__] self.signals[key].add_data(ds_y) self.__signals_have_same_length &= (len(y) == len(t)) if self.__downsampling_rate_start__ >= len(t): self.__downsampling_rate_start__ -= len(t) else: ds_t = t[self.__downsampling_rate_start__::self.__downsampling_rate__] self.__downsampling_rate_start__ += self.__downsampling_rate__ - len(ds_t) self.__tbuffer__.extend(ds_t) self.__new_added_data__ += len(t) self.rolling_Checkbox.setDisabled(self.__stp_active__) if self.__input_size__ > 1 or self.__signals_have_same_length: if self.__stp_active__: self.initiate_update_plot() if current_milli_time() - self.__last_time__ > self.__update_intervall__ - self.__last_plot_time__: self.__last_time__ = current_milli_time() self.update_plot() self.__last_time__ = current_milli_time() self.__new_added_data__ = 0 else: if not self.__stp_active__ : self.initiate_update_plot_single_timestamp() if current_milli_time() - self.__last_time__ > self.__update_intervall__ - self.__last_plot_time__: self.__last_time__ = current_milli_time() self.update_plot_single_timestamp(Data) self.__last_time__ = current_milli_time() self.__new_added_data__ = 0 # print("Plot time: %0.5f sec" % (self.__last_plot_time__) ) def cb_set_parameter(self, name, value): """ Function set parameters :param name: :param value: :return: """ if name == 'x-grid': self.config['x-grid']['value'] = value self.__plotWidget__.showGrid(x=value == '1') self.xGrid_Checkbox.stateChanged.disconnect() self.xGrid_Checkbox.setChecked(value=='1') self.xGrid_Checkbox.stateChanged.connect(self.contextMenu_xGrid_toogle) if name == 'y-grid': self.config['y-grid']['value'] = value self.__plotWidget__.showGrid(y=value == '1') self.yGrid_Checkbox.stateChanged.disconnect() self.yGrid_Checkbox.setChecked(value=='1') self.yGrid_Checkbox.stateChanged.connect(self.contextMenu_yGrid_toogle) if name == 'downsampling_rate': self.config['downsampling_rate']['value'] = value self.__downsampling_rate__ = int(value) self.__new_added_data__ = 0 self.update_downsampling_rate() if name == 'rolling': self.clear() self.config['rolling_plot']['value'] = value self.update_rolling_plot() if name == 'color': self.clear() self.config['color']['value'] = value int_re = re.compile(r'(\d+)') self.__colors_selected__ = int_re.findall(self.config['color']['value']) self.update_pens() self.update_legend() if name == 'style': self.clear() self.config['style']['value'] = value int_re = re.compile(r'(\d+)') self.__styles_selected__ = int_re.findall(self.config['style']['value']) self.update_pens() self.update_legend() if name == 'show_legend': self.config['show_legend']['value'] = value if value == '0': if self.__legend__ is not None: self.__legend__.scene().removeItem(self.__legend__) del self.__legend__ self.__legend__ = None if value == '1': self.update_legend() if name == 'buffersize': self.config['buffersize']['value'] = value self.update_buffer_size(value) if name == 'yRange': self.config['yRange']['value'] = value self.use_range_for_y(value) def update_pens(self): """ Function update pens :return: """ for signal_name in self.signals.keys(): signal_id = self.signals[signal_name].id new_pen = self.get_pen(signal_id) other_pen = self.get_pen(signal_id) o_color = other_pen.color() o_color.setAlpha(100) other_pen.setColor(o_color) self.signals[signal_name].pen = new_pen self.signals[signal_name].other_pen = other_pen def update_plot(self): """ Function update_plot :return: """ if len(self.__tbuffer__) == 0: return if not self.__rolling_plot__: tdata = list(self.__tbuffer__) if self.__rolling_plot__: tdata = list(range(0, len(self.__tbuffer__))) self.__append_at__ += self.signals[list(self.signals.keys())[0]].get_new_added_since_last_drawing() self.__append_at__ %= len(tdata) tdata = np.roll(tdata, -int(self.__append_at__)) now = pg.ptime.time() for signal_name in self.signals: # get all no more needed graphic items graphics = self.signals[signal_name].get_old_graphics() for graphic in graphics: self.__plotWidget__.removeItem(graphic) # Create new new graphic items self.signals[signal_name].create_graphics(tdata) # Get new created graphic item and paint them graphics = self.signals[signal_name].get_graphics() for graphic in graphics: self.__plotWidget__.addItem(graphic) self.__last_plot_time__ = pg.ptime.time()-now if self.__rolling_plot__: self.__plotWidget__.getPlotItem().getViewBox().setXRange(0, len(tdata)-1) self.time_label.setNum(self.__tbuffer__[-1]) else: self.__plotWidget__.getPlotItem().getViewBox().setXRange(tdata[0], tdata[-1]) # if self.__papi_debug__: # print("Plot time: %0.5f sec" % (self.__last_plot_time__) ) def initiate_update_plot(self): """ To all needed changes to use default plotting :return: """ self.__stp_active__ = False if self.__rolling_plot__: self.time_label.setHidden(False) else: self.time_label.setHidden(True) pass def initiate_update_plot_single_timestamp(self): """ To all needed changes to use single timestamp plotting :return: """ self.__stp_active__ = True self.time_label.setHidden(False) def update_plot_single_timestamp(self, data): """ Function update_plot_single_timestamp :return: """ self.__plotWidget__.clear() cur_max_y = 0 cur_min_y = 1000 for signal_name in data: if signal_name != CORE_TIME_SIGNAL: signal_data = data[signal_name] if signal_name in self.signals: tdata = np.linspace(1, len(signal_data), len(signal_data)) plot_item = self.signals[signal_name] if len(tdata) == 1: graphic = GraphicItem(np.array([self.__stp_min_x, self.__stp_max_x]), np.array([signal_data[0], signal_data[0]]), 0, pen=plot_item.pen) else: graphic = GraphicItem(np.array(tdata), np.array(signal_data), 0, pen=plot_item.pen) self.__plotWidget__.addItem(graphic) self.__stp_max_x = max(self.__stp_max_x, max(tdata)) self.__stp_min_x = min(self.__stp_min_x, min(tdata)) cur_max_y = max(cur_max_y, max(signal_data)) cur_min_y = min(cur_min_y, min(signal_data)) self.__stp_max_y = cur_max_y self.__stp_min_y = cur_min_y self.__plotWidget__.getPlotItem().getViewBox().setXRange(self.__stp_min_x, self.__stp_max_x) self.time_label.setNum(data[CORE_TIME_SIGNAL][0]) def update_buffer_size(self, new_size): """ Function set buffer size :param new_size: :return: """ self.__buffer_size__ = int(new_size) start_size = len(self.__tbuffer__) for signal_name in self.signals: self.__tbuffer__ = collections.deque([0.0] * start_size, self.__buffer_size__) # COLLECTION plot_item = self.signals[signal_name] plot_item.max_elements = self.__buffer_size__ plot_item.clear() self.__plotWidget__.clear() self.update_rolling_plot() self.__new_added_data__ = 0 def cb_plugin_meta_updated(self): """ This function is called whenever meta information are changed. This enables the plot to handle more than one input for plotting. :return: """ dp_info = self.pl_get_dplugin_info() subscriptions = dp_info.get_subscribtions() changes = False current_signals = {} index = 0 for dpluginsub_id in subscriptions: for dblock_name in subscriptions[dpluginsub_id]: # get subscription for dblock subscription = subscriptions[dpluginsub_id][dblock_name] for signal_name in subscription.get_signals(): if signal_name != pc.CORE_TIME_SIGNAL: signal = subscription.get_dblock().get_signal_by_uname(signal_name) current_signals[signal_name] = {} current_signals[signal_name]['signal'] = signal current_signals[signal_name]['index'] = index index += 1 # ---------------------------- # Add new subscribed signals # ---------------------------- for signal_name in sorted(current_signals.keys()): if signal_name != CORE_TIME_SIGNAL: if signal_name not in self.signals: signal = current_signals[signal_name]['signal'] self.add_plot_item(signal, current_signals[signal_name]['index']) changes = True # ------------------------------- # Remove unsubscribed signals # ------------------------------- for signal_name in self.signals.copy(): if signal_name not in current_signals: if self.__legend__ is not None: self.remove_plot_item(signal_name) changes = True if changes: self.update_pens() self.update_signals() self.update_legend() self.update_rolling_plot() self.update_downsampling_rate() else: self.update_signals() #self.update_legend() def add_plot_item(self, signal, signal_id): """ Create a new plot item object for a given signal and internal id :param signal: DSignal object :param signal_id: plot internal signal id :return: """ signal_name = signal.uname if signal_name not in self.signals: self.signals[signal_name] = {} plot_item = PlotItem(signal, signal_id, self.__buffer_size__) plot_item.set_downsampling_rate(self.__downsampling_rate__) self.signals[signal_name] = plot_item def remove_plot_item(self, signal_name): """ Remove the plot item object for a given signal_name. :param signal_name: :return: """ if signal_name in self.signals: plot_item = self.signals[signal_name] # Remove all graphic objects for graphic in plot_item.graphics: self.__plotWidget__.removeItem(graphic) # Remove from Legend self.__legend__.removeItem(plot_item.signal_name) del self.signals[signal_name] def get_pen(self, index): """ Function get pen :param index: :return: """ index = int(index) style_index = index % len(self.__styles_selected__) style_code = int(self.__styles_selected__[style_index]) color_index = index % len(self.__colors_selected__) color_code = int(self.__colors_selected__[color_index]) if style_code in self.styles: style = self.styles[style_code] else: style = self.styles[0] if color_code in self.colors: color = self.colors[color_code] else: color = self.colors[0] return pg.mkPen(color=color, style=style) def update_rolling_plot(self): """ Used to update the rolling plot by resolving all dependencies. The configuration for the rolling plot depends on the current value in self.config['rolling_plot']['value'] :return: """ value = self.config['rolling_plot']['value'] self.__rolling_plot__ = int(float(self.config['rolling_plot']['value'])) == int('1') self.rolling_Checkbox.stateChanged.disconnect() self.rolling_Checkbox.setChecked(value == '1') self.rolling_Checkbox.stateChanged.connect(self.contextMenu_rolling_toogled) self.clear() for signal_name in self.signals: self.signals[signal_name].rolling_plot = self.__rolling_plot__ self.initiate_update_plot() def use_range_for_x(self, value): """ :param value: :return: """ reg = re.compile(r'(\d+\.\d+)') range = reg.findall(value) if len(range) == 2: #self.xRange_minEdit.setText(range[0]) #self.xRange_maxEdit.setText(range[1]) self.__plotWidget__.getPlotItem().getViewBox().setXRange(float(range[0]),float(range[1])) def use_range_for_y(self, value): """ :param value: :return: """ reg = re.compile(r'([-]{0,1}\d+\.\d+)') range = reg.findall(value) if len(range) == 2: self.yRange_minEdit.setText(range[0]) self.yRange_maxEdit.setText(range[1]) self.__plotWidget__.getPlotItem().getViewBox().setYRange(float(range[0]), float(range[1])) def setup_context_menu(self): """ :return: """ self.custMenu = QMenu("Options") self.axesMenu = QMenu('Y-Axis') self.gridMenu = QMenu('Grid') ##### Y-Range Actions self.yRange_Widget = QWidget() self.yRange_Layout = QVBoxLayout(self.yRange_Widget) self.yRange_Layout.setContentsMargins(2, 2, 2, 2) self.yRange_Layout.setSpacing(1) self.yAutoRangeButton = QPushButton() self.yAutoRangeButton.clicked.connect(self.contextMenu_yAutoRangeButton_clicked) self.yAutoRangeButton.setText('Use autorange') self.yRange_Layout.addWidget(self.yAutoRangeButton) ##### Y Line Edits # Layout self.yRange_EditWidget = QWidget() self.yRange_EditLayout = QHBoxLayout(self.yRange_EditWidget) self.yRange_EditLayout.setContentsMargins(2, 2, 2, 2) self.yRange_EditLayout.setSpacing(1) # get old values; reg = re.compile(r'(\d+\.\d+)') range = reg.findall(self.config['yRange']['value']) if len(range) == 2: y_min = range[0] y_max = range[1] else: y_min = '0.0' y_max = '1.0' rx = QRegExp(r'([-]{0,1}\d+\.\d+)') validator = QRegExpValidator(rx, self.__plotWidget__) # Min self.yRange_minEdit = QLineEdit() self.yRange_minEdit.setFixedWidth(80) self.yRange_minEdit.setText(y_min) self.yRange_minEdit.editingFinished.connect(self.contextMenu_yRange_toogle) self.yRange_minEdit.setValidator(validator) # Max self.yRange_maxEdit = QLineEdit() self.yRange_maxEdit.setFixedWidth(80) self.yRange_maxEdit.setText(y_max) self.yRange_maxEdit.editingFinished.connect(self.contextMenu_yRange_toogle) self.yRange_maxEdit.setValidator(validator) # addTo Layout self.yRange_EditLayout.addWidget(self.yRange_minEdit) self.yRange_EditLayout.addWidget(QLabel('<')) self.yRange_EditLayout.addWidget(self.yRange_maxEdit) self.yRange_Layout.addWidget(self.yRange_EditWidget) # build Action self.yRange_Action = QWidgetAction(self.__plotWidget__) self.yRange_Action.setDefaultWidget(self.yRange_Widget) ##### Rolling Plot self.rolling_Checkbox = QCheckBox() self.rolling_Checkbox.setText('Rolling plot') self.rolling_Checkbox.setChecked(self.config['rolling_plot']['value'] == '1') self.rolling_Checkbox.stateChanged.connect(self.contextMenu_rolling_toogled) self.rolling_Checkbox_Action = QWidgetAction(self.__plotWidget__) self.rolling_Checkbox_Action.setDefaultWidget(self.rolling_Checkbox) if self.__stp_active__: self.rolling_Checkbox.setDisabled(True) # show legend self.legend_Checkbox = QCheckBox() self.legend_Checkbox.setText('Show legend') self.legend_Checkbox.setChecked(self.config['show_legend']['value'] == '1') self.legend_Checkbox.stateChanged.connect(self.contextMenu_legend_toogled) self.legend_Checkbox_Action = QWidgetAction(self.__plotWidget__) self.legend_Checkbox_Action.setDefaultWidget(self.legend_Checkbox) ##### Build axes menu #self.axesMenu.addAction(self.xRange_Action) self.axesMenu.addSeparator().setText("Y-Range") self.axesMenu.addAction(self.yRange_Action) # Grid Menu: # ----------------------------------------------------------- # Y-Grid checkbox self.xGrid_Checkbox = QCheckBox() self.xGrid_Checkbox.stateChanged.connect(self.contextMenu_xGrid_toogle) self.xGrid_Checkbox.setText('X-Grid') self.xGrid_Action = QWidgetAction(self.__plotWidget__) self.xGrid_Action.setDefaultWidget(self.xGrid_Checkbox) self.gridMenu.addAction(self.xGrid_Action) # Check config for startup state if self.__show_grid_x__: self.xGrid_Checkbox.setChecked(True) # X-Grid checkbox self.yGrid_Checkbox = QCheckBox() self.yGrid_Checkbox.stateChanged.connect(self.contextMenu_yGrid_toogle) self.yGrid_Checkbox.setText('Y-Grid') self.yGrid_Action = QWidgetAction(self.__plotWidget__) self.yGrid_Action.setDefaultWidget(self.yGrid_Checkbox) self.gridMenu.addAction(self.yGrid_Action) # Check config for startup state if self.__show_grid_y__: self.yGrid_Checkbox.setChecked(True) # add Menus self.custMenu.addMenu(self.axesMenu) self.custMenu.addMenu(self.gridMenu) self.custMenu.addSeparator().setText("Rolling Plot") self.custMenu.addAction(self.rolling_Checkbox_Action) self.custMenu.addAction(self.legend_Checkbox_Action) self.__plotWidget__.getPlotItem().getViewBox().menu.clear() if not self.__papi_debug__: self.__plotWidget__.getPlotItem().ctrlMenu = [self.pl_create_control_context_menu(), self.custMenu] def showContextMenu(self): self.setup_context_menu() def contextMenu_yAutoRangeButton_clicked(self): mi = None ma = None if self.__stp_active__: mi = self.__stp_min_y ma = self.__stp_max_y else: for sig in self.signals: graphics = self.signals[sig].graphics buf = [] for graphic in graphics: buf.extend(graphic.y) ma_buf = max(buf) mi_buf = min(buf) if ma is not None: if ma_buf > ma: ma = ma_buf else: ma = ma_buf if mi is not None: if mi_buf < mi: mi = mi_buf else: mi = mi_buf ma = str(float(ma)) mi = str(float(mi)) self.yRange_maxEdit.setText(ma) self.yRange_minEdit.setText(mi) self.control_api.do_set_parameter(self.__id__, 'yRange', '[' +mi + ' ' + ma + ']') def contextMenu_rolling_toogled(self): if self.rolling_Checkbox.isChecked(): self.control_api.do_set_parameter(self.__id__, 'rolling', '1') else: self.control_api.do_set_parameter(self.__id__, 'rolling', '0') def contextMenu_legend_toogled(self): if self.legend_Checkbox.isChecked(): self.control_api.do_set_parameter(self.__id__, 'show_legend', '1') else: self.control_api.do_set_parameter(self.__id__, 'show_legend', '0') def contextMenu_xGrid_toogle(self): if self.xGrid_Checkbox.isChecked(): self.control_api.do_set_parameter(self.__id__, 'x-grid', '1') else: self.control_api.do_set_parameter(self.__id__, 'x-grid', '0') def contextMenu_yGrid_toogle(self): if self.yGrid_Checkbox.isChecked(): self.control_api.do_set_parameter(self.__id__, 'y-grid', '1') else: self.control_api.do_set_parameter(self.__id__, 'y-grid', '0') def contextMenu_yRange_toogle(self): mi = self.yRange_minEdit.text() ma = self.yRange_maxEdit.text() if float(mi) < float(ma): self.control_api.do_set_parameter(self.__id__, 'yRange', '[' + mi + ' ' + ma + ']') def update_signals(self): """ Used to update the signals as they are described in self.dplugin_info :return: """ dp_info = self.pl_get_dplugin_info() subscriptions = dp_info.get_subscribtions() for dpluginsub_id in subscriptions: for dblock_name in subscriptions[dpluginsub_id]: # get subscription for dblock subscription = subscriptions[dpluginsub_id][dblock_name] for signal_name in subscription.get_signals(): if signal_name != CORE_TIME_SIGNAL: signal = subscription.get_dblock().get_signal_by_uname(signal_name) self.signals[signal_name].update_signal(signal) def update_legend(self): """ Used to update the legend. :return: """ if not self.__show_legend__: return if self.__legend__ is not None: self.__legend__.scene().removeItem(self.__legend__) del self.__legend__ self.__legend__ = None self.__legend__ = self.__plotWidget__.getPlotItem().addLegend() if not self.__papi_debug__: self.update_signals() for signal_name in sorted(self.signals.keys()): graphic = self.signals[signal_name].get_legend_item() if graphic is not None: signal = self.signals[signal_name].signal legend_name = signal.dname self.__legend__.addItem(graphic, legend_name) def update_downsampling_rate(self): """ Used to update the downsampling rate by resolving all dependencies. The new downsampling rate is taken by using the private attribute __downsampling_rate__. :return: """ rate = self.__downsampling_rate__ self.__downsampling_rate_start__ = 0 self.__downsampling_rate__ = rate for signal_name in self.signals: self.signals[signal_name].set_downsampling_rate(rate) def plot_yrange_changed(self): viewbox = self.__plotWidget__.getPlotItem().getViewBox() [xRange, yRange] = viewbox.viewRange() self.control_api.do_update_parameter(self.__id__, 'yRange', '[' + str(yRange[0]) + ' ' + str(yRange[1]) + ']') self.config['yRange']['value'] = '[' + str(yRange[0]) + ' ' + str(yRange[1]) + ']' def cb_quit(self): """ Function quit plugin :return: """ print('PlotPerformance: will quit') def debug_papi(self): config = self.get_cb_plugin_configuration() config['yRange'] = { 'value': '[0.0 50.0]', 'regex': '(\d+\.\d+)', 'advanced': '1', 'display_text': 'y: range' } config['buffersize'] = { 'value': '1000', 'regex': '(\d+\.\d+)', 'advanced': '1', 'display_text': 'y: range' } config['downsampling_rate'] = { 'value': '10', 'regex': '(\d+\.\d+)', 'advanced': '1', 'display_text': 'y: range' } self.config = config self.__id__ = 0 self.cb_initialize_plugin(config) signal_1 = DSignal('signal_1') signal_2 = DSignal('signal_2') signal_3 = DSignal('signal_3') signal_4 = DSignal('signal_4') signal_5 = DSignal('signal_5') self.add_plot_item(signal_1, 1) self.add_plot_item(signal_2, 2) self.add_plot_item(signal_3, 3) self.add_plot_item(signal_4, 4) self.add_plot_item(signal_5, 5) self.update_pens() self.update_legend() pass def cb_get_plugin_configuration(self): """ Function get plugin configuration :return {}: """ config = { 'x-grid': { 'value': "0", 'regex': '^(1|0)$', 'type': 'bool', 'display_text': 'Grid-X' }, 'y-grid': { 'value': "0", 'regex': '^(1|0)$', 'type': 'bool', 'display_text': 'Grid-Y' }, 'color': { 'value': "[0 1 2 3 4]", 'regex': '^\[(\s*\d\s*)+\]', 'advanced': '1', 'display_text': 'Color' }, 'style': { 'value': "[0 0 0 0 0]", 'regex': '^\[(\s*\d\s*)+\]', 'advanced': '1', 'display_text': 'Style' }, 'buffersize': { 'value': "100", 'regex': '^(\d+)$', 'advanced': '1', 'display_text': 'Buffersize' }, 'downsampling_rate': { 'value': "1", 'regex': '(\d+)' }, 'rolling_plot': { 'value': '0', 'regex': '^(1|0)$', 'type': 'bool', 'display_text': 'Rolling Plot' }, 'yRange': { 'value': '[0.0 1.0]', 'regex': '^\[(\d+\.\d+)\s+(\d+\.\d+)\]$', 'advanced': '1', 'display_text': 'y: range' }, 'show_legend' : { 'value' : '1', 'regex' : pc.REGEX_BOOL_BIN, 'display_text' : 'Enable/Disable legend', 'type' : pc.CFG_TYPE_BOOL } } # http://www.regexr.com/ return config def clear(self): """ :return: """ self.__plotWidget__.clear() self.__tbuffer__.clear() for signal_name in self.signals: self.signals[signal_name].clear()
def UploadAction(self): upload_widget = QWidget() self.upload_action = QWidgetAction(self.menu) self.upload_action.setIcon(QIcon(QPixmap("./icons/file.png"))) self.upload_action.setIconText("加载文件") self.upload_action.triggered.connect(self.getfile)
class SegyViewWidget(QWidget): def __init__(self, filename, show_toolbar=True, color_maps=None, width=11.7, height=8.3, dpi=100, segyioargs={}, parent=None): QWidget.__init__(self, parent) inline = SliceModel("Inline", SD.inline, SD.crossline, SD.depth) xline = SliceModel("Crossline", SD.crossline, SD.inline, SD.depth) depth = SliceModel("Depth", SD.depth, SD.inline, SD.crossline) slice_models = [inline, xline, depth] slice_data_source = SliceDataSource(filename, **segyioargs) self._slice_data_source = slice_data_source self._context = SliceViewContext(slice_models, slice_data_source) self._context.show_indicators(True) self._slice_view_widget = SliceViewWidget(self._context, width, height, dpi, self) layout = QVBoxLayout() self._settings_window = SettingsWindow(self._context, self) self._help_window = HelpWindow(self) self._toolbar = self._create_toolbar(color_maps) self._toolbar.setVisible(show_toolbar) layout.addWidget(self._toolbar) layout.addWidget(self._slice_view_widget) self.setLayout(layout) @property def context(self): """ :rtype: SliceViewContext""" return self._context @property def slice_data_source(self): """ :rtype: SliceDataSource""" return self._slice_data_source @property def toolbar(self): """ :rtype: QToolBar """ return self._toolbar @property def slice_view_widget(self): """ :rtype: SliceViewWidget """ return self._slice_view_widget @property def settings_window(self): """ :rtype: QWidget """ return self._settings_window @property def help_window(self): """ :rtype: QWidget """ return self._help_window # custom signal slots are required to be manually disconnected # https://stackoverflow.com/questions/15600014/pyqt-disconnect-slots-new-style # def __del__(self): # self._layout_combo.layout_changed.disconnect(self._slice_view_widget.set_plot_layout) def _create_toolbar(self, color_maps): toolbar = QToolBar() toolbar.setFloatable(False) toolbar.setMovable(False) self._layout_combo = LayoutCombo() self._layout_combo_action = QWidgetAction(self._layout_combo) self._layout_combo_action.setDefaultWidget(self._layout_combo) toolbar.addAction(self._layout_combo_action) self._layout_combo.layout_changed.connect( self._slice_view_widget.set_plot_layout) # self._colormap_combo = ColormapCombo(['seismic', 'spectral', 'RdGy', 'hot', 'jet', 'gray']) self._colormap_combo = ColormapCombo(color_maps) self._colormap_combo.currentIndexChanged[int].connect( self._colormap_changed) toolbar.addWidget(self._colormap_combo) self._save_button = QToolButton() self._save_button.setToolTip("Save as image") self._save_button.setIcon(resource_icon("table_export.png")) self._save_button.clicked.connect(self._save_figure) toolbar.addWidget(self._save_button) self._settings_button = QToolButton() self._settings_button.setToolTip("Toggle settings visibility") self._settings_button.setIcon(resource_icon("cog.png")) self._settings_button.setCheckable(True) self._settings_button.toggled.connect(self._show_settings) toolbar.addWidget(self._settings_button) self._help_button = QToolButton() self._help_button.setToolTip("View help") self._help_button.setIcon(resource_icon("help.png")) self._help_button.setCheckable(True) self._help_button.toggled.connect(self._show_help) toolbar.addWidget(self._help_button) def toggle_on_close(event): self._settings_button.setChecked(False) event.accept() def toggle_on_close_help(event): self._help_button.setChecked(False) event.accept() self._settings_window.closeEvent = toggle_on_close self._help_window.closeEvent = toggle_on_close_help self._colormap_combo.setCurrentIndex(45) self.set_default_layout() return toolbar def _colormap_changed(self, index): colormap = str(self._colormap_combo.itemText(index)) self._context.set_colormap(colormap) def _interpolation_changed(self, index): interpolation_name = str(self._interpolation_combo.itemText(index)) self._context.set_interpolation(interpolation_name) def _save_figure(self): formats = "Portable Network Graphic (*.png);;Adobe Acrobat (*.pdf);;Scalable Vector Graphics (*.svg)" output_file = QFileDialog.getSaveFileName(self, "Save as image", "untitled.png", formats) output_file = str(output_file).strip() if len(output_file) == 0: return image_size = self._context.image_size if not image_size: fig = self._slice_view_widget else: w, h, dpi = image_size fig = SliceViewWidget(self._context, width=w, height=h, dpi=dpi) fig.set_plot_layout( self._slice_view_widget.layout_figure().current_layout()) fig.layout_figure().savefig(output_file) def set_source_filename(self, filename): self._slice_data_source.set_source_filename(filename) def set_default_layout(self): # default slice view layout depends on the file size if self._slice_data_source.file_size < 8 * 10**8: self._layout_combo.setCurrentIndex( self._layout_combo.DEFAULT_SMALL_FILE_LAYOUT) else: self._layout_combo.setCurrentIndex( self._layout_combo.DEFAULT_LARGE_FILE_LAYOUT) def as_depth(self): self._context.samples_unit = 'Depth (m)' def _show_settings(self, toggled): self._settings_window.setVisible(toggled) if self._settings_window.isMinimized(): self._settings_window.showNormal() def _show_help(self, toggled): self._help_window.setVisible(toggled) if self._help_window.isMinimized(): self._help_window.showNormal() def show_toolbar(self, toolbar, layout_combo=True, colormap=True, save=True, settings=True): self._toolbar.setVisible(toolbar) self._colormap_combo.setDisabled(not colormap) self._save_button.setDisabled(not save) self._settings_button.setDisabled(not settings) self._layout_combo_action.setVisible(layout_combo)
class MainWindow(MainWindowUI, MainWindowBase): save_perspective_action: QAction perspective_list_action: QWidgetAction perspective_combo_box: QComboBox dock_manager: QtAds.CDockManager def __init__(self, parent=None): super().__init__(parent) self.save_perspective_action = None self.perspective_list_action = None self.perspective_combo_box = None self.dock_manager = None self.setupUi(self) self.create_actions() # uncomment the following line if the tab close button should be # a QToolButton instead of a QPushButton # QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.configFlags() | QtAds.CDockManager.TabCloseButtonIsToolButton) # uncomment the following line if you want to use opaque undocking and # opaque splitter resizing #QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.DefaultOpaqueConfig) # uncomment the following line if you want a fixed tab width that does # not change if the visibility of the close button changes #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.RetainTabSizeWhenCloseButtonHidden, True) # uncomment the following line if you don't want close button on DockArea's title bar #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasCloseButton, False) # uncomment the following line if you don't want undock button on DockArea's title bar #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasUndockButton, False) # uncomment the following line if you don't want tabs menu button on DockArea's title bar #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasTabsMenuButton, False) # uncomment the following line if you don't want disabled buttons to appear on DockArea's title bar #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHideDisabledButtons, True) # uncomment the following line if you want to show tabs menu button on DockArea's title bar only when there are more than one tab and at least of them has elided title #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaDynamicTabsMenuButtonVisibility, True) # uncomment the following line if you want floating container to always show application title instead of active dock widget's title #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FloatingContainerHasWidgetTitle, False) # uncomment the following line if you want floating container to show active dock widget's icon instead of always showing application icon #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FloatingContainerHasWidgetIcon, True) # uncomment the following line if you want a central widget in the main dock container (the dock manager) without a titlebar # If you enable this code, you can test it in the demo with the Calendar 0 # dock widget. #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.HideSingleCentralWidgetTitleBar, True) # uncomment the following line to enable focus highlighting of the dock # widget that has the focus QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FocusHighlighting, True) # uncomment if you would like to enable an equal distribution of the # available size of a splitter to all contained dock widgets # QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.EqualSplitOnInsertion, True) # Now create the dock manager and its content self.dock_manager = QtAds.CDockManager(self) # Uncomment the following line to have the old style where the dock # area close button closes the active tab # QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.DockAreaHasCloseButton # | QtAds.CDockManager.DockAreaCloseButtonClosesTab) self.perspective_combo_box.activated[str].connect( self.dock_manager.openPerspective) self.create_content() # Default window geometry - center on screen self.resize(1280, 720) self.setGeometry( QStyle.alignedRect( Qt.LeftToRight, Qt.AlignCenter, self.frameSize(), QGuiApplication.primaryScreen().availableGeometry())) # self.restore_state() self.restore_perspectives() def create_content(self): # Test container docking dock_widget = self.create_calendar_dock_widget() dock_widget.setFeature(QtAds.CDockWidget.DockWidgetClosable, False) special_dock_area = self.dock_manager.addDockWidget( QtAds.LeftDockWidgetArea, dock_widget) # For this Special Dock Area we want to avoid dropping on the center of it (i.e. we don't want this widget to be ever tabbified): special_dock_area.setAllowedAreas(QtAds.OuterDockAreas) # special_dock_area.setAllowedAreas(QtAds.LeftDockWidgetArea | QtAds.RightDockWidgetArea) # just for testing dock_widget = self.create_long_text_label_dock_widget() dock_widget.setFeature(QtAds.CDockWidget.DockWidgetFocusable, False) self.dock_manager.addDockWidget(QtAds.LeftDockWidgetArea, dock_widget) file_system_widget = self.create_file_system_tree_dock_widget() tool_bar = file_system_widget.createDefaultToolBar() tool_bar.addAction(self.actionSaveState) tool_bar.addAction(self.actionRestoreState) file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetFloatable, False) append_feature_string_to_window_title(file_system_widget) self.dock_manager.addDockWidget(QtAds.BottomDockWidgetArea, file_system_widget) file_system_widget = self.create_file_system_tree_dock_widget() file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetMovable, False) file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetFloatable, False) append_feature_string_to_window_title(file_system_widget) # Test custom factory - we inject a help button into the title bar QtAds.CDockComponentsFactory.setFactory(CCustomComponentsFactory()) top_dock_area = self.dock_manager.addDockWidget( QtAds.TopDockWidgetArea, file_system_widget) QtAds.CDockComponentsFactory.resetDefaultFactory() # We create a calendar widget and clear all flags to prevent the dock area # from closing dock_widget = self.create_calendar_dock_widget() dock_widget.setTabToolTip("Tab ToolTip\nHodie est dies magna") dock_area = self.dock_manager.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, top_dock_area) # Now we add a custom button to the dock area title bar that will create # new editor widgets when clicked custom_button = QToolButton(dock_area) custom_button.setToolTip("Create Editor") custom_button.setIcon(svg_icon(":/adsdemo/images/plus.svg")) custom_button.setAutoRaise(True) title_bar = dock_area.titleBar() index = title_bar.indexOf(title_bar.tabBar()) title_bar.insertWidget(index + 1, custom_button) def on_button_clicked(): dock_widget = self.create_editor_widget() dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True) self.dock_manager.addDockWidgetTabToArea(dock_widget, dock_area) dock_widget.closeRequested.connect(self.on_editor_close_requested) custom_button.clicked.connect(on_button_clicked) # Test dock area docking right_dock_area = self.dock_manager.addDockWidget( QtAds.RightDockWidgetArea, self.create_long_text_label_dock_widget(), top_dock_area) self.dock_manager.addDockWidget( QtAds.TopDockWidgetArea, self.create_long_text_label_dock_widget(), right_dock_area) bottom_dock_area = self.dock_manager.addDockWidget( QtAds.BottomDockWidgetArea, self.create_long_text_label_dock_widget(), right_dock_area) self.dock_manager.addDockWidget( QtAds.CenterDockWidgetArea, self.create_long_text_label_dock_widget(), right_dock_area) self.dock_manager.addDockWidget( QtAds.CenterDockWidgetArea, self.create_long_text_label_dock_widget(), bottom_dock_area) action = self.menuTests.addAction("Set {} Floating".format( dock_widget.windowTitle())) action.triggered.connect(dock_widget.setFloating) action = self.menuTests.addAction("Set {} As Current Tab".format( dock_widget.windowTitle())) action.triggered.connect(dock_widget.setAsCurrentTab) action = self.menuTests.addAction("Raise {}".format( dock_widget.windowTitle())) action.triggered.connect(dock_widget.raise_) if ACTIVEX_AVAILABLE: flags = self.dock_manager.configFlags() if flags & QtAds.CDockManager.OpaqueUndocking: self.dock_manager.addDockWidget(QtAds.CenterDockWidgetArea, self.create_activex_widget(), right_dock_area) for dock_widget in self.dock_manager.dockWidgetsMap().values(): dock_widget.viewToggled.connect(self.on_view_toggled) dock_widget.visibilityChanged.connect( self.on_view_visibility_changed) def create_actions(self): self.toolBar.addAction(self.actionSaveState) self.toolBar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.actionSaveState.setIcon(svg_icon(":/adsdemo/images/save.svg")) self.toolBar.addAction(self.actionRestoreState) self.actionRestoreState.setIcon( svg_icon(":/adsdemo/images/restore.svg")) self.save_perspective_action = QAction("Create Perspective", self) self.save_perspective_action.setIcon( svg_icon(":/adsdemo/images/picture_in_picture.svg")) self.save_perspective_action.triggered.connect(self.save_perspective) self.perspective_list_action = QWidgetAction(self) self.perspective_combo_box = QComboBox(self) self.perspective_combo_box.setSizeAdjustPolicy( QComboBox.AdjustToContents) self.perspective_combo_box.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.perspective_list_action.setDefaultWidget( self.perspective_combo_box) self.toolBar.addSeparator() self.toolBar.addAction(self.perspective_list_action) self.toolBar.addAction(self.save_perspective_action) a = self.toolBar.addAction("Create Floating Editor") a.setProperty("Floating", True) a.setToolTip( "Creates floating dynamic dockable editor windows that are deleted on close" ) a.setIcon(svg_icon(":/adsdemo/images/note_add.svg")) a.triggered.connect(self.create_editor) self.menuTests.addAction(a) a = self.toolBar.addAction("Create Docked Editor") a.setProperty("Floating", False) a.setToolTip( "Creates a docked editor windows that are deleted on close") a.setIcon(svg_icon(":/adsdemo/images/docked_editor.svg")) a.triggered.connect(self.create_editor) self.menuTests.addAction(a) a = self.toolBar.addAction("Create Floating Table") a.setToolTip( "Creates floating dynamic dockable table with millions of entries") a.setIcon(svg_icon(":/adsdemo/images/grid_on.svg")) a.triggered.connect(self.create_table) self.menuTests.addAction(a) self.menuTests.addSeparator() a = self.menuTests.addAction("Show Status Dialog") a.triggered.connect(self.show_status_dialog) self.menuTests.addSeparator() def closeEvent(self, event: QCloseEvent): self.save_state() super().closeEvent(event) def on_actionSaveState_triggered(self, state: bool): qDebug("MainWindow::on_action_save_state_triggered") self.save_state() def on_actionRestoreState_triggered(self, state: bool): qDebug("MainWindow::on_action_restore_state_triggered") self.restore_state() def save_perspective(self): perspective_name, ok = QInputDialog.getText(self, "Save perspective", "Enter unique name:") if ok and perspective_name: self.dock_manager.addPerspective(perspective_name) _ = QSignalBlocker(self.perspective_combo_box) self.perspective_combo_box.clear() self.perspective_combo_box.addItems( self.dock_manager.perspectiveNames()) self.perspective_combo_box.setCurrentText(perspective_name) self.save_perspectives() def on_view_toggled(self, open: bool): dock_widget = self.sender() if dock_widget is None: return qDebug("{} view_toggled({})".format(dock_widget.objectName(), open)) def on_view_visibility_changed(self, visible: bool): dock_widget = self.sender() if dock_widget is None: return # qDebug("{} visibility_changed({})".format(dock_widget.objectName(), visible)) def create_editor(self): sender = self.sender() floating = sender.property("Floating") print("Floating:", floating) dock_widget = self.create_editor_widget() dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True) dock_widget.closeRequested.connect(self.on_editor_close_requested) if floating: floating_widget = self.dock_manager.addDockWidgetFloating( dock_widget) floating_widget.move(QPoint(20, 20)) else: self.dock_manager.addDockWidget(QtAds.TopDockWidgetArea, dock_widget) def on_editor_close_requested(self): dock_widget = self.sender() result = QMessageBox.question( self, "Close Editor", "Editor {} contains unsaved changes? Would you like to close it?". format(dock_widget.windowTitle())) if result == QMessageBox.Yes: dock_widget.closeDockWidget() def create_table(self): dock_widget = self.create_table_widget() dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True) floating_widget = self.dock_manager.addDockWidgetFloating(dock_widget) floating_widget.move(QPoint(40, 40)) def show_status_dialog(self): dialog = CStatusDialog(self.dock_manager) dialog.exec_() def save_state(self): ''' Saves the dock manager state and the main window geometry ''' settings = QSettings("Settings.ini", QSettings.IniFormat) settings.setValue("mainWindow/Geometry", self.saveGeometry()) settings.setValue("mainWindow/State", self.saveState()) settings.setValue("mainWindow/DockingState", self.dock_manager.saveState()) def restore_state(self): ''' Restores the dock manager state ''' settings = QSettings("Settings.ini", QSettings.IniFormat) geom = settings.value("mainWindow/Geometry") if geom is not None: self.restoreGeometry(geom) state = settings.value("mainWindow/State") if state is not None: self.restoreState(state) state = settings.value("mainWindow/DockingState") if state is not None: self.dock_manager.restore_state(state) def save_perspectives(self): ''' Save the list of perspectives ''' settings = QSettings("Settings.ini", QSettings.IniFormat) self.dock_manager.savePerspectives(settings) def restore_perspectives(self): ''' Restore the perspective listo of the dock manager ''' settings = QSettings("Settings.ini", QSettings.IniFormat) self.dock_manager.loadPerspectives(settings) self.perspective_combo_box.clear() self.perspective_combo_box.addItems( self.dock_manager.perspectiveNames()) def save_perspective(self): perspective_name, ok = QInputDialog.getText(self, 'Save perspective', 'Enter unique name:') if ok and perspective_name: self.dock_manager.addPerspective(perspective_name) _ = QSignalBlocker(self.perspective_combo_box) self.perspective_combo_box.clear() self.perspective_combo_box.addItems( self.dock_manager.perspectiveNames()) self.perspective_combo_box.setCurrentText(perspective_name) self.save_perspectives() def create_long_text_label_dock_widget(self) -> QtAds.CDockWidget: label = QLabel() label.setWordWrap(True) label.setAlignment(Qt.AlignTop | Qt.AlignLeft) label.setText('''Label {} {} - Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. '''.format(_State.label_count, datetime.datetime.now().strftime("%H:%M:%S:%f"))) dock_widget = QtAds.CDockWidget("Label {}".format(_State.label_count)) _State.label_count += 1 dock_widget.setWidget(label) self.menuView.addAction(dock_widget.toggleViewAction()) return dock_widget def create_calendar_dock_widget(self) -> QtAds.CDockWidget: widget = QCalendarWidget() dock_widget = QtAds.CDockWidget("Calendar {}".format( _State.calendar_count)) _State.calendar_count += 1 # The following lines are for testing the setWidget() and takeWidget() # functionality dock_widget.setWidget(widget) dock_widget.setWidget( widget ) # what happens if we set a widget if a widget is already set dock_widget.takeWidget() # we remove the widget dock_widget.setWidget( widget) # and set the widget again - there should be no error dock_widget.setToggleViewActionMode(QtAds.CDockWidget.ActionModeShow) dock_widget.setIcon(svg_icon(":/adsdemo/images/date_range.svg")) self.menuView.addAction(dock_widget.toggleViewAction()) return dock_widget def create_file_system_tree_dock_widget(self) -> QtAds.CDockWidget: widget = QTreeView() widget.setFrameShape(QFrame.NoFrame) m = QFileSystemModel(widget) m.setRootPath(QDir.currentPath()) widget.setModel(m) dock_widget = QtAds.CDockWidget("Filesystem {}".format( _State.file_system_count)) _State.file_system_count += 1 dock_widget.setWidget(widget) self.menuView.addAction(dock_widget.toggleViewAction()) return dock_widget def create_editor_widget(self) -> QtAds.CDockWidget: widget = QPlainTextEdit() widget.setPlaceholderText( "This is an editor. If you close the editor, it will be " "deleted. Enter your text here.") widget.setStyleSheet("border: none") dock_widget = QtAds.CDockWidget("Editor {}".format( _State.editor_count)) _State.editor_count += 1 dock_widget.setWidget(widget) dock_widget.setIcon(svg_icon(":/adsdemo/images/edit.svg")) dock_widget.setFeature(QtAds.CDockWidget.CustomCloseHandling, True) self.menuView.addAction(dock_widget.toggleViewAction()) options_menu = QMenu(dock_widget) options_menu.setTitle("Options") options_menu.setToolTip(options_menu.title()) options_menu.setIcon( svg_icon(":/adsdemo/images/custom-menu-button.svg")) menu_action = options_menu.menuAction() # The object name of the action will be set for the QToolButton that # is created in the dock area title bar. You can use this name for CSS # styling menu_action.setObjectName("options_menu") dock_widget.setTitleBarActions([options_menu.menuAction()]) a = options_menu.addAction("Clear Editor") a.triggered.connect(widget.clear) return dock_widget def create_table_widget(self) -> QtAds.CDockWidget: widget = CMinSizeTableWidget() dock_widget = QtAds.CDockWidget("Table {}".format(_State.table_count)) _State.table_count += 1 COLCOUNT = 5 ROWCOUNT = 30 widget.setColumnCount(COLCOUNT) widget.setRowCount(ROWCOUNT) for col in range(ROWCOUNT): widget.setHorizontalHeaderItem( col, QTableWidgetItem("Col {}".format(col + 1))) for row in range(ROWCOUNT): widget.setItem( row, col, QTableWidgetItem("T {:}-{:}".format(row + 1, col + 1))) dock_widget.setWidget(widget) dock_widget.setIcon(svg_icon(":/adsdemo/images/grid_on.svg")) dock_widget.setMinimumSizeHintMode( QtAds.CDockWidget.MinimumSizeHintFromContent) toolbar = dock_widget.createDefaultToolBar() action = toolbar.addAction(svg_icon(":/adsdemo/images/fullscreen.svg"), "Toggle Fullscreen") def on_toggle_fullscreen(): if dock_widget.isFullScreen(): dock_widget.showNormal() else: dock_widget.showFullScreen() action.triggered.connect(on_toggle_fullscreen) self.menuView.addAction(dock_widget.toggleViewAction()) return dock_widget def create_activex_widget(self, parent: QWidget = None) -> QtAds.CDockWidget: widget = QAxWidget("{6bf52a52-394a-11d3-b153-00c04f79faa6}", parent) dock_widget = QtAds.CDockWidget("Active X {}".format( _State.activex_count)) _State.activex_count += 1 dock_widget.setWidget(widget) self.menuView.addAction(dock_widget.toggleViewAction()) return dock_widget
def __init__(self, widget, parent=None): QWidgetAction.__init__(self, parent) self.widget = widget self.setDefaultWidget(self.widget) widget.setMyAction(self) # Let widget know about action.