class CollapsibleSection(QFrame): def __init__(self, header_text, init_collapsed=False, is_top=False): super().__init__() if not is_top: self.setObjectName("CollapsibleSection") self.setStyleSheet("#CollapsibleSection{border-top: 1px solid lightgrey;}") self._layout = QVBoxLayout(self) self._layout.setContentsMargins(0, 0, 0, 0) self._layout.setSpacing(0) self.setLayout(self._layout) self._header_widget = QWidget() self.body_widget = QWidget() self._layout.addWidget(self._header_widget) self._layout.addWidget(self.body_widget) self.grid = QGridLayout(self.body_widget) self.grid.setContentsMargins(9, 0, 9, 9) self.grid.setColumnStretch(0, 1) self.grid.setColumnStretch(1, 1) self._header_widget_layout = QHBoxLayout(self._header_widget) self._header_widget_layout.setContentsMargins(7, 7, 7, 7) self._header_widget.setLayout(self._header_widget_layout) self._button = QToolButton() self._button.setText(header_text) self._button.setCheckable(True) self._button.setStyleSheet("QToolButton { border: none; }") self._button.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) self._button.pressed.connect(self.button_event) self.button_event(override=init_collapsed) self._header_widget_layout.addWidget(self._button) self._header_widget_layout.addStretch() def button_event(self, override=None): if override is None: checked = not self._button.isChecked() else: checked = override self._button.setChecked(checked) if checked: # collapsed self._button.setArrowType(QtCore.Qt.ArrowType.RightArrow) self.body_widget.hide() else: self._button.setArrowType(QtCore.Qt.ArrowType.DownArrow) self.body_widget.show()
class CollapsibleBox(QWidget): def __init__(self, title: str, bg_color: str, parent=None): super(CollapsibleBox, self).__init__(parent) self.setAutoFillBackground(True) self.toggle_button = QToolButton(text=title, checkable=True, checked=False) style_sheet = "border: none;" style_sheet += "border-image: url(" + bg_color + ");" style_sheet += "font: bold 15px;" self.toggle_button.setStyleSheet(style_sheet) self.toggle_button.setToolButtonStyle( QtCore.Qt.ToolButtonTextBesideIcon) self.toggle_button.setArrowType(QtCore.Qt.RightArrow) self.toggle_button.setMinimumHeight(30) self.toggle_button.clicked.connect(self.on_clicked) self.content_area = QScrollArea() self.content_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.content_area.setFrameShape(QFrame.NoFrame) self.content_area.setHidden(True) lay = QVBoxLayout(self) lay.setSpacing(0) lay.setContentsMargins(0, 0, 0, 0) lay.addWidget(self.toggle_button) lay.addWidget(self.content_area) @QtCore.pyqtSlot() def on_clicked(self): checked = self.toggle_button.isChecked() self.toggle_button.setArrowType( QtCore.Qt.DownArrow if checked else QtCore.Qt.RightArrow) if checked: self.content_area.setHidden(False) else: self.content_area.setHidden(True) def setContentLayout(self, layout): lay = self.content_area.layout() del lay self.content_area.setLayout(layout)
class MainWindow(QMainWindow): def __init__(self, gui): super(MainWindow, self).__init__() self.gui = gui self.gateways = [] self.welcome_dialog = None self.recovery_key_exporter = None self.setWindowTitle(APP_NAME) self.setMinimumSize(QSize(600, 400)) self.setUnifiedTitleAndToolBarOnMac(True) self.shortcut_new = QShortcut(QKeySequence.New, self) self.shortcut_new.activated.connect(self.show_welcome_dialog) self.shortcut_open = QShortcut(QKeySequence.Open, self) self.shortcut_open.activated.connect(self.select_folder) self.shortcut_close = QShortcut(QKeySequence.Close, self) self.shortcut_close.activated.connect(self.close) self.shortcut_quit = QShortcut(QKeySequence.Quit, self) self.shortcut_quit.activated.connect(self.confirm_quit) self.central_widget = CentralWidget(self.gui) self.setCentralWidget(self.central_widget) font = QFont() if sys.platform == 'darwin': font.setPointSize(11) else: font.setPointSize(8) folder_icon_default = QFileIconProvider().icon(QFileInfo(config_dir)) folder_icon_composite = CompositePixmap( folder_icon_default.pixmap(256, 256), resource('green-plus.png')) folder_icon = QIcon(folder_icon_composite) folder_action = QAction(folder_icon, "Add folder", self) folder_action.setToolTip("Add a folder...") folder_action.setFont(font) folder_action.triggered.connect(self.select_folder) invite_action = QAction( QIcon(resource('invite.png')), "Enter Code", self) invite_action.setToolTip("Enter an Invite Code...") invite_action.setFont(font) invite_action.triggered.connect(self.open_invite_receiver) history_action = QAction( QIcon(resource('time.png')), 'History', self) history_action.setToolTip("View history") history_action.setFont(font) history_action.triggered.connect(self.on_history_button_clicked) self.history_button = QToolButton(self) self.history_button.setDefaultAction(history_action) self.history_button.setCheckable(True) self.history_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) spacer_left = QWidget() spacer_left.setSizePolicy(QSizePolicy.Expanding, 0) self.combo_box = ComboBox() self.combo_box.currentIndexChanged.connect(self.on_grid_selected) spacer_right = QWidget() spacer_right.setSizePolicy(QSizePolicy.Expanding, 0) share_action = QAction(QIcon(resource('share.png')), "Share", self) share_action.setToolTip("Share...") share_action.setFont(font) share_action.triggered.connect(self.open_invite_sender_dialog) recovery_action = QAction( QIcon(resource('key.png')), "Recovery", self) recovery_action.setToolTip("Import/Export Recovery Key...") recovery_action.setFont(font) import_action = QAction(QIcon(), "Import Recovery Key...", self) import_action.setToolTip("Import Recovery Key...") import_action.triggered.connect(self.import_recovery_key) export_action = QAction(QIcon(), "Export Recovery Key...", self) export_action.setToolTip("Export Recovery Key...") export_action.setShortcut(QKeySequence.Save) export_action.triggered.connect(self.export_recovery_key) recovery_menu = QMenu(self) recovery_menu.addAction(import_action) recovery_menu.addAction(export_action) recovery_button = QToolButton(self) recovery_button.setDefaultAction(recovery_action) recovery_button.setMenu(recovery_menu) recovery_button.setPopupMode(2) recovery_button.setStyleSheet( 'QToolButton::menu-indicator { image: none }') recovery_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) preferences_action = QAction( QIcon(resource('preferences.png')), "Preferences", self) preferences_action.setStatusTip("Preferences") preferences_action.setToolTip("Preferences") preferences_action.setFont(font) preferences_action.setShortcut(QKeySequence.Preferences) preferences_action.triggered.connect(self.gui.show_preferences_window) self.toolbar = self.addToolBar('') if sys.platform != 'darwin': self.toolbar.setStyleSheet(""" QToolBar { border: 0px } QToolButton { color: rgb(50, 50, 50) } """) else: self.toolbar.setStyleSheet( "QToolButton { color: rgb(50, 50, 50) }") self.toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.toolbar.setIconSize(QSize(24, 24)) self.toolbar.setMovable(False) self.toolbar.addAction(folder_action) self.toolbar.addAction(invite_action) self.toolbar.addWidget(self.history_button) self.toolbar.addWidget(spacer_left) self.toolbar.addWidget(self.combo_box) self.toolbar.addWidget(spacer_right) self.toolbar.addAction(share_action) self.toolbar.addWidget(recovery_button) self.toolbar.addAction(preferences_action) if sys.platform != 'win32': # Text is getting clipped on Windows 10 for action in self.toolbar.actions(): widget = self.toolbar.widgetForAction(action) if isinstance(widget, QToolButton): widget.setMaximumWidth(68) self.active_invite_sender_dialogs = [] self.active_invite_receiver_dialogs = [] def populate(self, gateways): for gateway in gateways: if gateway not in self.gateways: self.central_widget.add_folders_view(gateway) self.central_widget.add_history_view(gateway) self.combo_box.add_gateway(gateway) self.gateways.append(gateway) self.gui.systray.menu.populate() def current_view(self): try: w = self.central_widget.folders_views[self.combo_box.currentData()] except KeyError: return None return w.layout().itemAt(0).widget() def select_folder(self): self.show_folders_view() view = self.current_view() if view: view.select_folder() def set_current_grid_status(self): current_view = self.current_view() if not current_view: return self.gui.systray.update() def show_folders_view(self): try: self.central_widget.setCurrentWidget( self.central_widget.folders_views[self.combo_box.currentData()] ) except KeyError: pass self.set_current_grid_status() def show_history_view(self): try: self.central_widget.setCurrentWidget( self.central_widget.history_views[self.combo_box.currentData()] ) except KeyError: pass self.set_current_grid_status() def show_welcome_dialog(self): if self.welcome_dialog: self.welcome_dialog.close() self.welcome_dialog = WelcomeDialog(self.gui, self.gateways) self.welcome_dialog.show() self.welcome_dialog.raise_() def on_grid_selected(self, index): if index == self.combo_box.count() - 1: self.show_welcome_dialog() if not self.combo_box.currentData(): return if self.history_button.isChecked(): self.show_history_view() else: self.show_folders_view() self.setWindowTitle( "{} - {}".format(APP_NAME, self.combo_box.currentData().name) ) def confirm_export(self, path): if os.path.isfile(path): info( self, "Export successful", "Recovery Key successfully exported to {}".format(path)) else: error( self, "Error exporting Recovery Key", "Destination file not found after export: {}".format(path)) def export_recovery_key(self, gateway=None): self.show_folders_view() if not gateway: gateway = self.combo_box.currentData() self.recovery_key_exporter = RecoveryKeyExporter(self) self.recovery_key_exporter.done.connect(self.confirm_export) self.recovery_key_exporter.do_export(gateway) def import_recovery_key(self): # XXX Quick hack for user-testing; change later self.welcome_dialog = WelcomeDialog(self.gui, self.gateways) self.welcome_dialog.on_restore_link_activated() def on_history_button_clicked(self): if not self.history_button.isChecked(): self.history_button.setChecked(True) self.show_history_view() else: self.history_button.setChecked(False) self.show_folders_view() def on_invite_received(self, gateway): self.populate([gateway]) for view in self.central_widget.views: view.model().monitor.scan_rootcap('star.png') def on_invite_closed(self, obj): try: self.active_invite_receiver_dialogs.remove(obj) except ValueError: pass def open_invite_receiver(self): invite_receiver_dialog = InviteReceiverDialog(self.gateways) invite_receiver_dialog.done.connect(self.on_invite_received) invite_receiver_dialog.closed.connect(self.on_invite_closed) invite_receiver_dialog.show() self.active_invite_receiver_dialogs.append(invite_receiver_dialog) def open_invite_sender_dialog(self): gateway = self.combo_box.currentData() if gateway: view = self.current_view() if view: invite_sender_dialog = InviteSenderDialog( gateway, self.gui, view.get_selected_folders()) else: invite_sender_dialog = InviteSenderDialog(gateway, self.gui) invite_sender_dialog.closed.connect( self.active_invite_sender_dialogs.remove) invite_sender_dialog.show() self.active_invite_sender_dialogs.append(invite_sender_dialog) def confirm_quit(self): folder_loading = False folder_syncing = False for model in [view.model() for view in self.central_widget.views]: for row in range(model.rowCount()): status = model.item(row, 1).data(Qt.UserRole) mtime = model.item(row, 2).data(Qt.UserRole) if not status and not mtime: # "Loading..." and not yet synced folder_loading = True break elif status == 1: # "Syncing" folder_syncing = True break msg = QMessageBox(self) if folder_loading: msg.setIcon(QMessageBox.Warning) informative_text = ( "One or more folders have not finished loading. If these " "folders were recently added, you may need to add them again.") elif folder_syncing: msg.setIcon(QMessageBox.Warning) informative_text = ( "One or more folders are currently syncing. If you quit, any " "pending upload or download operations will be cancelled " "until you launch {} again.".format(APP_NAME)) else: msg.setIcon(QMessageBox.Question) informative_text = ( "If you quit, {} will stop synchronizing your folders until " "you launch it again.".format(APP_NAME)) if sys.platform == 'darwin': msg.setText("Are you sure you wish to quit?") msg.setInformativeText(informative_text) else: msg.setWindowTitle("Exit {}?".format(APP_NAME)) msg.setText( "Are you sure you wish to quit? {}".format(informative_text)) msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msg.setDefaultButton(QMessageBox.No) if msg.exec_() == QMessageBox.Yes: if sys.platform == 'win32': self.gui.systray.hide() reactor.stop() def keyPressEvent(self, event): key = event.key() if key in (Qt.Key_Backspace, Qt.Key_Delete): view = self.current_view() selected = (view.selectedIndexes() if view else None) if selected: view.confirm_remove(view.get_selected_folders()) if key == Qt.Key_Escape: view = self.current_view() selected = (view.selectedIndexes() if view else None) if selected: for index in selected: view.selectionModel().select( index, QItemSelectionModel.Deselect) elif self.gui.systray.isSystemTrayAvailable(): self.hide() def closeEvent(self, event): if self.gui.systray.isSystemTrayAvailable(): event.accept() else: event.ignore() self.confirm_quit()
class MainWindow(QMainWindow): def __init__(self, view_manager: ViewManagerFromViewInterface = None): QMainWindow.__init__(self, None) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.view_manager = view_manager self.create_widgets() pixmap = QPixmap('view/resource/icons_my/icon.png') icon = QIcon() icon.addPixmap(pixmap, QIcon.Normal, QIcon.Off) self.setWindowTitle('P Browser - thumbnail view') self.setWindowIcon(icon) self.thumb_views = list() self.ui.tabWidget.tabCloseRequested.connect(self.close_tab) self.ui.tabWidget.currentChanged.connect(self.on_current_tab_changed) self.bn_favorite.clicked.connect(self.view_manager.add_to_favorite) self.log_button.toggled.connect(self.log_button_toggle) def create_widgets(self): self.sites = ButtonLine(self.ui.top_frame, height=50, speed=90, space=5) self.ui.top_frame_layout.addWidget(self.sites) self.history = HistoryView(self, self.view_manager) self.ui.controls_frame_layout.addWidget(self.history) self.bn_favorite = QToolButton(self.ui.controls_frame) self.bn_favorite.setAutoRaise(True) icon = QIcon() icon.addPixmap( QPixmap("view/resource/icons/ic_add_box_white_48dp.png"), QIcon.Normal, QIcon.Off) self.bn_favorite.setIcon(icon) self.bn_favorite.setIconSize(QSize(32, 32)) self.ui.controls_frame_layout.addWidget(self.bn_favorite) self.log_button = QToolButton() sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Ignored) self.log_button.setSizePolicy(sizePolicy) self.log_button.setMinimumSize(QSize(0, 10)) icon = QIcon() icon.addPixmap( QPixmap("view/resource/icons/ic_arrow_drop_up_white_24dp.png"), QIcon.Normal, QIcon.Off) icon.addPixmap( QPixmap("view/resource/icons/ic_arrow_drop_down_white_24dp.png"), QIcon.Normal, QIcon.On) self.log_button.setIcon(icon) self.log_button.setIconSize(QSize(24, 24)) self.log_button.setCheckable(True) self.log_button.setAutoRaise(True) self.ui.bottom_frame_layout.addWidget(self.log_button) self.log = LogViewWindow(self.view_manager) self.ui.bottom_frame_layout.addWidget(self.log) self.log.setMaximumHeight(70) self.log.hide() # self.updateGeometry() def log_button_toggle(self): # return if self.log_button.isChecked(): self.log.show() else: self.log.hide() def get_new_thumb_view(self) -> ThumbView: tab = self.ui.tabWidget view = ThumbView(tab, self.view_manager) self.thumb_views.append(view) return view def get_current_thumb_view(self) -> ThumbView: index = self.ui.tabWidget.currentIndex() if index >= 0: return self.thumb_views[index] else: return None def get_log(self) -> LogViewInterface: return self.log def set_tab_text(self, view, text: str, tooltip=''): try: index = self.thumb_views.index(view) self.ui.tabWidget.setTabText(index, text) self.ui.tabWidget.setTabToolTip(index, tooltip) except ValueError: pass def create_site_button(self, button): self.sites.add_button(button) def close_tab(self, index: int): # self.thumb_views[index].history_event() self.thumb_views[index].prepare_to_close() self.thumb_views.pop(index) self.ui.tabWidget.removeTab(index) self.update() def panic(self): self.showMinimized() def on_history_changed(self, history: HistoryFromViewInterface): self.history.update_history(history) def on_current_tab_changed(self, index: int): if index >= 0 and len(self.thumb_views) > 0: self.history.set_current_url(self.thumb_views[index].url) else: self.history.set_current_url(URL()) def on_url_in_tab_changed(self, view): if self.thumb_views[self.ui.tabWidget.currentIndex()] == view: # print(view.url.get()) self.history.set_current_url(view.url) def closeEvent(self, *args, **kwargs): for thumbs in self.thumb_views: thumbs.history_event() self.view_manager.on_exit()
class CollapsibleWidget(QWidget): def __init__(self, title="", parent=None, animation_duration=300): """ References: # Adapted from c++ version http://stackoverflow.com/questions/32476006/how-to-make-an-expandable-collapsable-section-widget-in-qt """ super(CollapsibleWidget, self).__init__(parent) self.title = title self.toggle_button = QToolButton() self.toggle_animation = QParallelAnimationGroup(self) self.content_area = QScrollArea() self.animation_duration = animation_duration self._init_base_ui() def _init_base_ui(self): self.toggle_button.setStyleSheet("QToolButton { border: none; }") self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.toggle_button.setArrowType(Qt.RightArrow) self.toggle_button.pressed.connect(self.on_pressed) self.toggle_button.setText(str(self.title)) self.toggle_button.setCheckable(True) self.toggle_button.setChecked(False) self.content_area.setMaximumHeight(0) self.content_area.setMinimumHeight(0) self.content_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.content_area.setFrameShape(QFrame.NoFrame) self.toggle_animation.addAnimation( QPropertyAnimation(self, b"minimumHeight")) self.toggle_animation.addAnimation( QPropertyAnimation(self, b"maximumHeight")) self.toggle_animation.addAnimation( QPropertyAnimation(self.content_area, b"maximumHeight")) layout = QVBoxLayout(self) layout.setSpacing(0) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.toggle_button) layout.addWidget(self.content_area) def on_pressed(self): checked = self.toggle_button.isChecked() self.toggle_button.setArrowType( Qt.DownArrow if not checked else Qt.RightArrow) self.toggle_animation.setDirection( QAbstractAnimation.Forward if not checked else QAbstractAnimation. Backward) self.toggle_animation.start() def set_content_layout(self, layout): initial_layout = self.content_area.layout() del initial_layout self.content_area.setLayout(layout) collapsed_height = (self.sizeHint().height() - self.content_area.maximumHeight()) content_height = layout.sizeHint().height() for i in range(self.toggle_animation.animationCount()): animation = self.toggle_animation.animationAt(i) animation.setDuration(self.animation_duration) animation.setStartValue(collapsed_height) animation.setEndValue(collapsed_height + content_height) content_animation = self.toggle_animation.animationAt( self.toggle_animation.animationCount() - 1) content_animation.setDuration(self.animation_duration) content_animation.setStartValue(0) content_animation.setEndValue(content_height) def set_content_widget(self, widget): initial_layout = self.content_area.layout() del initial_layout self.content_area.setWidget(widget) collapsed_height = (self.sizeHint().height() - self.content_area.maximumHeight()) content_height = widget.sizeHint().height() for i in range(self.toggle_animation.animationCount()): animation = self.toggle_animation.animationAt(i) animation.setDuration(self.animation_duration) animation.setStartValue(collapsed_height) animation.setEndValue(collapsed_height + content_height) content_animation = self.toggle_animation.animationAt( self.toggle_animation.animationCount() - 1) content_animation.setDuration(self.animation_duration) content_animation.setStartValue(0) content_animation.setEndValue(content_height)
class CollapsibleBox(QWidget): def __init__(self, title="", parent=None): super(CollapsibleBox, self).__init__(parent) self.toggle_button = QToolButton(text=title, checkable=True, checked=False) self.toggle_button.setStyleSheet("QToolButton {border: none;\ border: 1px solid #FF17365D;\ border-top-left-radius: 15px;\ border-top-right-radius: 15px;\ background-color: #FF17365D;\ padding: 5px 0px;\ color: rgb(255, 255, 255);\ max-height: 30px;\ font-size: 14px;\ }\ QToolButton:hover {\ background-color: lightgreen;\ color: black;\ }") self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.toggle_button.setArrowType(Qt.RightArrow) self.toggle_button.pressed.connect(self.on_pressed) self.toggle_animation = QParallelAnimationGroup(self) self.content_area = QScrollArea(maximumHeight=0, minimumHeight=0) self.content_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) lay = QVBoxLayout(self) lay.setSpacing(0) lay.setContentsMargins(0, 0, 0, 0) lay.addWidget(self.toggle_button) lay.addWidget(self.content_area) self.toggle_animation.addAnimation( QPropertyAnimation(self, b"minimumHeight")) self.toggle_animation.addAnimation( QPropertyAnimation(self, b"maximumHeight")) self.toggle_animation.addAnimation( QPropertyAnimation(self.content_area, b"maximumHeight")) @QtCore.pyqtSlot() def on_pressed(self): checked = self.toggle_button.isChecked() self.toggle_button.setArrowType( Qt.DownArrow if not checked else Qt.RightArrow) self.toggle_animation.setDirection( QAbstractAnimation.Forward if not checked else QAbstractAnimation. Backward) self.toggle_animation.start() def clear_layout(self, layout): try: for i in reversed(range(layout.count())): widgetToRemove = layout.itemAt(i).widget() layout.removeWidget(widgetToRemove) widgetToRemove.setPArent(None) except AttributeError: pass def setContentLayout(self, layout): lay = self.content_area.layout() self.clear_layout(lay) self.content_area.setLayout(layout) collapsed_height = (self.sizeHint().height() - self.content_area.maximumHeight()) content_height = layout.sizeHint().height() for i in range(self.toggle_animation.animationCount()): animation = self.toggle_animation.animationAt(i) animation.setDuration(500) animation.setStartValue(collapsed_height) animation.setEndValue(collapsed_height + content_height) content_animation = self.toggle_animation.animationAt( self.toggle_animation.animationCount() - 1) content_animation.setDuration(500) content_animation.setStartValue(0) content_animation.setEndValue(content_height)
class EventPicker(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle('EventPicker 2018.1') self.nSubPlots = None # number of traces/subplots self.nSamples = None # number of samples per trace self.dragFrom = None self.segy = None # type: Segy class # # {'0': {'2500': {'p':[marker1, marker2]} # {'s':[maerker1, marker2]}} # self.markers = defaultdict(dict) self.eventList = [] self.markerList = [] self.currentEvent = defaultdict(dict) self.event2file = defaultdict(dict) self.currentEventId = int(1) self.spanMarker = None self.modeFlag = 'a' self.componentFlag = int(12) self.normFlag = int(1) # traces data normalized before display self.zTraces = None self.xTraces = None self.yTraces = None self.xcolor = 'b' self.ycolor = 'r' self.zcolor = 'green' self.fileList = [] self.currentFile = None self.inpath = None self.outpath = "F:\\datafolder\\eventspicked" self.zLines = [] # list container of line curves of Z traces self.xLines = [] self.yLines = [] self.autoPickerParams = { 'stalta_algorithm': 'Recursive', 'nsta': '20', 'nlta': '50', 'pthreshold': '2.0', 'sthreshold': '2.2' } self.initUI() def initUI(self): # Trace plot self.fig = plt.figure() self.staticCanvas = FigureCanvas(self.fig) self.staticCanvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.fig.canvas.mpl_connect('button_press_event', self.onClick) self.fig.canvas.mpl_connect('button_release_event', self.onRelease) #self.fig.canvas.mpl_connect('scroll_event', self.onScroll) self.fig.canvas.mpl_connect('key_press_event', self.onKey) self.p_line_style = dict(color='r', linestyle='-', linewidth=2) self.p_marker_style = dict(marker='o', s=40, facecolors='none', edgecolors='r') self.s_line_style = dict(color='b', linestyle='-', linewidth=2) self.s_marker_style = dict(marker='o', s=40, facecolors='none', edgecolors='b') # Reference trace plot self.refFig = plt.figure() self.refCanvas = FigureCanvas(self.refFig) self.refFig.set_size_inches(self.size().width()/self.refFig.get_dpi(), self.size().height() * 0.25 /self.refFig.get_dpi()) self.refCanvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.refCanvas.updateGeometry() self.graphArea = QScrollArea(self) self.graphArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) self.graphArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.graphArea.setWidget(self.staticCanvas) self.graphArea.setWidgetResizable(True) layout = QVBoxLayout() layout.addWidget(self.graphArea) #layout.addWidget(self.staticCanvas) layout.addWidget(self.refCanvas) self.main = QWidget() self.setCentralWidget(self.main) self.main.setLayout(layout) self.createActions() self.createMenus() self.createToolBars() self.resize(1176, 776) def createActions(self): self.pickSettingAction = QAction(QIcon(':/icons/windows/settings-48.png'), "&AutoPicker Settings", self, shortcut= '', statusTip="AutoPicker settings", triggered=self.onPickSettingsClicked) self.pickSettingAction.setEnabled(False) self.selectFolderAction = QAction(QIcon(':/icons/windows/add-folder-48.png'), "&Select SEG-Y Folder", self, shortcut= '', statusTip="Select SEG-Y files folder", triggered=self.onSelectFolder) self.exportAction = QAction(QIcon(':/icons/windows/export-one-48.png'), "&Export Current Event", self, shortcut= '', statusTip="Export current picked event", triggered=self.onExport) self.exportAllAction = QAction(QIcon(':/icons/windows/export-all-48.png'), "&Export All Events", self, shortcut= '', statusTip="Export all picked events", triggered=self.onExportAll) self.editEventsAction = QAction(QIcon(':/icons/windows/edit-event-48.png'), "&Edit Events", self, shortcut= '', statusTip="Edit all picked events", triggered=self.onEditEvents) def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addAction(self.selectFolderAction) self.editMenu = self.menuBar().addMenu("&Edit") self.editMenu.addAction(self.editEventsAction) self.exportMenu = self.menuBar().addMenu("&Export") self.exportMenu.addAction(self.exportAction) self.exportMenu.addAction(self.exportAllAction) def createToolBars(self): # Component Toolbar self.componentToolBar = QToolBar(self) self.addToolBar(Qt.TopToolBarArea, self.componentToolBar) self.zComponentToolButton = QToolButton(self) self.zComponentToolButton.setToolTip('Z Component') self.zComponentToolButton.setIcon(QIcon(':/icons/windows/z-checked-48.png')) self.zComponentToolButton.setCheckable(True) self.zComponentToolButton.setChecked(True) self.zComponentToolButton.toggled.connect(self.update) self.xComponentToolButton = QToolButton(self) self.xComponentToolButton.setToolTip('X Component') self.xComponentToolButton.setIcon(QIcon(':/icons/windows/n-48.png')) self.xComponentToolButton.setCheckable(True) self.xComponentToolButton.toggled.connect(self.update) self.yComponentToolButton = QToolButton(self) self.yComponentToolButton.setToolTip('Y Component') self.yComponentToolButton.setIcon(QIcon(':/icons/windows/e-48.png')) self.yComponentToolButton.setCheckable(True) self.yComponentToolButton.toggled.connect(self.update) self.componentToolBar.addWidget(self.yComponentToolButton) self.componentToolBar.addWidget(self.xComponentToolButton) self.componentToolBar.addWidget(self.zComponentToolButton) # Auto Pick Toolbar self.autoPickToolBar = QToolBar(self) self.addToolBar(Qt.TopToolBarArea, self.autoPickToolBar) self.autoPickToolButton = QToolButton(self) self.autoPickToolButton.setToolTip('Run AutoPicker') self.autoPickToolButton.setIcon(QIcon(':/icons/windows/autopick-purple-48.png')) self.autoPickToolButton.clicked.connect(self.onAutoPickClicked) self.autoPickToolButton.setEnabled(False) self.autoPickToolBar.addAction(self.pickSettingAction) self.autoPickToolBar.addWidget(self.autoPickToolButton) # Manual Pick Toolbar self.manualPickToolBar = QToolBar(self) self.addToolBar(Qt.TopToolBarArea, self.manualPickToolBar) self.pickPwaveToolButton = QToolButton(self) self.pickPwaveToolButton.setToolTip('Pick P-phase Arrival') self.pickPwaveToolButton.setIcon(QIcon(':/icons/windows/pickp-48.png')) self.pickPwaveToolButton.setCheckable(True) self.pickPwaveToolButton.toggled.connect(self.onPickPwaveToggled) self.pickSwaveToolButton = QToolButton(self) self.pickSwaveToolButton.setToolTip('Pick S-phase Arrival') self.pickSwaveToolButton.setIcon(QIcon(':/icons/windows/picks-48.png')) self.pickSwaveToolButton.setCheckable(True) self.pickSwaveToolButton.toggled.connect(self.onPickSwaveToggled) self.manualPickToolBar.addWidget(self.pickPwaveToolButton) self.manualPickToolBar.addWidget(self.pickSwaveToolButton) # Event Toolbar self.eventToolBar = QToolBar(self) self.addToolBar(Qt.TopToolBarArea, self.eventToolBar) self.clearPickToolButton = QToolButton(self) self.clearPickToolButton.setToolTip('Clear Current Picks') self.clearPickToolButton.setIcon(QIcon(':/icons/windows/clear-picks-48.png')) self.clearPickToolButton.clicked.connect(self.onClearPick) self.clearAllPickToolButton = QToolButton(self) self.clearAllPickToolButton.setToolTip('Clear All Picks') self.clearAllPickToolButton.setIcon(QIcon(':/icons/windows/clear-all-picks-48.png')) self.clearAllPickToolButton.clicked.connect(self.onClearAllPick) self.eventIdWidget = EventIDWidget(self) self.eventToolBar.addWidget(self.clearPickToolButton) self.eventToolBar.addWidget(self.clearAllPickToolButton) self.eventToolBar.addWidget(self.eventIdWidget) self.eventToolBar.addAction(self.editEventsAction) self.eventToolBar.addAction(self.exportAction) self.eventToolBar.addAction(self.exportAllAction) # Matplotlib Navigation ToolBar self.pltToolBar = NavigationToolbar(self.staticCanvas, self) self.addToolBar(self.pltToolBar) self.addToolBarBreak() # Manual Pick Toolbar self.fileToolBar = FileToolBar(self) self.addToolBar(Qt.TopToolBarArea, self.fileToolBar) def onExportAll(self): self.updateCurrentEvent2File() fileName, ok = QFileDialog.getSaveFileName(self, "Export", "C:\\", "All Files (*);;CSV Files (*.csv)") if fileName: markers = self.markers dics = [] dic = {'event_id':None, 'file_name': None, 'receiver_id': None, 'p_pos': None, 's_pos':None} if len(markers): for event_id, item in self.markers.items(): for plot_id, markers in item.items(): dic['event_id'] = int(event_id) dic['file_name'] = self.event2file[event_id] dic['receiver_id'] = int(plot_id) + 1 if markers['p'] != None: dic['p_pos'] = markers['p']['pos'] else: dic['p_pos'] = DEFAULT_NUMERIC_VALUE if markers['s'] != None: dic['s_pos'] = markers['s']['pos'] else: dic['s_pos'] = DEFAULT_NUMERIC_VALUE dics.append(copy.deepcopy(dic)) df = pd.DataFrame(dics) df.to_csv(fileName) QMessageBox.information(self, "Information", "All Events have been saved successfully!", QMessageBox.Ok) else: QMessageBox.warning(self, "Warning", "No P-wave or S-wave arrival time has been picked!\nPlease pick at least one arrival time for exporting.", QMessageBox.Ok) def onSelectFolder (self): folderPath = QFileDialog.getExistingDirectory(self,"Select SEG-Y folder","C:\\") if folderPath: self.inpath = folderPath self.fileList = self.getAllFiles(folderPath) self.updateAll(self.fileList[0]) self.fileToolBar.initWidget(self.fileList) def getAllFiles(self, path_dir): if os.path.exists(path_dir) and os.path.isdir(path_dir): path_dir = os.path.abspath(path_dir) for i in os.listdir(path_dir): path_i = os.path.join(path_dir, i) if os.path.isfile(path_i) and os.path.splitext(os.path.basename(path_i))[1] == '.sgy': self.fileList.append(path_i) #print(path_i) else: self.getAllFiles(path_i) return self.fileList def updateMarkers(self, params): ''' NOT FINISHED YET ''' pass # for subPlotNr in range(self.nSubPlots): # if str(subPlotNr) not in self.markers[str(self.currentEventId)]: # self.markers[str(self.currentEventId)][str(subPlotNr)] = [] # if 'stalta_algorithm' in params.keys(): # method = params['stalta_algorithm'] # nsta = int(params['nsta']) # lsta = int(params['nlta']) # pthres = float(params['pthreshold']) # sthres = float(params['sthreshold']) # pCfs, sCfs = self.segy.calcStaLtaCF(nsta, lsta, method) # pPicks, sPicks = self.segy.pickPS(pCfs, sCfs, pthres, sthres) # for subPlotNr in range(self.nSubPlots): # xP = pPicks[str(subPlotNr)] # xS = sPicks[str(subPlotNr)] # subPlot = self.selectSubPlot(subPlotNr) # markerList = [] # for i in range(len(xP)): # xp = xP[i] # pMarker1 = subPlot.axvline(xp, 0.1, 0.9, **self.p_line_style) # pMarker2 = subPlot.scatter(xp, 0.0, **self.p_marker_style) # markerList.append({'px': xp, # 'pmarker': [pMarker1, pMarker2] # }) # for i in range(len(xS)): # xs = xS[i] # sMarker1 = subPlot.axvline(xs, 0.1, 0.9, **self.s_line_style) # sMarker2 = subPlot.scatter(xs, 0.0, **self.s_marker_style) # markerList.append({'sx': xs, # 'smarker': [sMarker1, sMarker2] # }) # self.markers[str(self.currentEventId)][str(subPlotNr)] = markerList # self.fig.canvas.draw() def setAutoPicker(self, object): self.autoPickerParams.clear() self.autoPickerParams = object print(self.autoPickerParams) def getComponentFlag(self): if self.xComponentToolButton.isChecked(): xflag = 14 self.xComponentToolButton.setIcon(QIcon(':/icons/windows/e-checked-48.png')) else: xflag = 0 self.xComponentToolButton.setIcon(QIcon(':/icons/windows/e-48.png')) if self.yComponentToolButton.isChecked(): yflag = 13 self.yComponentToolButton.setIcon(QIcon(':/icons/windows/n-checked-48.png')) else: yflag = 0 self.yComponentToolButton.setIcon(QIcon(':/icons/windows/n-48.png')) if self.zComponentToolButton.isChecked(): zflag = 12 self.zComponentToolButton.setIcon(QIcon(':/icons/windows/z-checked-48.png')) else: zflag = 0 self.zComponentToolButton.setIcon(QIcon(':/icons/windows/z-48.png')) flag = xflag + yflag +zflag return flag def onPickPwaveToggled(self, checked): if checked: self.modeFlag = 'p' self.pickSwaveToolButton.setChecked(False) elif self.pickSwaveToolButton.isChecked() == False: self.modeFlag = 'a' def onPickSwaveToggled(self, checked): if checked: self.modeFlag = 's' self.pickPwaveToolButton.setChecked(False) elif self.pickPwaveToolButton.isChecked() == False: self.modeFlag = 'a' def onAutoPickClicked(self): self.updateMarkers(self.autoPickerParams) def onPickSettingsClicked(self): dialog = AutoPickerSettingDialog(self) dialog.applySignal.connect(self.updateMarkers) dialog.show() dialog.exec_() def setSegy(self, segy): self.segy = segy def getSegy(self): return self.segy def updateAll(self, file): self.currentFile = file segy = pssegy.Segy(file) self.setSegy(segy) self.xComponentToolButton.setChecked(False) self.yComponentToolButton.setChecked(False) self.zComponentToolButton.setChecked(True) self.initPlot() def updateEvent2File(self, ind): if str(ind) not in self.event2file and len(self.markers[str(ind)]): self.event2file[str(ind)] = self.currentFile def updateCurrentEvent2File(self): ind = self.currentEventId if str(ind) not in self.event2file and len(self.markers[str(ind)]): self.event2file[str(ind)] = self.currentFile def initPlot(self): df = self.segy.df if self.normFlag == 1: self.zTraces = signorm(self.segy.zTraces) self.xTraces = signorm(self.segy.xTraces) self.yTraces = signorm(self.segy.yTraces) # @TODO: add norm flag here else: self.zTraces = self.segy.zTraces self.xTraces = self.segy.xTraces self.yTraces = self.segy.yTraces ns, ntr = self.zTraces.shape self.nSamples = ns self.nSubPlots = ntr if self.nSubPlots > 12: self.fig.set_size_inches(self.size().width()/self.fig.get_dpi(), self.size().height() * self.nSubPlots / 12 /self.fig.get_dpi()) self.staticCanvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.staticCanvas.setMinimumHeight(self.size().height() * self.nSubPlots / 12 ) t = np.arange(self.nSamples, dtype=np.float32) / df # if len(self.fig.axes): # xlim = self.fig.axes[0].get_xlim() # #print(xlim) # else: # self.fig.clear() xlim = (0, ns) nrow = int(ntr) ncol = 1 self.zLines = self.plotWaveform(self.zTraces, xlim, nrow, ncol, self.fig, self.zcolor) #self.nSubPlots = len(self.fig.axes) self.plotRefWaveform(self.zTraces, self.nSubPlots, df, self.refFig) def updatePlot(self): if len(self.fig.axes): xlim = self.fig.axes[0].get_xlim() #print(xlim) else: xlim = (0, self.nSamples) nrow = int(self.nSubPlots) ncol = 1 if self.zComponentToolButton.isChecked() == False: self.removeLines(self.zLines) self.zLines = [] else: if not len(self.zLines): self.zLines = self.plotWaveform(self.zTraces, xlim, nrow, ncol, self.fig, self.zcolor) if self.xComponentToolButton.isChecked() == False: self.removeLines(self.xLines) self.xLines = [] else: if not len(self.xLines): self.xLines = self.plotWaveform(self.xTraces, xlim, nrow, ncol, self.fig, self.xcolor) if self.yComponentToolButton.isChecked() == False: self.removeLines(self.yLines) self.yLines = [] else: if not len(self.yLines): self.yLines = self.plotWaveform(self.yTraces, xlim, nrow, ncol, self.fig, self.ycolor) self.fig.canvas.draw() if not len(self.zLines) and not len(self.xLines) and not len(self.yLines): self.autoPickToolButton.setEnabled(False) else: self.autoPickToolButton.setEnabled(True) def removeLines(self, lines): if len(lines): for subPlotNr in range(self.nSubPlots): subPlot = self.selectSubPlot(subPlotNr) line = lines[subPlotNr] if line in subPlot.lines: #print('line in subplot.lines') subPlot.lines.remove(line) def updateToolBar(self): if self.xComponentToolButton.isChecked(): self.xComponentToolButton.setIcon(QIcon(':/icons/windows/e-checked-48.png')) else: self.xComponentToolButton.setIcon(QIcon(':/icons/windows/e-48.png')) if self.yComponentToolButton.isChecked(): self.yComponentToolButton.setIcon(QIcon(':/icons/windows/n-checked-48.png')) else: self.yComponentToolButton.setIcon(QIcon(':/icons/windows/n-48.png')) if self.zComponentToolButton.isChecked(): self.zComponentToolButton.setIcon(QIcon(':/icons/windows/z-checked-48.png')) else: self.zComponentToolButton.setIcon(QIcon(':/icons/windows/z-48.png')) # Declare and register callbacks def onXlimsChanged(self, ax): if len(self.refFig.axes): #print ("updated xlims: ", ax.get_xlim()) xlim = ax.get_xlim() self.refFig.axes[0].patches = [] self.refFig.axes[1].patches = [] # if self.spanMarker in self.refFig.axes[0].patches: # #print('spanMarker in subplot.patches') # self.refFig.axes[0].patches.remove(self.spanMarker) # self.spanMarker = None df = self.segy.df self.spanMarker = self.refFig.axes[0].axvspan(xlim[0]/df, xlim[1]/df, facecolor='#2ca02c', alpha=0.25) self.refFig.canvas.draw() def onYlimsChanged(self, ax): pass #print ("updated ylims: ", ax.get_ylim()) def update(self): self.updateToolBar() if self.segy is not None: self.updatePlot() def plotRefWaveform(self, traces, ind, df, fig): fig.clear() ns, ntr = traces.shape xlim = (0/df, ns/df) nTick = 10 step = divmod(ns, nTick)[0] x_n = np.linspace(0, ns, ns) x_t = np.arange(ns, dtype=np.float32) / df ax1 = fig.add_subplot(1,1,1) line = ax1.plot(x_t, traces[:, ind -1] , linewidth=1.0, c = 'k', figure=fig) #ax1.set_xlabel(u'Time [second]') ax1.set_yticks([]) ax1.set_xlim(xlim[0], xlim[1]) # Set scond x-axis ax2 = ax1.twiny() # Decide the ticklabel position in the new x-axis, # then convert them to the position in the old x-axis newlabel = [] for i in range(nTick+1): newlabel.append(i*step) # labels of the xticklabels: the position in the new x-axis n2t = lambda t: t/df # convert function: from Kelvin to Degree Celsius newpos = [n2t(t) for t in newlabel] # position of the xticklabels in the old x-axis ax2.set_xticks(newpos) ax2.set_xticklabels(newlabel) ax2.set_yticks([]) #ax2.set_xlabel('Sample') ax2.set_xlim(ax1.get_xlim()) self.spanMarker = self.refFig.axes[0].axvspan(xlim[0], xlim[1], facecolor='#2ca02c', alpha=0.5) fig.subplots_adjust(left=0.02, bottom=0.25, right=0.98, top=0.75) fig.canvas.draw() return line def resizeEvent(self, ev): pass #print(ev) # # incorrect code here: only figure size changed while canvas not # self.refFig.set_size_inches(self.size().width()/self.refFig.get_dpi(), # self.size().height() * 0.1/self.refFig.get_dpi()) # self.refFig.canvas.draw() def plotWaveform(self, traces, xlim, nrow, ncol, fig, color): ns, ntr = traces.shape #t = np.arange(ns, dtype=np.float32) / df xData = np.linspace(1, ns, ns) lines = [] for irow in range(nrow): if irow == 0: ax1 = fig.add_subplot(nrow, ncol, irow + 1) line = ax1.plot(xData, traces[:, irow] , linewidth=1.0, c = color, figure=fig) ax1.callbacks.connect('xlim_changed', self.onXlimsChanged) ax1.set_yticks([]) ax1.set_xlim(int(xlim[0]), int(xlim[1])) ax1.set_xticks([]) else: subPlot = fig.add_subplot(nrow, ncol, irow + 1, sharex = ax1, sharey = ax1) subPlot.callbacks.connect('xlim_changed', self.onXlimsChanged) line = subPlot.plot(xData, traces[:, irow] , linewidth=1.0, c = color, figure=self.fig) lines.append(line[0]) fig.subplots_adjust(left=0.02, bottom=0.02, right=0.99, top=0.98) #self.fig.tight_layout() fig.canvas.draw() return lines def onExport(self): self.updateCurrentEvent2File() fileName, ok = QFileDialog.getSaveFileName(self, "Export", "C:\\", "All Files (*);;CSV Files (*.csv)") if fileName: markers = self.markers dics = [] dic = {'event_id':None, 'file_name': None, 'receiver_id': None, 'p_pos': None, 's_pos':None} if len(markers[str(self.currentEventId)]): item = markers[str(self.currentEventId)] for plot_id, markers in item.items(): dic['event_id'] = self.currentEventId dic['file_name'] = self.currentFile dic['receiver_id'] = int(plot_id) + 1 if markers['p'] != None: dic['p_pos'] = markers['p']['pos'] else: dic['p_pos'] = DEFAULT_NUMERIC_VALUE if markers['s'] != None: dic['s_pos'] = markers['s']['pos'] else: dic['s_pos'] = DEFAULT_NUMERIC_VALUE dics.append(copy.deepcopy(dic)) df = pd.DataFrame(dics) df.to_csv(fileName) QMessageBox.information(self, "Information", "Event #" + str(self.currentEventId) + " has been saved successfully!", QMessageBox.Ok) else: QMessageBox.warning(self, "Warning", "No P-wave or S-wave arrival time has been picked for Event #" + str(self.currentEventId) + ".\nPlease pick at least one arrival time for exporting.", QMessageBox.Ok) def onEditEvents(self): print('edit event list') def onClearPick(self): self.clearMarkers() def onClearAllPick(self): self.clearAllMarkers() def clearMarkers(self): if len(self.markers[str(self.currentEventId)]): item = self.markers[str(self.currentEventId)] for plot_id, markers in item.items(): subPlot = self.selectSubPlot(int(plot_id)) for flag in ['p', 's']: marker = markers[flag] if marker != None: mk = marker['marker'] subPlot.lines.remove(mk) markers[flag] = None self.markers[str(self.currentEventId)].clear() self.markers.pop(str(self.currentEventId)) self.fig.canvas.draw() def clearAllMarkers(self): if len(self.markers): for event_id, item in self.markers.items(): for plot_id, markers in item.items(): subPlot = self.selectSubPlot(int(plot_id)) for flag in ['p', 's']: marker = markers[flag] if marker != None: mk = marker['marker'] subPlot.lines.remove(mk) markers[flag] = None self.markers.clear() self.fig.canvas.draw() def deleteMarker(self,event): subPlotNr = self.getSubPlotNr(event) if subPlotNr == None: return subPlot = self.selectSubPlot(subPlotNr) plotIdPopped = None for event_id, item in self.markers.items(): for plot_id, markers in item.items(): if plot_id == str(subPlotNr): for flag in ['p', 's']: marker = markers[flag] if marker != None and abs (marker['pos'] - event.xdata) <=10: mk = marker['marker'] subPlot.lines.remove(mk) markers[flag] = None if markers['p'] == None and markers['s'] == None: plotIdPopped = plot_id if plotIdPopped != None: self.markers[str(self.currentEventId)].pop(plotIdPopped) self.fig.canvas.draw() def getSubPlotNr(self, event): """ Get the nr of the subplot that has been clicked Arguments: event -- an event Returns: A number or None if no subplot has been clicked """ i = 0 axisNr = None for axis in self.fig.axes: if axis == event.inaxes: axisNr = i break i += 1 return axisNr def selectSubPlot(self, i): """ Select a subplot Arguments: i -- the nr of the subplot to select Returns: A subplot """ #pyplot.subplot(self.nSubPlots, 1, i+1) return self.fig.axes[ i ] def onClick(self, event): """ Process a mouse click event. If a mouse is right clicked within a subplot, the return value is set to a (subPlotNr, xVal, yVal) tuple and the plot is closed. With right-clicking and dragging, the plot can be moved. Arguments: event -- a MouseEvent event """ mode = self.pltToolBar.mode if event.button == 1 and mode != 'zoom rect' and self.modeFlag != 'a': # left clicked subPlotNr = self.getSubPlotNr(event) if subPlotNr == None: return else: if str(subPlotNr) not in self.markers[str(self.currentEventId)]: self.markers[str(self.currentEventId)][str(subPlotNr)] = {'p': None, 's':None} marker = {'pos': None, 'marker': None } subPlot = self.selectSubPlot(subPlotNr) if self.markers[str(self.currentEventId)][str(subPlotNr)][self.modeFlag] == None: if self.modeFlag == 'p': mks = subPlot.axvline(event.xdata, 0.1, 0.9, **self.p_line_style) else: mks = subPlot.axvline(event.xdata, 0.1, 0.9, **self.s_line_style) marker['pos'] = event.xdata marker['marker'] = mks self.markers[str(self.currentEventId)][str(subPlotNr)][self.modeFlag] = marker else: QMessageBox.warning(self, "Warning", "For each microseismic event, there should only one P-wave arrival time and one S-wave arrival time be picked.\nPlease firstly clear the existing one and then re-pick the new one", QMessageBox.Ok) self.fig.canvas.draw() elif event.button == 3 and mode != 'zoom rect': # right clicked self.deleteMarker(event) # else: # # Start a dragFrom # self.dragFrom = event.xdata def onKey(self, event): """ Handle a keypress event. The plot is closed without return value on enter. Other keys are used to add a comment. Arguments: event -- a KeyEvent """ # if event.key == 'enter': # self.fig.close() # return # if event.key == 'escape': # self.clearMarker() # return # if event.key == 'backspace': # self.comment = self.comment[:-1] # elif len(event.key) == 1: # self.comment += event.key # event.canvas.draw() pass def onRelease(self, event): """ Handles a mouse release, which causes a move Arguments: event -- a mouse event """ if self.dragFrom == None or event.button != 3: return dragTo = event.xdata dx = self.dragFrom - dragTo for i in range(self.nSubPlots): subPlot = self.selectSubPlot(i) xmin, xmax = subPlot.get_xlim() xmin += dx xmax += dx subPlot.set_xlim(xmin, xmax) event.canvas.draw() def onScroll(self, event): """ Process scroll events. All subplots are scrolled simultaneously Arguments: event -- a MouseEvent """ for i in range(self.nSubPlots): subPlot = self.selectSubPlot(i) xmin, xmax = subPlot.get_xlim() dx = xmax - xmin cx = (xmax+xmin)/2 if event.button == 'down': dx *= 1.1 else: dx /= 1.1 _xmin = cx - dx/2 _xmax = cx + dx/2 subPlot.set_xlim(_xmin, _xmax) event.canvas.draw() def updateXLim(self, lim): ''' lim: a tuple, (x1, x2) ''' x1 = lim[0] x2 = lim[1] for axis in self.fig.axes: axis.set_xlim(x1, x2) self.fig.canvas.draw()
class TextEditWidget(PWidget): alert = pyqtSignal(str, str, object, object) syncRequest = pyqtSignal(object) editorTypeChanged = pyqtSignal(object) saveDataDone = pyqtSignal(str) def __init__(self, editType: EditorType = EditorType.Manual, save: bool = True, sync: bool = True): super().__init__() self.editor = TextEditor() self.editor.keyEvent.connect(self.editorEvent) tool = QHBoxLayout() if save: iconSize = 36 else: iconSize = 24 if save: self.title = PLabelEdit() self.title.setMaximumWidth(300) self.title.setFixedHeight(iconSize) self.title.setMaximumHeight(iconSize) self.title.setStyleSheet("QLabel{color:#424242; font-size:16px}") self.title.setText("Untitled") tool.addWidget(self.title) tool.addStretch() if editType == EditorType.Manual: self.editorTypeBox = PComboBox() self.editorTypeBox.setView(MiniView.listView()) self.editorTypeBox.addItems(["Text", "JSON", "XML", "HTML"]) self.editorTypeBox.currentIndexChanged.connect( self.editorTypeChange) tool.addWidget(self.editorTypeBox) self.wrapButton = QToolButton() self.wrapButton.setCheckable(True) self.wrapButton.setText("Wrap") self.wrapButton.setToolTip("Wrap/Unwrap (Ctrl+W)") self.wrapButton.setIcon( PResource.defaultIcon(Parapluie.Icon_Wrap_Text_Svg)) self.wrapButton.setFixedSize(iconSize, iconSize) self.wrapButton.pressed.connect(self.wrapText) tool.addWidget(self.wrapButton) formatButton = QToolButton() formatButton.setText("Format") formatButton.setToolTip("Format Code (Ctrl+F)") formatButton.setIcon( PResource.defaultIcon(Parapluie.Icon_Clean_Code_Svg)) formatButton.setFixedSize(iconSize, iconSize) formatButton.pressed.connect(self.formatText) tool.addWidget(formatButton) if save: saveButton = QToolButton() saveButton.setText("Save") saveButton.setToolTip("Save (Ctrl+S)") saveButton.setIcon(PResource.defaultIcon(Parapluie.Icon_Save_Svg)) saveButton.setFixedSize(iconSize, iconSize) saveButton.pressed.connect(self.saveData) tool.addWidget(saveButton) if sync: syncButton = QToolButton() syncButton.setText("Sync") syncButton.setToolTip("Sync (Ctrl+B)") syncButton.setIcon( PResource.defaultIcon(Parapluie.Icon_Double_Right_Chevron_Svg)) syncButton.setFixedSize(iconSize, iconSize) syncButton.pressed.connect(self.syncJson) tool.addWidget(syncButton) widget = QWidget() widget.setLayout(tool) widget.layout().setContentsMargins(8, 0, 8, 0) widget.setObjectName(Parapluie.Object_Editor_Header) widget.setMaximumHeight(iconSize) layout = QVBoxLayout() layout.addWidget(widget) layout.addWidget(self.editor) self.setLayout(layout) self.layout().setContentsMargins(5, 5, 5, 5) self.setObjectName(Parapluie.Object_Editor) self.currentFile = None self.editType = EditorType.Text self.setEditorType(EditorType.Text) def formatText(self, key: bool = False, sync=True): text = self.editor.text() if text != "": new_text = Formatter.dumps(text, self.editType, self.pushAlert if not key else None) if new_text: self.editor.setText(new_text) if sync: self.syncJson(key) def syncJson(self, key: bool = False): obj = self.getData(key) if self.editType == EditorType.JSON or self.editType == EditorType.XML: self.syncRequest.emit(obj) self.formatText(key, False) def pushAlert(self, text, tpe=Parapluie.Alert_Error): self.alert.emit(text, tpe, None, None) def setData(self, obj): text = Formatter.dumps(obj, self.editType, self.pushAlert if obj is None else None) self.editor.setText(text) def getData(self, key: bool = False): text = self.editor.text() if text != "": if self.editType == EditorType.JSON: try: obj = json.loads(text) return obj except Exception as ex: logging.exception(ex) if not key: self.pushAlert(str(ex)) return None elif self.editType == EditorType.XML: try: obj = Et.fromstring(text) return obj except Exception as ex: logging.exception(ex) if not key: self.pushAlert(str(ex)) return None else: if self.editType == EditorType.JSON: return {} elif self.editType == EditorType.XML: return None return text def setText(self, text): self.editor.setText(text) def text(self): return self.editor.text() def wrapText(self): if self.wrapButton.isChecked(): self.editor.setWrapMode(Qsci.QsciScintilla.WrapNone) else: self.editor.setWrapMode(Qsci.QsciScintilla.WrapWord) def editorEvent(self, key): if key == "ENTER": self.syncJson(True) elif key == "B": self.syncJson() elif key == "F": self.formatText() def setTitle(self, title): self.title.setText(title) def setEditorType(self, tpe: EditorType, inner=False): self.editType = tpe if not inner: self.editorTypeBox.setCurrentIndex(tpe.value) if tpe == EditorType.JSON: self.editor.changeLexer(Qsci.QsciLexerJSON(self.editor), 'JSON') elif tpe == EditorType.XML: self.editor.changeLexer(Qsci.QsciLexerXML(self.editor), 'XML') elif tpe == EditorType.HTML: self.editor.changeLexer(Qsci.QsciLexerHTML(self.editor), 'HTML') elif tpe == EditorType.Javascript: self.editor.changeLexer(Qsci.QsciLexerJavaScript(self.editor), 'Javascript') else: self.editor.changeLexer(Qsci.QsciLexerMarkdown(self.editor), 'Text<') self.editorTypeChanged.emit(tpe.value) def blockEditorType(self, block): self.editorTypeBox.setVisible(not block) # ["Text", "JSON", "XML", "HTML"] def editorTypeChange(self, index): if index == 0: self.setEditorType(EditorType.Text, True) elif index == 1: self.setEditorType(EditorType.JSON, True) elif index == 2: self.setEditorType(EditorType.XML, True) elif index == 3: self.setEditorType(EditorType.HTML, True) def setFile(self, file: XFile): # save data cũ if self.currentFile is not None: self.currentFile.unsavedData = self.text() # load data moi self.currentFile = file self.setTitle(file.name()[0]) if file.name()[1].lower() == '.json': self.setEditorType(EditorType.JSON) elif file.name()[1].lower() == '.xml': self.setEditorType(EditorType.XML) elif file.name()[1].lower() == '.html': self.setEditorType(EditorType.HTML) elif file.name()[1].lower() == '.js': self.setEditorType(EditorType.Javascript) else: self.setEditorType(EditorType.Text) self.title.setEditable(not os.path.isfile(file.getPath())) if file.unsavedData != "": self.setText(file.unsavedData) else: if os.path.isfile(file.getPath()): d = open(file.getPath(), "r", encoding="utf-8").read() self.setText(d) else: self.setText("") self.syncJson() def saveData(self): if self.currentFile is None: init_dir = Config.getViewerConfig_LastOpen() file = os.path.join(init_dir, self.title.text()) name = QFileDialog.getSaveFileName(self, 'Save file', file, self.getFileExtension()) if name[0] != "": config = Config.getConfig() config["viewer"]["last_open"] = os.path.dirname(name[0]) Config.updateConfig(config) self.currentFile = XFile(name[0]) self.save(self.currentFile) else: if not os.path.isfile(self.currentFile.getPath()): name = QFileDialog.getSaveFileName(self, 'Save file', self.currentFile.getPath(), self.getFileExtension()) if name[0] != "": self.currentFile.setPath(name[0]) if self.save(self.currentFile) is not None: self.saveDataDone.emit(name[0]) else: if self.save(self.currentFile) is not None: self.saveDataDone.emit(self.currentFile.getPath()) def save(self, f: XFile): try: file = open(f.getPath(), "w", encoding="utf-8") file.write(self.text()) file.close() f.unsavedData = "" self.pushAlert("Saved: " + f.getPath(), Parapluie.Alert_Information) return f.getPath() except Exception as ex: logging.exception(ex) self.pushAlert(str(ex)) def getFileExtension(self): if self.editType == EditorType.JSON: return "JSON files (*.json);; All files (*)" elif self.editType == EditorType.XML: return "XML files (*.xml);; All files (*)" elif self.editType == EditorType.HTML: return "HTML files (*.html);; All files (*)" elif self.editType == EditorType.Javascript: return "Javascript files (*.js);; All files (*)" else: return "All files (*)"
class QRectangleCreator: def __init__(self, iface): self.iface = iface self.plugin_dir = os.path.dirname(__file__) locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir, 'i18n', 'qrectanglecreator_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) self.actions = [] self.menu = self.tr(u'&QRectangleCreator') self.toolsToolbar = self.iface.addToolBar(u'QRectangle Creator') self.toolsToolbar.setObjectName(u'QRectangle Creator') self.settingsDlg = SettingsDialog() self.settingsDlg.width.valueChanged.connect(self.settingsChanged) self.settingsDlg.height.valueChanged.connect(self.settingsChanged) self.settingsDlg.angle.valueChanged.connect(self.settingsChanged) self.first_start = None def tr(self, message): return QCoreApplication.translate('QRectangleCreator', message) def add_action(self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None, checkable=False, checked=False, shortcut=None): icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: self.toolsToolbar.addAction(action) if add_to_menu: self.iface.addPluginToMenu(self.menu, action) if checkable: action.setCheckable(True) if checked: action.setChecked(1) if shortcut: action.setShortcut(shortcut) self.actions.append(action) return action def initGui(self): icon_path = ':/plugins/QRectangleCreator/icons/' #LoginButton self.mainButton = QToolButton() self.mainButton.setIcon(QIcon(icon_path + 'addRectangle.png')) self.mainButton.setPopupMode(QToolButton.MenuButtonPopup) self.mainButton.clicked.connect(self.run) self.mainButton.setToolTip('Add Rectangle') self.mainButton.setEnabled(True) self.mainButton.setCheckable(True) self.mainButton.setMenu(QMenu()) self.toolsToolbar.addWidget(self.mainButton) #SettingsButton self.SettingsButton = self.add_action(icon_path + 'addRectangle.png', text=self.tr(u'Settings'), callback=self.settings, parent=self.iface.mainWindow(), add_to_menu=False, enabled_flag=False, add_to_toolbar=False) m = self.mainButton.menu() m.addAction(self.SettingsButton) self.first_start = True def unload(self): for action in self.actions: self.iface.removePluginMenu(self.tr(u'&QRectangleCreator'), action) self.iface.removeToolBarIcon(action) def run(self): if self.first_start == True: self.first_start = False if self.mainButton.isChecked() == 1: self.drawingObject = StartDrawing(self.iface.mapCanvas(), self.iface) self.drawingObject.setConfiguration( self.settingsDlg.width.value(), self.settingsDlg.height.value(), self.settingsDlg.angle.value()) self.iface.mapCanvas().setMapTool(self.drawingObject) self.SettingsButton.setEnabled(True) else: self.iface.mapCanvas().unsetMapTool(self.drawingObject) self.drawingObject.reset() self.SettingsButton.setEnabled(False) def settings(self): self.settingsDlg.show() current_width = self.settingsDlg.width.value() current_height = self.settingsDlg.height.value() current_angle = self.settingsDlg.angle.value() if self.settingsDlg.exec_() != 1: self.settingsDlg.width.setValue(current_width) self.settingsDlg.height.setValue(current_height) self.settingsDlg.angle.setValue(current_angle) def settingsChanged(self): self.drawingObject.setConfiguration(self.settingsDlg.width.value(), self.settingsDlg.height.value(), self.settingsDlg.angle.value())
class View(QFrame): def __init__(self, name, parent=None): super().__init__(parent) self.setFrameStyle(QFrame.Sunken | QFrame.StyledPanel) self.graphicsView = GraphicsView(self) self.graphicsView.setRenderHint(QPainter.Antialiasing, False) self.graphicsView.setDragMode(QGraphicsView.RubberBandDrag) self.graphicsView.setOptimizationFlags( QGraphicsView.DontSavePainterState) self.graphicsView.setViewportUpdateMode( QGraphicsView.SmartViewportUpdate) self.graphicsView.setTransformationAnchor( QGraphicsView.AnchorUnderMouse) size = self.style().pixelMetric(QStyle.PM_ToolBarIconSize) iconSize = QSize(size, size) zoomInIcon = QToolButton() zoomInIcon.setAutoRepeat(True) zoomInIcon.setAutoRepeatInterval(33) zoomInIcon.setAutoRepeatDelay(0) zoomInIcon.setIcon(QIcon(QPixmap(':/images/zoomin.png'))) zoomInIcon.setIconSize(iconSize) zoomOutIcon = QToolButton() zoomOutIcon.setAutoRepeat(True) zoomOutIcon.setAutoRepeatInterval(33) zoomOutIcon.setAutoRepeatDelay(0) zoomOutIcon.setIcon(QIcon(QPixmap(':/images/zoomout.png'))) zoomOutIcon.setIconSize(iconSize) self.zoomSlider = QSlider() self.zoomSlider.setMinimum(0) self.zoomSlider.setMaximum(500) self.zoomSlider.setValue(250) self.zoomSlider.setTickPosition(QSlider.TicksRight) zoomSliderLayout = QVBoxLayout() zoomSliderLayout.addWidget(zoomInIcon) zoomSliderLayout.addWidget(self.zoomSlider) zoomSliderLayout.addWidget(zoomOutIcon) rotateLeftIcon = QToolButton() rotateLeftIcon.setIcon(QIcon(QPixmap(':/images/rotateleft.png'))) rotateLeftIcon.setIconSize(iconSize) rotateRightIcon = QToolButton() rotateRightIcon.setIcon(QIcon(QPixmap(':/images/rotateright.png'))) rotateRightIcon.setIconSize(iconSize) self.rotateSlider = QSlider() self.rotateSlider.setOrientation(Qt.Horizontal) self.rotateSlider.setMinimum(-360) self.rotateSlider.setMaximum(360) self.rotateSlider.setValue(0) self.rotateSlider.setTickPosition(QSlider.TicksBelow) rotateSliderLayout = QHBoxLayout() rotateSliderLayout.addWidget(rotateLeftIcon) rotateSliderLayout.addWidget(self.rotateSlider) rotateSliderLayout.addWidget(rotateRightIcon) self.resetButton = QToolButton() self.resetButton.setText('0') self.resetButton.setEnabled(False) labelLayout = QHBoxLayout() self.label = QLabel(name) self.label2 = QLabel("Pointer Mode") self.selectModeButton = QToolButton() self.selectModeButton.setText("Select") self.selectModeButton.setCheckable(True) self.selectModeButton.setChecked(True) self.dragModeButton = QToolButton() self.dragModeButton.setText("Drag") self.dragModeButton.setCheckable(True) self.dragModeButton.setChecked(False) self.openGlButton = QToolButton() self.openGlButton.setText("OpenGL") self.openGlButton.setCheckable(True) self.openGlButton.setEnabled(QGLFormat.hasOpenGL()) self.antialiasButton = QToolButton() self.antialiasButton.setText("Antialiasing") self.antialiasButton.setCheckable(True) self.antialiasButton.setChecked(False) self.printButton = QToolButton() self.printButton.setIcon(QIcon(QPixmap(":/images/fileprint.png"))) pointerModeGroup = QButtonGroup(self) pointerModeGroup.setExclusive(True) pointerModeGroup.addButton(self.selectModeButton) pointerModeGroup.addButton(self.dragModeButton) labelLayout.addWidget(self.label) labelLayout.addStretch() labelLayout.addWidget(self.label2) labelLayout.addWidget(self.selectModeButton) labelLayout.addWidget(self.dragModeButton) labelLayout.addStretch() labelLayout.addWidget(self.antialiasButton) labelLayout.addWidget(self.openGlButton) labelLayout.addWidget(self.printButton) topLayout = QGridLayout() topLayout.addLayout(labelLayout, 0, 0) topLayout.addWidget(self.graphicsView, 1, 0) topLayout.addLayout(zoomSliderLayout, 1, 1) topLayout.addLayout(rotateSliderLayout, 2, 0) topLayout.addWidget(self.resetButton, 2, 1) self.setLayout(topLayout) self.resetButton.clicked.connect(self.resetView) self.zoomSlider.valueChanged.connect(self.setupMatrix) self.rotateSlider.valueChanged.connect(self.setupMatrix) self.graphicsView.verticalScrollBar().valueChanged.connect( self.setResetButtonEnabled) self.graphicsView.horizontalScrollBar().valueChanged.connect( self.setResetButtonEnabled) self.selectModeButton.toggled.connect(self.togglePointerMode) self.dragModeButton.toggled.connect(self.togglePointerMode) self.antialiasButton.toggled.connect(self.toggleAntialiasing) self.openGlButton.toggled.connect(self.toggleOpenGL) rotateLeftIcon.clicked.connect(self.rotateLeft) rotateRightIcon.clicked.connect(self.rotateRight) zoomInIcon.clicked.connect(self.zoomIn) zoomOutIcon.clicked.connect(self.zoomOut) self.printButton.clicked.connect(self.print) self.setupMatrix() def view(self): return self.graphicsView def resetView(self): self.zoomSlider.setValue(250) self.rotateSlider.setValue(0) self.setupMatrix() self.graphicsView.ensureVisible(QRectF(0, 0, 0, 0)) self.resetButton.setEnabled(False) def setResetButtonEnabled(self): self.resetButton.setEnabled(True) def setupMatrix(self): scale = pow(2.0, (self.zoomSlider.value() - 250) / 50) matrix = QTransform() matrix.scale(scale, scale) matrix.rotate(self.rotateSlider.value()) self.graphicsView.setTransform(matrix) self.setResetButtonEnabled() def togglePointerMode(self): self.graphicsView.setDragMode( QGraphicsView.RubberBandDrag if self.selectModeButton.isChecked( ) else QGraphicsView.ScrollHandDrag) self.graphicsView.setInteractive(self.selectModeButton.isChecked()) def toggleOpenGL(self): vp = QWidget() if self.openGlButton.isChecked(): fmt = QSurfaceFormat() fmt.setSamples(8) vp = QOpenGLWidget() vp.setFormat(fmt) self.graphicsView.setViewport(vp) def toggleAntialiasing(self): self.graphicsView.setRenderHint(QPainter.Antialiasing, self.antialiasButton.isChecked()) def print(self): pass def zoomIn(self, level=1): self.zoomSlider.setValue(self.zoomSlider.value() + level) def zoomOut(self, level=1): self.zoomSlider.setValue(self.zoomSlider.value() - level) def rotateLeft(self): self.rotateSlider.setValue(self.rotateSlider.value() - 10) def rotateRight(self): self.rotateSlider.setValue(self.rotateSlider.value() + 10)
class kstImageViewer(QWidget): def __init__(self, sourceFile, data, type, image, mode): """ Class constructor. """ QWidget.__init__(self) # Initialize image panel: self.imagePanel = _kstImagePanel() # Set original mode: self.__originalMode = mode # Set the type of image with respect of the lightfield pipeline: self.__imageType = type # 'raw', 'pre-processed', 'reconstructed', 'post-processed' # The actual object handled by the image viewer: self.__data = data # Properties: self.__sourceFile = sourceFile # Current view index: self.__view = 0 # Top toolbar: self.topToolBar = QToolBar() self._createTopToolbar() # Bottom toolbar: self.bottomToolBar = QToolBar() self._createBottomToolbar() # Handle mouse hover with custom slot: self.imagePanel.mouseHoverEvent.connect(self._handleMouseHover) # Compose layout of the whole widget: layout = QVBoxLayout() layout.addWidget(self.topToolBar) layout.addWidget(self.imagePanel) layout.addWidget(self.bottomToolBar) layout.setContentsMargins(0,0,0,0) self.setLayout(layout) self.setContentsMargins(0,0,0,0) # Set image: self.__setImage(image) def _createTopToolbar(self): """ """ topToolbarSizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.topToolBar.setSizePolicy(topToolbarSizePolicy) #pan_zoom = QAction(QIcon(dir + "/resources/btnDrag.png"),"Pan (Mouse #Left)",self) #self.toolBar.addAction(pan_zoom) #zoomSelect = QAction(QIcon(dir + "/resources/btnZoomSelect.png"),"ROI Zoom #(Mouse Left)",self) #self.toolBar.addAction(zoomSelect) exitAct = QAction('Exit', self) exitAct.setShortcut('Ctrl+Q') self._panZoom = QToolButton(self) self._panZoom.setIcon(QIcon(PAN_ZOOM_ICON)) self._panZoom.setToolTip(PAN_ZOOM_TOOLTIP) self._panZoom.setCheckable(True) self._panZoom.setChecked(True) self._panZoom.clicked.connect(self._panZoomSwitch) self.topToolBar.addWidget(self._panZoom) self._zoomSelect = QToolButton(self) self._zoomSelect.setIcon(QIcon(ZOOM_SELECT_ICON)) self._zoomSelect.setToolTip(ZOOM_SELECT_TOOLTIP) self._zoomSelect.setCheckable(True) self._zoomSelect.setChecked(False) self._zoomSelect.clicked.connect(self._zoomSelectSwitch) self.topToolBar.addWidget(self._zoomSelect) self.topToolBar.addSeparator() zoomIn = QAction(QIcon(ZOOM_IN_ICON),ZOOM_IN_TOOLTIP,self) self.topToolBar.addAction(zoomIn) zoomOut = QAction(QIcon(ZOOM_OUT_ICON),ZOOM_OUT_TOOLTIP,self) self.topToolBar.addAction(zoomOut) zoomReset = QAction(QIcon(ZOOM_RESET_ICON),ZOOM_RESET_TOOLTIP,self) self.topToolBar.addAction(zoomReset) self.topToolBar.addSeparator() # Separator: #self.fooWidget = QWidget() #self.fooWidget.setFixedWidth(6) #self.fooWidgetAction = self.topToolBar.addWidget(self.fooWidget) #self.extraSeparatorAction = self.topToolBar.addSeparator() export = QAction(QIcon(EXPORT_ICON),EXPORT_TOOLTIP,self) self.topToolBar.addAction(export) exportAll = QAction(QIcon(EXPORTALL_ICON),EXPORTALL_TOOLTIP,self) self.topToolBar.addAction(exportAll) # Spacer: spacer = QWidget() spacerSizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) spacer.setSizePolicy(spacerSizePolicy) self.topToolBar.addWidget(spacer) # Label on the right: self.hoverLabel = QLabel(self) self.hoverLabel.setText("") self.topToolBar.addWidget(self.hoverLabel) # Connect handler for toolbar buttons: self.topToolBar.actionTriggered[QAction].connect(self._toolBarBtnPressed) def _createBottomToolbar(self): """ """ bottomToolbarSizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.bottomToolBar.setSizePolicy(bottomToolbarSizePolicy) # Combo box for the 4 "views" of a dataset: self.lblView = QLabel(" View: ") # Use spaces self.lblViewAction = self.bottomToolBar.addWidget(self.lblView) self.cbxView = QComboBox() self.cbxView.addItems(["Projection/Axial", "Sinogram/Sagittal", "Lateral/Frontal"]) self.cbxView.currentIndexChanged.connect(self.changeView) self.cbxViewAction = self.bottomToolBar.addWidget(self.cbxView) self.indexLabel = QLabel(self) self.indexLabel.setText("") self.indexLabel.setFixedWidth(70) self.indexLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.bottomToolBar.addWidget(self.indexLabel) # Slider for the projection/slices: self.lblImageSlider = QLabel(" Image: ") # Use spaces self.lblImageSliderAction = self.bottomToolBar.addWidget(self.lblImageSlider) self.sldDataset = QSlider(Qt.Horizontal) self.sldDataset.setFixedWidth(250) self.sldDataset.setFocusPolicy(Qt.StrongFocus) self.sldDataset.setTickPosition(QSlider.TicksBelow) self.sldDataset.valueChanged.connect(self.changeDatasetView) self.sldDatasetAction = self.bottomToolBar.addWidget(self.sldDataset) # Slider for the repetitions: self.lblRepetitionIndex = QLabel(self) self.lblRepetitionIndex.setText("") self.lblRepetitionIndex.setFixedWidth(50) self.lblRepetitionIndex.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.bottomToolBar.addWidget(self.lblRepetitionIndex) self.lblRepetitionSlider = QLabel(" Repetition: ") # Use spaces self.lblRepetitionSlider.setFixedWidth(80) self.lblRepetitionSlider.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.lblRepetitionSliderAction = self.bottomToolBar.addWidget(self.lblRepetitionSlider) self.sldRepetition = QSlider(Qt.Horizontal) self.sldRepetition.setFixedWidth(150) self.sldRepetition.setFocusPolicy(Qt.StrongFocus) self.sldRepetition.setTickPosition(QSlider.TicksBelow) self.sldRepetition.valueChanged.connect(self.changeRepetitionView) self.sldRepetitionAction = self.bottomToolBar.addWidget(self.sldRepetition) if self.__data.ndim == 4: self.lblRepetitionSliderAction.setVisible(True) self.sldRepetitionAction.setVisible(True) else: self.lblRepetitionSliderAction.setVisible(False) self.sldRepetitionAction.setVisible(False) #def drawBackground(self, painter, rect): # color = self.palette().color(QPalette.Background) # background_brush = QBrush( color, Qt.SolidPattern) # painter.fillRect(rect, background_brush) def _panZoomSwitch(self): self._zoomSelect.setChecked(not self._panZoom.isChecked()) self.imagePanel.togglePanZoom = self._zoomSelect.isChecked() def _zoomSelectSwitch(self): self._panZoom.setChecked(not self._zoomSelect.isChecked()) self.imagePanel.togglePanZoom = self._zoomSelect.isChecked() def _toolBarBtnPressed(self, button): if button.text() == ZOOM_IN_TOOLTIP: self.imagePanel.performZoom(min(400.0,self.imagePanel.zoomFactor*1.15)) elif button.text() == ZOOM_OUT_TOOLTIP: self.imagePanel.performZoom(max(1.0,self.imagePanel.zoomFactor/1.15)) elif button.text() == ZOOM_RESET_TOOLTIP: self.imagePanel.performZoom(1.0) elif button.text() == EXPORT_TOOLTIP: # Open a Save As dialog: try: options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog filename, _ = QFileDialog.getSaveFileName(self,"Save as TIFF", "","TIFF Files (*.tif);;All Files (*)", options=options) if filename: # Call the method to save the current displayed image: self.imagePanel.saveAsTIFF(filename) except Exception as e: eprint(str(e)) elif button.text() == EXPORTALL_TOOLTIP: # Open a Save As dialog: try: options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog options |= QFileDialog.DirectoryOnly folder = QFileDialog.getExistingDirectory(self, "Select Folder for TIFF sequence") if folder: for i in range(0,self.__data.shape[2]): # Prepare filename: filename = os.path.join(folder, "image_" + "{:04d}".format(i) + ".tif") # Save as TIFF with tiffile library: tifffile.imsave(filename, data=self.__data[:,:,i]) except Exception as e: eprint(str(e)) def _handleMouseHover(self, x, y, z, type): if (x == -1): self.hoverLabel.setText("") else: if (type == 'float'): s = "{:0.4f}".format(z) if (z > 1e-2) else "{:.4E}".format(z) else: s = "{:d}".format(round(z)) self.hoverLabel.setText("[" + str(x) + "," + str(y) + "]=" + s + " " ) def __setImage(self, npImage): """ Set the scene's current image pixmap to the input image as a numpy array. :type npImage: numpy array """ # Set the new numpy image: self.imagePanel.setImage(npImage) # Enable/disable UI widgets: if (self.__imageType == 'raw'): self.lblViewAction.setVisible(True) self.cbxViewAction.setVisible(True) self.lblImageSliderAction.setVisible(True) self.sldDatasetAction.setVisible(True) if self.__data.ndim == 4: self.lblRepetitionSliderAction.setVisible(True) self.lblRepetitionIndex.setVisible(True) self.sldRepetitionAction.setVisible(True) else: self.lblRepetitionSliderAction.setVisible(False) self.lblRepetitionIndex.setVisible(False) self.sldRepetitionAction.setVisible(False) elif (self.__imageType == 'pre-processed'): self.lblViewAction.setVisible(True) self.cbxViewAction.setVisible(True) self.lblImageSliderAction.setVisible(True) self.sldDatasetAction.setVisible(True) self.sldRepetitionAction.setVisible(False) self.lblRepetitionIndex.setVisible(False) self.lblRepetitionSliderAction.setVisible(False) elif (self.__imageType == 'reconstructed'): self.lblViewAction.setVisible(True) self.cbxViewAction.setVisible(True) self.lblImageSliderAction.setVisible(True) self.sldDatasetAction.setVisible(True) self.sldRepetitionAction.setVisible(False) self.lblRepetitionIndex.setVisible(False) self.lblRepetitionSliderAction.setVisible(False) # Set dimension of the slider and default: self.sldDataset.setMinimum(0) self.sldDataset.setMaximum(self.__data.shape[2]-1) self.sldDataset.setValue(round(self.__data.shape[2]/2)) self.indexLabel.setText(str(round(self.__data.shape[2]/2)) \ + "/" + str(round(self.__data.shape[2]))) def changeView(self, idx): """ Called when the combo box index is changed. """ # Reset sliders: self.sldDataset.setValue(0) if self.__data.ndim == 4: self.sldRepetition.setValue(0) # Transpose datasets: if idx == 0: # Axial or projection view: if self.__data.ndim == 4: if self.__view == 1: self.__data = numpy.transpose(self.__data, (2,1,0,3)) # OK if self.__view == 2: self.__data = numpy.transpose(self.__data, (1,2,0,3)) # OK else: if self.__view == 1: self.__data = numpy.transpose(self.__data, (2,1,0)) # OK if self.__view == 2: self.__data = numpy.transpose(self.__data, (1,2,0)) # OK elif idx == 1: # Sinogram of sagittal view: if self.__data.ndim == 4: if self.__view == 0: self.__data = numpy.transpose(self.__data, (2,1,0,3)) # OK if self.__view == 2: self.__data = numpy.transpose(self.__data, (0,2,1,3)) # OK else: if self.__view == 0: self.__data = numpy.transpose(self.__data, (2,1,0)) # OK if self.__view == 2: self.__data = numpy.transpose(self.__data, (0,2,1)) # OK else: # Lateral or coronal view: if self.__data.ndim == 4: if self.__view == 0: self.__data = numpy.transpose(self.__data, (2,0,1,3)) # OK if self.__view == 1: self.__data = numpy.transpose(self.__data, (0,2,1,3)) # OK else: if self.__view == 0: self.__data = numpy.transpose(self.__data, (2,0,1)) # OK if self.__view == 1: self.__data = numpy.transpose(self.__data, (0,2,1)) # OK # Set new view: self.__view = idx # Change to the new numpy image: if self.__data.ndim == 4: self.imagePanel.changeImage(self.__data[:,:,round(self.__data.shape[2]/2),round(self.__data.shape[3]/2)]) else: self.imagePanel.changeImage(self.__data[:,:,round(self.__data.shape[2]/2)]) # Set the index: self.sldDataset.setMinimum(0) self.sldDataset.setMaximum(self.__data.shape[2]-1) self.sldDataset.setValue(round(self.__data.shape[2]/2)) # Reset zoom: self.imagePanel.performZoom(1.0) def changeDatasetView(self): """ Called when the slider is moved, so user wants to see a different projection or slice. """ val = int(self.sldDataset.value()) # Change to the new numpy image: if self.__data.ndim == 4: rep = int(self.sldRepetition.value()) self.imagePanel.changeImage(self.__data[:,:,val,rep]) #self.sldRepetition.setValue(round(self.__data.shape[3]/2)) else: self.imagePanel.changeImage(self.__data[:,:,val]) # Set the index: self.indexLabel.setText(str(val + 1) + "/" + str(round(self.__data.shape[2]))) def changeRepetitionView(self): """ Called when the slider is moved, so user wants to see a different repetition of the same projection. """ img = int(self.sldDataset.value()) val = int(self.sldRepetition.value()) # Change to the new numpy image: self.imagePanel.changeImage(self.__data[:,:,img,val]) # Set the index: self.lblRepetitionIndex.setText(str(val+1) + "/" + str(round(self.__data.shape[3]))) def getType(self): """ Get the type of current image viewer. """ # Set the new numpy image: return self.__imageType def getOriginalMode(self): """ Get the original mode (2COL or 1COL). """ # Set the new numpy image: return self.__originalMode def getSourceFile(self): """ Get the source file of current image viewer. """ # Set the new numpy image: return self.__sourceFile def getImage(self): """ Get the scene's current image pixmap as a numpy array. """ # Set the new numpy image: return self.imagePanel.npImage def getData(self): """ Get the data connected to this image viewer. """ return self.__data
class View(QFrame): graphicsView = None label = None label2 = None selectModeButton = None dragModeButton = None openGlButton = None antialiasButton = None resetButton = None zoomSlider = None rotateSlider = None def __init__(self, name, parent=None): super(View, self).__init__(parent) self.init_ui(name) def init_ui(self, name): self.setFrameStyle(QFrame.Sunken | QFrame.StyledPanel) self.graphicsView = GraphicsView(self) self.graphicsView.setRenderHint(QPainter.Antialiasing, False) self.graphicsView.setDragMode(QGraphicsView.RubberBandDrag) self.graphicsView.setOptimizationFlags( QGraphicsView.DontSavePainterState) self.graphicsView.setViewportUpdateMode( QGraphicsView.SmartViewportUpdate) self.graphicsView.setTransformationAnchor( QGraphicsView.AnchorUnderMouse) size = self.style().pixelMetric(QStyle.PM_ToolBarIconSize) iconSize = QSize(size, size) zoomInIcon = QToolButton() zoomInIcon.setAutoRepeat(True) zoomInIcon.setAutoRepeatInterval(33) zoomInIcon.setAutoRepeatDelay(0) zoomInIcon.setIcon(QIcon(":/zoomin.png")) zoomInIcon.setIconSize(iconSize) zoomOutIcon = QToolButton() zoomOutIcon.setAutoRepeat(True) zoomOutIcon.setAutoRepeatInterval(33) zoomOutIcon.setAutoRepeatDelay(0) zoomOutIcon.setIcon(QIcon(":/zoomout.png")) zoomOutIcon.setIconSize(iconSize) self.zoomSlider = QSlider() self.zoomSlider.setMinimum(0) self.zoomSlider.setMaximum(500) self.zoomSlider.setValue(250) self.zoomSlider.setTickPosition(QSlider.TicksRight) # Zoom slider layout zoomSliderLayout = QVBoxLayout() zoomSliderLayout.addWidget(zoomInIcon) zoomSliderLayout.addWidget(self.zoomSlider) zoomSliderLayout.addWidget(zoomOutIcon) rotateLeftIcon = QToolButton() rotateLeftIcon.setIcon(QIcon(":/rotateleft.png")) rotateLeftIcon.setIconSize(iconSize) rotateRightIcon = QToolButton() rotateRightIcon.setIcon(QIcon(":/rotateright.png")) rotateRightIcon.setIconSize(iconSize) self.rotateSlider = QSlider() self.rotateSlider.setOrientation(Qt.Horizontal) self.rotateSlider.setMinimum(-360) self.rotateSlider.setMaximum(360) self.rotateSlider.setValue(0) self.rotateSlider.setTickPosition(QSlider.TicksBelow) # Rotate slider layout rotateSliderLayout = QHBoxLayout() rotateSliderLayout.addWidget(rotateLeftIcon) rotateSliderLayout.addWidget(self.rotateSlider) rotateSliderLayout.addWidget(rotateRightIcon) self.resetButton = QToolButton() self.resetButton.setText("0") self.resetButton.setEnabled(False) # Label layout labelLayout = QHBoxLayout() self.label = QLabel(name) self.label2 = QLabel("Pointer Mode") self.selectModeButton = QToolButton() self.selectModeButton.setText("Select") self.selectModeButton.setCheckable(True) self.selectModeButton.setChecked(True) self.dragModeButton = QToolButton() self.dragModeButton.setText("Drag") self.dragModeButton.setCheckable(True) self.dragModeButton.setChecked(False) self.antialiasButton = QToolButton() self.antialiasButton.setText("Antialiasing") self.antialiasButton.setCheckable(True) self.antialiasButton.setChecked(False) self.openGlButton = QToolButton() self.openGlButton.setText("OpenGL") self.openGlButton.setCheckable(True) self.openGlButton.setEnabled(QGLFormat.hasOpenGL()) pointerModeGroup = QButtonGroup() pointerModeGroup.setExclusive(True) pointerModeGroup.addButton(self.selectModeButton) pointerModeGroup.addButton(self.dragModeButton) labelLayout.addWidget(self.label) labelLayout.addStretch() labelLayout.addWidget(self.label2) labelLayout.addWidget(self.selectModeButton) labelLayout.addWidget(self.dragModeButton) labelLayout.addStretch() labelLayout.addWidget(self.antialiasButton) labelLayout.addWidget(self.openGlButton) topLayout = QGridLayout() topLayout.addLayout(labelLayout, 0, 0) topLayout.addWidget(self.graphicsView, 1, 0) topLayout.addLayout(zoomSliderLayout, 1, 1) topLayout.addLayout(rotateSliderLayout, 2, 0) topLayout.addWidget(self.resetButton, 2, 1) self.setLayout(topLayout) self.resetButton.clicked.connect(self.resetView) self.zoomSlider.valueChanged.connect(self.setupTransform) self.rotateSlider.valueChanged.connect(self.setupTransform) self.graphicsView.verticalScrollBar().valueChanged.connect( self.setResetButtonEnabled) self.graphicsView.horizontalScrollBar().valueChanged.connect( self.setResetButtonEnabled) self.selectModeButton.toggled.connect(self.togglePointerMode) self.dragModeButton.toggled.connect(self.togglePointerMode) self.antialiasButton.toggled.connect(self.toggleAntialiasing) self.openGlButton.toggled.connect(self.toggleOpenGL) rotateLeftIcon.clicked.connect(self.rotateLeft) rotateRightIcon.clicked.connect(self.rotateRight) zoomInIcon.clicked.connect(self.zoomIn) zoomOutIcon.clicked.connect(self.zoomOut) self.setupTransform() def view(self): return self.graphicsView @pyqtSlot() def zoomIn(self): self.zoomSlider.setValue(self.zoomSlider.value() + 1) @pyqtSlot() def zoomOut(self): self.zoomSlider.setValue(self.zoomSlider.value() - 1) @pyqtSlot() def resetView(self): self.zoomSlider.setValue(250) self.rotateSlider.setValue(0) self.setupTransform() self.graphicsView.ensureVisible(QRectF(0, 0, 0, 0)) self.resetButton.setEnabled(False) @pyqtSlot() def setResetButtonEnabled(self): self.resetButton.setEnabled(True) @pyqtSlot() def setupTransform(self): scale = pow(2.0, (self.zoomSlider.value() - 250) / 50.0) trans = QTransform() trans.scale(scale, scale) trans.rotate(self.rotateSlider.value()) self.graphicsView.setTransform(trans) self.setResetButtonEnabled() @pyqtSlot() def togglePointerMode(self): self.graphicsView.setDragMode( QGraphicsView.RubberBandDrag if self.selectModeButton.isChecked( ) else QGraphicsView.ScrollHandDrag) self.graphicsView.setInteractive(self.selectModeButton.isChecked()) @pyqtSlot() def toggleOpenGL(self): self.graphicsView.setViewport( QGLWidget(QGLFormat(QGL.SampleBuffers)) if self.openGlButton. isChecked() else QWidget()) @pyqtSlot() def toggleAntialiasing(self): self.graphicsView.setRenderHint(QPainter.Antialiasing, self.antialiasButton.isChecked()) @pyqtSlot() def rotateLeft(self): self.rotateSlider.setValue(self.rotateSlider.value() - 10) @pyqtSlot() def rotateRight(self): self.rotateSlider.setValue(self.rotateSlider.value() + 10)
class CollapsibleMessageBox(QWidget): ''' docstring: 消息显示类,按钮触发折叠 ''' def __init__(self, Title="", parent=None, defaultLayout=False, Message=None): super().__init__(parent) self.toggle_button = QToolButton(text=Title, checkable=True, checked=False) self.toggle_button.setStyleSheet("QToolButton { border: none; }") self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.toggle_button.setArrowType(Qt.RightArrow) self.toggle_button.pressed.connect(self.on_pressed) self.toggle_animation = QParallelAnimationGroup(self) self.content_area = QScrollArea(maximumHeight=0, minimumHeight=0) self.content_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.content_area.setFrameShape(QFrame.NoFrame) lay = QVBoxLayout(self) lay.setSpacing(0) lay.setContentsMargins(0, 0, 0, 0) lay.addWidget(self.toggle_button) lay.addWidget(self.content_area) self.toggle_animation.addAnimation( QPropertyAnimation(self, b"minimumHeight")) self.toggle_animation.addAnimation( QPropertyAnimation(self, b"maximumHeight")) self.toggle_animation.addAnimation( QPropertyAnimation(self.content_area, b"maximumHeight")) if defaultLayout: lay = QVBoxLayout() self.text = QLabel() pa = QPalette() pa.setColor(pa.Background, Qt.white) pa.setColor(pa.Foreground, Qt.black) self.text.setAutoFillBackground(True) self.text.setPalette(pa) self.text.setTextInteractionFlags(Qt.TextSelectableByMouse) self.text.setTextFormat(Qt.MarkdownText) self.text.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum) self.text.setWordWrap(True) if not Message: Message = '空' self.text.setText(Message.replace('\n', '\n\n') + '\n') lay.addWidget(self.text) self.setContentLayout(lay) @pyqtSlot() def on_pressed(self): ''' docstring: 按钮函数,设置动画参数并触发 ''' checked = self.toggle_button.isChecked() self.toggle_button.setArrowType( Qt.DownArrow if not checked else Qt.RightArrow) self.toggle_animation.setDirection( QAbstractAnimation.Forward if not checked else QAbstractAnimation. Backward) self.toggle_animation.start() def setContentLayout(self, layout): ''' docstring: 重新设置布局,并计算按钮动画参数 ''' lay = self.content_area.layout() del lay self.content_area.setLayout(layout) collapsed_height = (self.sizeHint().height() - self.content_area.maximumHeight()) content_height = layout.sizeHint().height() for i in range(self.toggle_animation.animationCount()): animation = self.toggle_animation.animationAt(i) animation.setDuration(500) animation.setStartValue(collapsed_height) animation.setEndValue(collapsed_height + content_height) content_animation = self.toggle_animation.animationAt( self.toggle_animation.animationCount() - 1) content_animation.setDuration(500) content_animation.setStartValue(0) content_animation.setEndValue(content_height)
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): self.current_dir = 'F:/Desktop2020.1.17/AutoCut/' self.font = cv2.FONT_HERSHEY_SIMPLEX self.mouse_pos_initial() exitAct = QAction(QIcon('quit.jpg'), '&Quit', self) exitAct.setShortcut('Ctrl+Q') exitAct.triggered.connect(qApp.quit) help_contact = QAction('Contact', self) help_contact.triggered.connect(self.contact) self.menubar = self.menuBar() FileMenu = self.menubar.addMenu('&File') FileMenu.addAction(exitAct) HelpMenu = self.menubar.addMenu('&Help') HelpMenu.addAction(help_contact) self.read_button = QToolButton() self.read_button.setIcon(QIcon(self.current_dir + 'read.png')) self.read_button.setToolTip('Read Ctrl+R') self.read_button.clicked.connect(self.read) self.read_button.setShortcut('Ctrl+R') self.draw_shape_action_list = [] self.draw_shape_list = [] self.draw_shape_action_list_for_redo = [] self.draw_shape_count = 1 self.line_button = QToolButton() self.line_button.setIcon(QIcon(self.current_dir + 'line.png')) self.line_button.setToolTip('Draw line') self.line_button.clicked.connect(self.draw_line) self.line_button.setCheckable(True) self.draw_shape_line = False self.drawing_shape_line = False self.show_distance = False # line = Line(0,0,100,100) self.eraser_button = QToolButton() self.eraser_button.setIcon(QIcon(self.current_dir + 'eraser.png')) self.eraser_button.setToolTip('eraser') self.eraser_button.clicked.connect(self.erase_shape) self.eraser_button.setCheckable(True) self.erase = False self.drawing_eraser = False self.undo_button = QToolButton() self.undo_button.setIcon( QIcon(self.current_dir + 'undo_gray_opacity.png')) self.undo_button.setToolTip('undo Ctrl+Z') self.undo_button.clicked.connect(self.undo_draw) self.undo_button.setShortcut('Ctrl+Z') self.redo_button = QToolButton() self.redo_button.setIcon( QIcon(self.current_dir + 'redo_gray_opacity.png')) self.redo_button.setToolTip('redo Ctrl+Y') self.redo_button.clicked.connect(self.redo_draw) self.redo_button.setShortcut('Ctrl+Y') self.clear_button = QToolButton() self.clear_button.setIcon(QIcon(self.current_dir + 'clear.png')) self.clear_button.setToolTip('clear drawing') self.clear_button.clicked.connect(self.clear_draw) self.run_button = QToolButton() self.run_button.setIcon(QIcon(self.current_dir + 'run.png')) self.run_button.setToolTip('Run F5') self.run_button.clicked.connect(self.run_cut) self.run_button.setShortcut('F5') self.repeat_button = QToolButton() self.repeat_button.setIcon(QIcon(self.current_dir + 'repeat.png')) self.repeat_button.setToolTip('Repeat') self.repeat_button.clicked.connect(self.repeat_cut) self.toolbar1 = self.addToolBar('Read') self.toolbar1.addWidget(self.read_button) self.toolbar2 = self.addToolBar('draw') self.toolbar2.addWidget(self.line_button) self.toolbar2.addWidget(self.undo_button) self.toolbar2.addWidget(self.redo_button) self.toolbar2.addWidget(self.eraser_button) self.toolbar2.addWidget(self.clear_button) self.toolbar3 = self.addToolBar('run') self.toolbar3.addWidget(self.run_button) self.toolbar3.addWidget(self.repeat_button) self.toolbar = self.addToolBar(' ') self.pixmap = QPixmap() self.lbl_main = QLabel(self) self.lbl_main.setAlignment(Qt.AlignTop) # self.lbl_main.setAlignment(Qt.AlignCenter) self.lbl_main.setPixmap(self.pixmap) self.vbox = QVBoxLayout() self.vbox.addWidget(self.lbl_main) self.central_widget = QWidget() self.layout = QVBoxLayout(self.central_widget) self.setCentralWidget(self.central_widget) self.layout.addLayout(self.vbox) self.refresh_timer = QTimer() self.refresh_timer.timeout.connect(self.refresh_show) self.setWindowTitle('Auto Cut') self.show() def read(self): window_name = 'Scanning control' self.scan_control_hwnd = win32gui.FindWindow(None, window_name) if self.scan_control_hwnd == 0: window_name = 'Scanning control ( Lift Mode )' self.scan_control_hwnd = win32gui.FindWindow(None, window_name) # win32gui.ShowWindow(scan_control_hwnd, win32con.SW_MAXIMIZE) win32gui.SendMessage(self.scan_control_hwnd, win32con.WM_SYSCOMMAND, win32con.SC_RESTORE, 0) win32gui.SetForegroundWindow(self.scan_control_hwnd) time.sleep(0.5) hwnd = self.scan_control_hwnd hwndChildList = [] win32gui.EnumChildWindows(hwnd, lambda hwnd, param: param.append(hwnd), hwndChildList) for hwnd_child in hwndChildList: name = win32gui.GetWindowText(hwnd_child) if 'Scan Area' in name: self.frame_hwnd = hwnd_child break # run_hwnd = hwndChildList[3] # self.frame_hwnd = hwndChildList[54] # self.frame_hwnd = self.scan_control_hwnd self.left, self.top, self.right, self.bottom = win32gui.GetWindowRect( self.frame_hwnd) print(self.left, self.top, self.right, self.bottom) self.screenshot = pyautogui.screenshot(region=[self.left,self.top,\ self.right-self.left,\ self.bottom-self.top]) self.screenshot = np.asarray(self.screenshot) #self.screenshot = cv2.imread('F:/Desktop2020.1.17/AutoCut/screenshot2.bmp') #self.screenshot = cv2.cvtColor(self.screenshot, cv2.COLOR_BGR2RGB) self.crop_left, self.crop_top, self.crop_right, self.crop_bottom = find_region( self.screenshot) self.screenshot = self.screenshot[self.crop_top: self.crop_bottom, \ self.crop_left: self.crop_right] # self.img = cv2.cvtColor(np.asarray(self.img),cv2.COLOR_RGB2BGR) self.start_refresh() print('Read') def contact(self): print('contact') def mouse_pos_initial(self): self.mouse_x1, self.mouse_y1 = 0, 0 self.mouse_x2, self.mouse_y2 = 0, 0 def mousePressEvent(self, event): self.mouse_x1_raw = max(0, event.pos().x()) self.mouse_y1_raw = max(0, event.pos().y()) self.mouse_x2_raw, self.mouse_y2_raw = self.mouse_x1_raw, self.mouse_y1_raw self.mouse_pos_correct() if event.buttons() == Qt.LeftButton and self.draw_shape_line: self.draw_shape_action_list.append(Line(self.mouse_x1, self.mouse_y1, \ self.mouse_x2, self.mouse_y2, \ color = (0,255,0),\ num = self.draw_shape_count,\ show_distance = self.show_distance)) self.draw_shape_count += 1 self.drawing_shape_line = True self.undo_redo_setting() elif event.buttons() == Qt.LeftButton and self.erase: self.draw_shape_action_list.append(Eraser(self.mouse_x1, \ self.mouse_y1, num = [0])) self.drawing_eraser = True print(self.mouse_x1, self.mouse_y1) def mouseMoveEvent(self, event): self.mouse_x2_raw = max(0, event.pos().x()) self.mouse_y2_raw = max(0, event.pos().y()) self.mouse_pos_correct() if self.drawing_shape_line: self.draw_shape_action_list[-1].x2 = self.mouse_x2 self.draw_shape_action_list[-1].y2 = self.mouse_y2 self.draw_shape_action_list[-1].pos_refresh() if self.drawing_eraser: self.draw_shape_action_list[-1].x1 = self.mouse_x2 self.draw_shape_action_list[-1].y1 = self.mouse_y2 self.draw_shape_action_list[-1].pos_refresh() def mouseReleaseEvent(self, event): if self.mouse_x1_raw == self.mouse_x2_raw and self.mouse_y1_raw == self.mouse_y2_raw: if self.drawing_shape_line: self.draw_shape_action_list.pop() if event.button() == Qt.LeftButton and self.drawing_eraser: self.drawing_eraser = False if len(self.draw_shape_action_list[-1].num) == 1: self.draw_shape_action_list.pop() def mouse_pos_correct(self): lbl_main_x = self.lbl_main.pos().x() lbl_main_y = self.lbl_main.pos().y() + self.menubar.height( ) + self.toolbar.height() self.mouse_x1 = self.mouse_x1_raw - lbl_main_x self.mouse_x2 = self.mouse_x2_raw - lbl_main_x self.mouse_y1 = self.mouse_y1_raw - lbl_main_y self.mouse_y2 = self.mouse_y2_raw - lbl_main_y def refresh_show(self): self.img = self.screenshot.copy() if len(self.draw_shape_action_list) > 0: self.generate_draw_shape_list() self.draw_shape_canvas() if self.drawing_eraser: eraser_temp = self.draw_shape_action_list[-1] cv2.circle(self.img, *eraser_temp.pos, eraser_temp.size, \ eraser_temp.color, eraser_temp.width) cv2.circle(self.img, *eraser_temp.pos, eraser_temp.size, \ (0,0,0), 1) # self.find_eraser_num() self.show_on_screen() def generate_draw_shape_list(self): self.draw_shape_list = [] for action in self.draw_shape_action_list: if action.prop != 'eraser' and action.prop != 'clear': self.draw_shape_list.append(action) elif action.prop == 'eraser': i = 0 while i < len(self.draw_shape_list): if self.draw_shape_list[i].num in action.num: #print(action.num) self.draw_shape_list.pop(i) i -= 1 i += 1 if i == len(self.draw_shape_list): break elif action.prop == 'clear': self.draw_shape_list = [] def draw_shape_canvas(self): #目前canvas还没什么用,均可用img_show代替,但也可以先留着 self.canvas = np.zeros(self.img.shape, dtype=np.uint8) self.canvas_blank = np.zeros((self.img.shape[0], self.img.shape[1]), dtype=int) count = 1 if len(self.draw_shape_list) == 0: pass for shape in self.draw_shape_list: # shape.x1, shape.y1 = self.mouse_pos_ratio_change_line(shape.x1, shape.y1) # shape.x2, shape.y2 = self.mouse_pos_ratio_change_line(shape.x2, shape.y2) # shape.pos_refresh() if shape.prop == 'line' or shape.prop == 'base line': x_temp, y_temp = Pos_of_Line(*list(shape.pos[0]), *list(shape.pos[1])) self.canvas_blank = record_draw_shape(self.canvas_blank, \ np.array(x_temp), np.array(y_temp), \ shape.num) cv2.circle(self.img, shape.pos[0], 5, shape.color, 1) cv2.line(self.img, *shape.pos, shape.color, shape.width) cv2.putText(self.img, str(count), shape.pos[1], self.font, 0.7, \ shape.color, 1, cv2.LINE_AA) count += 1 if shape.show_distance: distance = self.calculate_distance(shape.x1, shape.y1, shape.x2, shape.y2) pos = (round((shape.x1 + shape.x2) / 2), round((shape.y1 + shape.y2) / 2)) cv2.putText(self.img, str(round(distance, 2)), pos, \ self.font, 0.7, (255,0,0), 1, cv2.LINE_AA) def start_refresh(self): self.refresh_timer.start(30) def show_on_screen(self): self.img_qi = QImage(self.img[:], self.img.shape[1], self.img.shape[0],\ self.img.shape[1] * 3, QImage.Format_RGB888) self.pixmap = QPixmap(self.img_qi) self.lbl_main.setPixmap(self.pixmap) def draw_line(self): if self.line_button.isChecked(): self.draw_shape_initial() self.draw_shape_line = True self.line_button.setChecked(True) else: self.draw_shape_line = False self.drawing_shape_line = False self.line_button.setChecked(False) print('draw line') def erase_shape(self): if self.eraser_button.isChecked(): self.draw_shape_initial() self.erase = True self.eraser_button.setChecked(True) else: self.erase = False self.eraser_button.setChecked(False) def undo_redo_setting(self): self.undo_button.setIcon(QIcon(self.current_dir + 'undo.png')) self.draw_shape_action_list_for_redo = [] self.redo_button.setIcon( QIcon(self.current_dir + 'redo_gray_opacity.png')) def undo_draw(self): if len(self.draw_shape_action_list) > 0: self.draw_shape_action_list_for_redo.append( self.draw_shape_action_list[-1]) self.redo_button.setIcon(QIcon(self.current_dir + 'redo.png')) self.draw_shape_action_list.pop() if len(self.draw_shape_action_list) == 0: self.undo_button.setIcon( QIcon(self.current_dir + 'undo_gray_opacity.png')) def redo_draw(self): if len(self.draw_shape_action_list_for_redo) > 0: self.draw_shape_action_list.append( self.draw_shape_action_list_for_redo[-1]) self.undo_button.setIcon(QIcon(self.current_dir + 'undo.png')) self.draw_shape_action_list_for_redo.pop() if len(self.draw_shape_action_list_for_redo) == 0: self.redo_button.setIcon( QIcon(self.current_dir + 'redo_gray_opacity.png')) def clear_draw(self): self.draw_shape_initial() self.draw_shape_action_list.append(Clear_All()) def draw_shape_initial(self): self.line_button.setChecked(False) self.draw_shape_line = False self.drawing_shape_line = False self.eraser_button.setChecked(False) self.erase = False self.drawing_eraser = False def run_cut(self): if len(self.draw_shape_list) > 0: win32gui.SetForegroundWindow(self.scan_control_hwnd) #self.left, self.top, self.right, self.bottom = win32gui.GetWindowRect(self.frame_hwnd) #screenshot_temp = pyautogui.screenshot(region=[self.left,self.top,\ # self.right-self.left,\ # self.bottom-self.top]) #screenshot_temp = np.asarray(screenshot_temp) #self.crop_left, self.crop_top, self.crop_right, self.crop_bottom = find_region(screenshot_temp) a = pyautogui.locateCenterOnScreen('G:/1.png') for shape in self.draw_shape_list: pyautogui.moveTo(self.left + self.crop_left, self.top + self.crop_top) pyautogui.moveRel(list(shape.pos[0])[0], list(shape.pos[0])[1]) pyautogui.dragRel(list(shape.pos[1])[0] - list(shape.pos[0])[0], \ list(shape.pos[1])[1] - list(shape.pos[0])[1], duration=0.25) try: pyautogui.moveTo(a[0], a[1]) except: a = pyautogui.locateCenterOnScreen('G:/1.png') time.sleep(0.5) pyautogui.moveTo(a[0], a[1]) pyautogui.click() time.sleep(1) pyautogui.moveRel(300, 300) self.wait_cut() #time.sleep(15) def wait_cut(self): for i in range(30): a = pyautogui.locateCenterOnScreen('G:/1.png') if a == None: time.sleep(1) else: break def repeat_cut(self): print('repeat cut')
class MainWindow(QMainWindow): def __init__(self, gui): # noqa: max-complexity super().__init__() self.gui = gui self.gateways = [] self.welcome_dialog = None self.recovery_key_exporter = None self.setWindowTitle(APP_NAME) self.setMinimumSize(QSize(600, 400)) self.setUnifiedTitleAndToolBarOnMac(True) self.setContextMenuPolicy(Qt.NoContextMenu) if sys.platform == "darwin": # To disable the broken/buggy "full screen" mode on macOS. # See https://github.com/gridsync/gridsync/issues/241 self.setWindowFlags(Qt.Dialog) grid_invites_enabled = True invites_enabled = True multiple_grids_enabled = True features_settings = settings.get("features") if features_settings: grid_invites = features_settings.get("grid_invites") if grid_invites and grid_invites.lower() == "false": grid_invites_enabled = False invites = features_settings.get("invites") if invites and invites.lower() == "false": invites_enabled = False multiple_grids = features_settings.get("multiple_grids") if multiple_grids and multiple_grids.lower() == "false": multiple_grids_enabled = False if multiple_grids_enabled: self.shortcut_new = QShortcut(QKeySequence.New, self) self.shortcut_new.activated.connect(self.show_welcome_dialog) self.shortcut_open = QShortcut(QKeySequence.Open, self) self.shortcut_open.activated.connect(self.select_folder) self.shortcut_preferences = QShortcut(QKeySequence.Preferences, self) self.shortcut_preferences.activated.connect( self.gui.show_preferences_window) self.shortcut_close = QShortcut(QKeySequence.Close, self) self.shortcut_close.activated.connect(self.close) self.shortcut_quit = QShortcut(QKeySequence.Quit, self) self.shortcut_quit.activated.connect(self.confirm_quit) self.central_widget = CentralWidget(self.gui) self.setCentralWidget(self.central_widget) font = Font(8) folder_icon_default = QFileIconProvider().icon(QFileInfo(config_dir)) folder_icon_composite = CompositePixmap( folder_icon_default.pixmap(256, 256), resource("green-plus.png")) folder_icon = QIcon(folder_icon_composite) folder_action = QAction(folder_icon, "Add Folder", self) folder_action.setToolTip("Add a Folder...") folder_action.setFont(font) folder_action.triggered.connect(self.select_folder) if grid_invites_enabled: invites_action = QAction(QIcon(resource("invite.png")), "Invites", self) invites_action.setToolTip("Enter or Create an Invite Code") invites_action.setFont(font) enter_invite_action = QAction(QIcon(), "Enter Invite Code...", self) enter_invite_action.setToolTip("Enter an Invite Code...") enter_invite_action.triggered.connect(self.open_invite_receiver) create_invite_action = QAction(QIcon(), "Create Invite Code...", self) create_invite_action.setToolTip("Create on Invite Code...") create_invite_action.triggered.connect( self.open_invite_sender_dialog) invites_menu = QMenu(self) invites_menu.addAction(enter_invite_action) invites_menu.addAction(create_invite_action) invites_button = QToolButton(self) invites_button.setDefaultAction(invites_action) invites_button.setMenu(invites_menu) invites_button.setPopupMode(2) invites_button.setStyleSheet( "QToolButton::menu-indicator { image: none }") invites_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) elif invites_enabled: invite_action = QAction(QIcon(resource("invite.png")), "Enter Code", self) invite_action.setToolTip("Enter an Invite Code...") invite_action.setFont(font) invite_action.triggered.connect(self.open_invite_receiver) spacer_left = QWidget() spacer_left.setSizePolicy(QSizePolicy.Expanding, 0) self.combo_box = ComboBox() self.combo_box.currentIndexChanged.connect(self.on_grid_selected) if not multiple_grids_enabled: self.combo_box.hide() spacer_right = QWidget() spacer_right.setSizePolicy(QSizePolicy.Expanding, 0) history_action = QAction(QIcon(resource("time.png")), "History", self) history_action.setToolTip("Show/Hide History") history_action.setFont(font) history_action.triggered.connect(self.on_history_button_clicked) self.history_button = QToolButton(self) self.history_button.setDefaultAction(history_action) self.history_button.setCheckable(True) self.history_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) recovery_action = QAction(QIcon(resource("key.png")), "Recovery", self) recovery_action.setToolTip("Import or Export a Recovery Key") recovery_action.setFont(font) import_action = QAction(QIcon(), "Import Recovery Key...", self) import_action.setToolTip("Import Recovery Key...") import_action.triggered.connect(self.import_recovery_key) export_action = QAction(QIcon(), "Export Recovery Key...", self) export_action.setToolTip("Export Recovery Key...") export_action.setShortcut(QKeySequence.Save) export_action.triggered.connect(self.export_recovery_key) recovery_menu = QMenu(self) recovery_menu.addAction(import_action) recovery_menu.addAction(export_action) recovery_button = QToolButton(self) recovery_button.setDefaultAction(recovery_action) recovery_button.setMenu(recovery_menu) recovery_button.setPopupMode(2) recovery_button.setStyleSheet( "QToolButton::menu-indicator { image: none }") recovery_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.toolbar = self.addToolBar("") p = self.palette() dimmer_grey = BlendedColor(p.windowText().color(), p.window().color(), 0.7).name() if sys.platform != "darwin": self.toolbar.setStyleSheet(""" QToolBar {{ border: 0px }} QToolButton {{ color: {} }} """.format(dimmer_grey)) else: self.toolbar.setStyleSheet( "QToolButton {{ color: {} }}".format(dimmer_grey)) self.toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.toolbar.setIconSize(QSize(24, 24)) self.toolbar.setMovable(False) self.toolbar.addAction(folder_action) if grid_invites_enabled: self.toolbar.addWidget(invites_button) elif invites_enabled: self.toolbar.addAction(invite_action) self.toolbar.addWidget(spacer_left) self.toolbar.addWidget(self.combo_box) self.toolbar.addWidget(spacer_right) self.toolbar.addWidget(self.history_button) self.toolbar.addWidget(recovery_button) if sys.platform != "win32": # Text is getting clipped on Windows 10 for action in self.toolbar.actions(): widget = self.toolbar.widgetForAction(action) if isinstance(widget, QToolButton): widget.setMaximumWidth(68) self.active_invite_sender_dialogs = [] self.active_invite_receiver_dialogs = [] self.pending_news_message = () def populate(self, gateways): for gateway in gateways: if gateway not in self.gateways: self.central_widget.add_folders_view(gateway) self.central_widget.add_history_view(gateway) self.combo_box.add_gateway(gateway) self.gateways.append(gateway) gateway.newscap_checker.message_received.connect( self.on_message_received) gateway.newscap_checker.upgrade_required.connect( self.on_upgrade_required) def show_news_message(self, gateway, title, message): msgbox = QMessageBox(self) msgbox.setWindowModality(Qt.WindowModal) icon_filepath = os.path.join(gateway.nodedir, "icon") if os.path.exists(icon_filepath): msgbox.setIconPixmap(QIcon(icon_filepath).pixmap(64, 64)) elif os.path.exists(resource("tahoe-lafs.png")): msgbox.setIconPixmap( QIcon(resource("tahoe-lafs.png")).pixmap(64, 64)) else: msgbox.setIcon(QMessageBox.Information) if sys.platform == "darwin": msgbox.setText(title) msgbox.setInformativeText(message) else: msgbox.setWindowTitle(title) msgbox.setText(message) msgbox.show() try: self.gui.unread_messages.remove((gateway, title, message)) except ValueError: return self.gui.systray.update() def _maybe_show_news_message(self, gateway, title, message): self.gui.unread_messages.append((gateway, title, message)) self.gui.systray.update() if self.isVisible(): self.show_news_message(gateway, title, message) else: self.pending_news_message = (gateway, title, message) def on_message_received(self, gateway, message): title = "New message from {}".format(gateway.name) self.gui.show_message(title, strip_html_tags(message.replace("<p>", "\n\n"))) self._maybe_show_news_message(gateway, title, message) def on_upgrade_required(self, gateway): title = "Upgrade required" message = ( "A message was received from {} in an unsupported format. This " "suggests that you are running an out-of-date version of {}.\n\n" "To avoid seeing this warning, please upgrade to the latest " "version.".format(gateway.name, APP_NAME)) self._maybe_show_news_message(gateway, title, message) def current_view(self): try: w = self.central_widget.folders_views[self.combo_box.currentData()] except KeyError: return None return w.layout().itemAt(0).widget() def select_folder(self): self.show_folders_view() view = self.current_view() if view: view.select_folder() def set_current_grid_status(self): current_view = self.current_view() if not current_view: return self.gui.systray.update() def show_folders_view(self): try: self.central_widget.setCurrentWidget( self.central_widget.folders_views[ self.combo_box.currentData()]) except KeyError: pass self.set_current_grid_status() def show_history_view(self): try: self.central_widget.setCurrentWidget( self.central_widget.history_views[ self.combo_box.currentData()]) except KeyError: pass self.set_current_grid_status() def show_welcome_dialog(self): if self.welcome_dialog: self.welcome_dialog.close() self.welcome_dialog = WelcomeDialog(self.gui, self.gateways) self.welcome_dialog.show() self.welcome_dialog.raise_() def on_grid_selected(self, index): if index == self.combo_box.count() - 1: self.show_welcome_dialog() if not self.combo_box.currentData(): return if self.history_button.isChecked(): self.show_history_view() else: self.show_folders_view() self.setWindowTitle("{} - {}".format( APP_NAME, self.combo_box.currentData().name)) def confirm_export(self, path): if os.path.isfile(path): logging.info("Recovery Key successfully exported") info( self, "Export successful", "Recovery Key successfully exported to {}".format(path), ) else: logging.error("Error exporting Recovery Key; file not found.") error( self, "Error exporting Recovery Key", "Destination file not found after export: {}".format(path), ) def export_recovery_key(self, gateway=None): self.show_folders_view() if not gateway: gateway = self.combo_box.currentData() self.recovery_key_exporter = RecoveryKeyExporter(self) self.recovery_key_exporter.done.connect(self.confirm_export) self.recovery_key_exporter.do_export(gateway) def import_recovery_key(self): # XXX Quick hack for user-testing; change later self.welcome_dialog = WelcomeDialog(self.gui, self.gateways) self.welcome_dialog.on_restore_link_activated() def on_history_button_clicked(self): if not self.history_button.isChecked(): self.history_button.setChecked(True) self.show_history_view() else: self.history_button.setChecked(False) self.show_folders_view() def on_invite_received(self, gateway): self.populate([gateway]) for view in self.central_widget.views: view.model().monitor.scan_rootcap("star.png") def on_invite_closed(self, obj): try: self.active_invite_receiver_dialogs.remove(obj) except ValueError: pass def open_invite_receiver(self): invite_receiver_dialog = InviteReceiverDialog(self.gateways) invite_receiver_dialog.done.connect(self.on_invite_received) invite_receiver_dialog.closed.connect(self.on_invite_closed) invite_receiver_dialog.show() self.active_invite_receiver_dialogs.append(invite_receiver_dialog) def open_invite_sender_dialog(self): gateway = self.combo_box.currentData() if gateway: view = self.current_view() if view: invite_sender_dialog = InviteSenderDialog( gateway, self.gui, view.get_selected_folders()) else: invite_sender_dialog = InviteSenderDialog(gateway, self.gui) invite_sender_dialog.closed.connect( self.active_invite_sender_dialogs.remove) invite_sender_dialog.show() self.active_invite_sender_dialogs.append(invite_sender_dialog) def confirm_quit(self): folder_loading = False folder_syncing = False for model in [view.model() for view in self.central_widget.views]: for row in range(model.rowCount()): status = model.item(row, 1).data(Qt.UserRole) mtime = model.item(row, 2).data(Qt.UserRole) if not status and not mtime: # "Loading..." and not yet synced folder_loading = True break if status == 1: # "Syncing" folder_syncing = True break msg = QMessageBox(self) if folder_loading: msg.setIcon(QMessageBox.Warning) informative_text = ( "One or more folders have not finished loading. If these " "folders were recently added, you may need to add them again.") elif folder_syncing: msg.setIcon(QMessageBox.Warning) informative_text = ( "One or more folders are currently syncing. If you quit, any " "pending upload or download operations will be cancelled " "until you launch {} again.".format(APP_NAME)) else: msg.setIcon(QMessageBox.Question) informative_text = ( "If you quit, {} will stop synchronizing your folders until " "you launch it again.".format(APP_NAME)) if sys.platform == "darwin": msg.setText("Are you sure you wish to quit?") msg.setInformativeText(informative_text) else: msg.setWindowTitle("Exit {}?".format(APP_NAME)) msg.setText( "Are you sure you wish to quit? {}".format(informative_text)) msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msg.setDefaultButton(QMessageBox.No) if msg.exec_() == QMessageBox.Yes: if sys.platform == "win32": self.gui.systray.hide() reactor.stop() def keyPressEvent(self, event): key = event.key() if key in (Qt.Key_Backspace, Qt.Key_Delete): view = self.current_view() selected = view.selectedIndexes() if view else None if selected: view.confirm_stop_syncing(view.get_selected_folders()) if key == Qt.Key_Escape: view = self.current_view() selected = view.selectedIndexes() if view else None if selected: for index in selected: view.selectionModel().select(index, QItemSelectionModel.Deselect) elif self.gui.systray.isSystemTrayAvailable(): self.hide() def closeEvent(self, event): if self.gui.systray.isSystemTrayAvailable(): event.accept() else: event.ignore() self.confirm_quit() def showEvent(self, _): if self.pending_news_message: gateway, title, message = self.pending_news_message self.pending_news_message = () QTimer.singleShot( 0, lambda: self.show_news_message(gateway, title, message))
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): self.current_dir = os.path.abspath(__file__).replace('\\', '/') self.current_dir = get_folder_from_file(self.current_dir) self.current_dir += 'support_files/' #self.afp_dir, self.afp, self.bfp_dir, self.bfp = load_known() print(self.current_dir) self.get_hwnd() self.scan_speed = 1 self.total_range = 20 self.font = cv2.FONT_HERSHEY_SIMPLEX self.mouse_pos_initial() self.canvas_blank = np.zeros((512, 512), dtype=np.int8) exitAct = QAction(QIcon(self.current_dir + 'quit.png'), '&Quit', self) exitAct.setShortcut('Ctrl+Q') exitAct.triggered.connect(qApp.quit) help_contact = QAction(QIcon(self.current_dir + 'email.png'), 'Contact', self) help_contact.triggered.connect(self.contact) help_about = QAction('About', self) help_about.triggered.connect(self.about) self.menubar = self.menuBar() FileMenu = self.menubar.addMenu('&File') FileMenu.addAction(exitAct) HelpMenu = self.menubar.addMenu('&Help') HelpMenu.addAction(help_contact) HelpMenu.addAction(help_about) self.read_button = QToolButton() self.read_button.setIcon(QIcon(self.current_dir + 'read.png')) self.read_button.setToolTip('Read Ctrl+R') self.read_button.clicked.connect(self.read) self.read_button.setShortcut('Ctrl+R') self.select_button = QToolButton() self.select_button.setIcon(QIcon(self.current_dir + 'select.png')) self.select_button.setToolTip('Select') self.select_button.clicked.connect(self.select_move_shape) self.select_button.setCheckable(True) self.select = False self.selecting = False self.select_rec = Rectangle() self.cursor_on_select = False self.moving = False self.move_start = [0, 0] self.move_end = [0, 0] self.drag_button = QToolButton() self.drag_button.setIcon(QIcon(self.current_dir + 'drag.png')) self.drag_button.setToolTip('Move') self.drag_button.clicked.connect(self.drag_shape) self.draw_shape_action_list = [] self.draw_shape_list = [] self.draw_shape_action_list_for_redo = [] self.draw_shape_count = 1 self.line_button = QToolButton() self.line_button.setIcon(QIcon(self.current_dir + 'line.png')) self.line_button.setToolTip('Draw line') self.line_button.clicked.connect(self.draw_line) self.line_button.setCheckable(True) self.draw_shape_line = False self.drawing_shape_line = False self.show_distance = False self.grating_button = QToolButton() self.grating_button.setIcon(QIcon(self.current_dir + 'grating.png')) self.grating_button.setToolTip('Grating') self.grating_button.clicked.connect(self.draw_grating) # line = Line(0,0,100,100) self.eraser_button = QToolButton() self.eraser_button.setIcon(QIcon(self.current_dir + 'eraser.png')) self.eraser_button.setToolTip('eraser') self.eraser_button.clicked.connect(self.erase_shape) self.eraser_button.setCheckable(True) self.erase = False self.drawing_eraser = False self.undo_button = QToolButton() self.undo_button.setIcon( QIcon(self.current_dir + 'undo_gray_opacity.png')) self.undo_button.setToolTip('undo Ctrl+Z') self.undo_button.clicked.connect(self.undo_draw) self.undo_button.setShortcut('Ctrl+Z') self.redo_button = QToolButton() self.redo_button.setIcon( QIcon(self.current_dir + 'redo_gray_opacity.png')) self.redo_button.setToolTip('redo Ctrl+Y') self.redo_button.clicked.connect(self.redo_draw) self.redo_button.setShortcut('Ctrl+Y') self.clear_button = QToolButton() self.clear_button.setIcon(QIcon(self.current_dir + 'clear.png')) self.clear_button.setToolTip('clear drawing') self.clear_button.clicked.connect(self.clear_draw) self.run_button = QToolButton() self.run_button.setIcon(QIcon(self.current_dir + 'run.png')) self.run_button.setToolTip('Run F5') self.run_button.clicked.connect(self.run_cut) self.run_button.setShortcut('F5') self.repeat_button = QToolButton() self.repeat_button.setIcon(QIcon(self.current_dir + 'repeat.png')) self.repeat_button.setToolTip('Repeat') self.repeat_button.clicked.connect(self.repeat_cut) self.stop_button = QToolButton() self.stop_button.setIcon(QIcon(self.current_dir + 'stop.png')) self.stop_button.setToolTip('Stop') self.stop_button.clicked.connect(self.stop_cut) self.toolbar1 = self.addToolBar('Read') self.toolbar1.addWidget(self.read_button) self.toolbar2 = self.addToolBar('Select') self.toolbar2.addWidget(self.select_button) self.toolbar2.addWidget(self.drag_button) self.toolbar3 = self.addToolBar('Draw') self.toolbar3.addWidget(self.line_button) self.toolbar3.addWidget(self.grating_button) self.toolbar3.addWidget(self.undo_button) self.toolbar3.addWidget(self.redo_button) self.toolbar3.addWidget(self.eraser_button) self.toolbar3.addWidget(self.clear_button) self.toolbar4 = self.addToolBar('Run') self.toolbar4.addWidget(self.run_button) self.toolbar4.addWidget(self.repeat_button) self.toolbar4.addWidget(self.stop_button) self.toolbar = self.addToolBar(' ') self.pixmap = QPixmap() self.lbl_main = QLabel(self) self.lbl_main.setAlignment(Qt.AlignTop) # self.lbl_main.setAlignment(Qt.AlignCenter) self.lbl_main.setPixmap(self.pixmap) self.lbl_main.setMouseTracking(True) self.vbox = QVBoxLayout() self.vbox.addWidget(self.lbl_main) self.central_widget = QWidget() self.central_widget.setMouseTracking(True) self.layout = QVBoxLayout(self.central_widget) self.setCentralWidget(self.central_widget) self.layout.addLayout(self.vbox) self.refresh_timer = QTimer() self.refresh_timer.timeout.connect(self.refresh_show) self.setMouseTracking(True) self.setWindowTitle('Auto Cut') self.show() def read(self): window_name = 'Scanning control' self.scan_control_hwnd = win32gui.FindWindow(None, window_name) if self.scan_control_hwnd == 0: window_name = 'Scanning control ( Lift Mode )' self.scan_control_hwnd = win32gui.FindWindow(None, window_name) # win32gui.ShowWindow(scan_control_hwnd, win32con.SW_MAXIMIZE) try: win32gui.SendMessage(self.scan_control_hwnd, win32con.WM_SYSCOMMAND, win32con.SC_RESTORE, 0) win32gui.SetForegroundWindow(self.scan_control_hwnd) except: print('Can not set foreground window ') time.sleep(0.5) hwnd = self.scan_control_hwnd hwndChildList = [] win32gui.EnumChildWindows(hwnd, lambda hwnd, param: param.append(hwnd), hwndChildList) self.frame_hwnd = 0 probe_position_hwnd = 0 for hwnd_child in hwndChildList: name = win32gui.GetWindowText(hwnd_child) if 'Scan Area' in name: self.frame_hwnd = hwnd_child self.total_range = float(name[11:-3]) print(self.total_range) elif name == 'probe_position': probe_position_hwnd = hwnd_child hwnd = probe_position_hwnd hwndChildList = [] win32gui.EnumChildWindows(hwnd, lambda hwnd, param: param.append(hwnd), hwndChildList) self.move_time_hwnd = hwndChildList[0] self.new_x_hwnd = hwndChildList[3] self.new_y_hwnd = hwndChildList[2] self.move_time_Edit = EditWrapper(self.move_time_hwnd) self.x_Edit = EditWrapper(self.new_x_hwnd) self.y_Edit = EditWrapper(self.new_y_hwnd) # run_hwnd = hwndChildList[3] # self.frame_hwnd = hwndChildList[54] # self.frame_hwnd = self.scan_control_hwnd ''' self.left, self.top, self.right, self.bottom = win32gui.GetWindowRect(self.frame_hwnd) print(self.left, self.top, self.right, self.bottom) self.screenshot = pyautogui.screenshot(region=[self.left,self.top,\ self.right-self.left,\ self.bottom-self.top]) self.screenshot = np.asarray(self.screenshot) ''' self.screenshot = cv2.imread( 'F:/Desktop2020.1.17/AutoCut/screenshot2.bmp') self.screenshot = cv2.cvtColor(self.screenshot, cv2.COLOR_BGR2RGB) self.crop_left, self.crop_top, self.crop_right, self.crop_bottom = find_region( self.screenshot) self.screenshot = self.screenshot[self.crop_top: self.crop_bottom, \ self.crop_left: self.crop_right] # self.img = cv2.cvtColor(np.asarray(self.img),cv2.COLOR_RGB2BGR) #self.read_z_pos() self.start_refresh() print('Read') def contact(self): QMessageBox.information(self, 'contact','Please contact [email protected] '+\ 'for support. Thanks!') def about(self): QMessageBox.information(self, 'About', 'AFM Auto Cut v1.0. '+ \ 'Proudly designed and created by Jingxu Xie(谢京旭).\n \n' 'Copyright © 2020 Jingxu Xie. All Rights Reserved.') def draw_shape_initial(self): self.line_button.setChecked(False) self.draw_shape_line = False self.drawing_shape_line = False self.select_button.setChecked(False) self.select = False self.selecting = False self.select_rec = Rectangle() self.cursor_on_select = False self.moving = False self.eraser_button.setChecked(False) self.erase = False self.drawing_eraser = False def draw_line(self): if self.line_button.isChecked(): self.draw_shape_initial() self.draw_shape_line = True self.line_button.setChecked(True) else: self.draw_shape_line = False self.drawing_shape_line = False self.line_button.setChecked(False) print('draw line') def select_move_shape(self): if self.select_button.isChecked(): self.draw_shape_initial() self.select = True self.select_button.setChecked(True) else: self.draw_shape_line = False self.select = False self.select_button.setChecked(False) print('select') def drag_shape(self): print('drag') def draw_grating(self): self.grating_property_widget = GratingProperty() self.grating_property_widget.confirmed.connect(self.creat_grating) self.grating_property_widget.show() print('grating') def creat_grating(self, s): if s == 'confirmed': total_width = float(self.grating_property_widget.total_width) total_height = float(self.grating_property_widget.total_height) lines = int(self.grating_property_widget.lines) standard_distance = self.img.shape[0] / self.total_range x1 = int((self.total_range - total_width) / 2 * standard_distance) y1 = int((self.total_range - total_height) / 2 * standard_distance) x2 = x1 + int(total_width / self.total_range * self.img.shape[0]) y2 = y1 + int(total_height / self.total_range * self.img.shape[1]) grating_temp = Grating(x1, y1, x2, y2, total_width = total_width, \ total_height = total_height, \ standard_distance = standard_distance,\ lines = lines, color = (0,255,0),\ num = self.draw_shape_count) self.draw_shape_count += 1 self.draw_shape_action_list.append(grating_temp) print('confirmed') self.grating_property_widget.close() def erase_shape(self): if self.eraser_button.isChecked(): self.draw_shape_initial() self.erase = True self.eraser_button.setChecked(True) else: self.erase = False self.eraser_button.setChecked(False) def undo_redo_setting(self): self.undo_button.setIcon(QIcon(self.current_dir + 'undo.png')) self.draw_shape_action_list_for_redo = [] self.redo_button.setIcon( QIcon(self.current_dir + 'redo_gray_opacity.png')) def undo_draw(self): if len(self.draw_shape_action_list) > 0: self.draw_shape_action_list_for_redo.append( self.draw_shape_action_list[-1]) self.redo_button.setIcon(QIcon(self.current_dir + 'redo.png')) self.draw_shape_action_list.pop() if len(self.draw_shape_action_list) == 0: self.undo_button.setIcon( QIcon(self.current_dir + 'undo_gray_opacity.png')) def redo_draw(self): if len(self.draw_shape_action_list_for_redo) > 0: self.draw_shape_action_list.append( self.draw_shape_action_list_for_redo[-1]) self.undo_button.setIcon(QIcon(self.current_dir + 'undo.png')) self.draw_shape_action_list_for_redo.pop() if len(self.draw_shape_action_list_for_redo) == 0: self.redo_button.setIcon( QIcon(self.current_dir + 'redo_gray_opacity.png')) def clear_draw(self): self.draw_shape_initial() self.draw_shape_action_list.append(Clear_All()) def mouse_pos_initial(self): self.mouse_x1, self.mouse_y1 = 0, 0 self.mouse_x2, self.mouse_y2 = 0, 0 self.mouse_x1_raw, self.mouse_y1_raw = 0, 0 self.mouse_x2_raw, self.mouse_y2_raw = 0, 0 self.mouse_pos_right = True def mousePressEvent(self, event): self.mouse_x1_raw = max(0, event.pos().x()) self.mouse_y1_raw = max(0, event.pos().y()) self.mouse_x2_raw, self.mouse_y2_raw = self.mouse_x1_raw, self.mouse_y1_raw self.mouse_pos_correct() if event.buttons() == Qt.LeftButton and self.draw_shape_line: if self.check_mouse_valid(): self.draw_shape_action_list.append(Line(self.mouse_x1, self.mouse_y1, \ self.mouse_x2, self.mouse_y2, \ color = (0,255,0),\ num = self.draw_shape_count,\ show_distance = self.show_distance)) self.draw_shape_count += 1 self.drawing_shape_line = True self.undo_redo_setting() elif event.buttons() == Qt.LeftButton and self.erase: if self.check_mouse_valid(): self.draw_shape_action_list.append(Eraser(self.mouse_x1, \ self.mouse_y1, num = [0])) self.drawing_eraser = True elif event.buttons( ) == Qt.LeftButton and self.select and not self.cursor_on_select: if self.check_mouse_valid(): self.select_rec = Rectangle(self.mouse_x1, self.mouse_y1,\ self.mouse_x2, self.mouse_y2,\ num = -1, color = (0,0,0), width = 2) self.selecting = True elif event.buttons() == Qt.LeftButton and self.cursor_on_select: self.move_start = [self.mouse_x1, self.mouse_y1] self.moving = True print(self.mouse_x1, self.mouse_y1) #print(self.get_pos_on_screen(769, 769)) def mouseMoveEvent(self, event): self.mouse_x2_raw = max(0, event.pos().x()) self.mouse_y2_raw = max(0, event.pos().y()) self.mouse_pos_correct() if self.drawing_shape_line and len(self.draw_shape_action_list) > 0: if self.check_mouse_valid(): self.draw_shape_action_list[-1].x2 = self.mouse_x2 self.draw_shape_action_list[-1].y2 = self.mouse_y2 self.draw_shape_action_list[-1].pos_refresh() elif self.drawing_eraser and len(self.draw_shape_action_list) > 0: if self.check_mouse_valid(): self.draw_shape_action_list[-1].x1 = self.mouse_x2 self.draw_shape_action_list[-1].y1 = self.mouse_y2 self.draw_shape_action_list[-1].pos_refresh() elif self.selecting: if self.check_mouse_valid(): self.select_rec.x2 = self.mouse_x2 self.select_rec.y2 = self.mouse_y2 self.select_rec.pos_refresh() elif self.select and not self.moving: x_temp, y_temp = Pos_in_Circle(self.mouse_x2, self.mouse_y2, 20) self.cursor_on_select = False for i in range(len(x_temp)): if x_temp[i] < self.canvas_blank.shape[1] and y_temp[ i] < self.canvas_blank.shape[0]: num = self.canvas_blank[y_temp[i], x_temp[i]] if num == -1: self.setCursor(Qt.SizeAllCursor) self.cursor_on_select = True break if not self.cursor_on_select: self.setCursor(Qt.ArrowCursor) if self.moving: self.move_end = [self.mouse_x2, self.mouse_y2] move_x = self.move_end[0] - self.move_start[0] move_y = self.move_end[1] - self.move_start[1] self.select_rec.x1 += move_x self.select_rec.x2 += move_x self.select_rec.y1 += move_y self.select_rec.y2 += move_y self.select_rec.pos_refresh() self.move_start = [self.mouse_x2, self.mouse_y2] def mouseReleaseEvent(self, event): # if self.mouse_x1_raw == self.mouse_x2_raw and self.mouse_y1_raw == self.mouse_y2_raw: # if self.drawing_shape_line: # self.draw_shape_action_list.pop() if event.button() == Qt.RightButton and self.drawing_shape_line: self.drawing_shape_line = False if len(self.draw_shape_action_list) > 0: self.draw_shape_action_list.pop() if event.button() == Qt.LeftButton and self.drawing_eraser: self.drawing_eraser = False if len(self.draw_shape_action_list[-1].num) == 1: self.draw_shape_action_list.pop() if event.button() == Qt.LeftButton and self.selecting: self.selecting = False elif event.button() == Qt.LeftButton and self.moving: self.moving = False def mouse_pos_correct(self): lbl_main_x = self.lbl_main.pos().x() lbl_main_y = self.lbl_main.pos().y() + self.menubar.height( ) + self.toolbar.height() self.mouse_x1 = self.mouse_x1_raw - lbl_main_x self.mouse_x2 = self.mouse_x2_raw - lbl_main_x self.mouse_y1 = self.mouse_y1_raw - lbl_main_y self.mouse_y2 = self.mouse_y2_raw - lbl_main_y def check_mouse_valid(self): if 1 <= self.mouse_x2 < self.img.shape[1] - 1 and \ 1 <= self.mouse_x2 < self.img.shape[1] - 1 and \ 1 <= self.mouse_y2 < self.img.shape[0] - 1 and \ 1 <= self.mouse_y2 < self.img.shape[0] - 1: return True else: return False def refresh_show(self): self.img = self.screenshot.copy() #self.canvas_blank = np.zeros((self.img.shape[0], self.img.shape[1]), dtype = int) if self.drawing_eraser: eraser_temp = self.draw_shape_action_list[-1] cv2.circle(self.img, *eraser_temp.pos, eraser_temp.size, \ eraser_temp.color, eraser_temp.width) cv2.circle(self.img, *eraser_temp.pos, eraser_temp.size, \ (0,0,0), 1) self.find_eraser_num() if len(self.draw_shape_action_list) > 0: self.generate_draw_shape_list() self.draw_shape_canvas() if self.select: cv2.rectangle(self.img, *self.select_rec.pos,\ self.select_rec.color, self.select_rec.width) x_temp, y_temp = Pos_of_Rec(*list(self.select_rec.pos[0]), \ *list(self.select_rec.pos[1])) self.canvas_blank = record_draw_shape(self.canvas_blank, \ np.array(x_temp), np.array(y_temp), \ self.select_rec.num) if not self.selecting: pass # x_temp, y_temp = Pos_in_Circle(self.mouse_x2, self.mouse_y2, 10) # on_rec = False # for i in range(len(x_temp)): # if x_temp[i] < self.canvas_blank.shape[1] and y_temp[i] < self.canvas_blank.shape[0]: # num = self.canvas_blank[y_temp[i], x_temp[i]] # if num == -1: # self.setCursor(Qt.SizeAllCursor) # on_rec = True # break # if not on_rec: # self.setCursor(Qt.ArrowCursor) self.show_on_screen() def generate_draw_shape_list(self): self.draw_shape_list = [] for action in self.draw_shape_action_list: if action.prop != 'eraser' and action.prop != 'clear': self.draw_shape_list.append(action) elif action.prop == 'eraser': i = 0 while i < len(self.draw_shape_list): if self.draw_shape_list[i].num in action.num: #print(action.num) self.draw_shape_list.pop(i) i -= 1 i += 1 if i == len(self.draw_shape_list): break elif action.prop == 'clear': self.draw_shape_list = [] def draw_shape_canvas(self): #目前canvas还没什么用,均可用img_show代替,但也可以先留着 self.canvas = np.zeros(self.img.shape, dtype=np.uint8) self.canvas_blank = np.zeros((self.img.shape[0], self.img.shape[1]), dtype=int) count = 1 if len(self.draw_shape_list) == 0: pass for shape in self.draw_shape_list: # shape.x1, shape.y1 = self.mouse_pos_ratio_change_line(shape.x1, shape.y1) # shape.x2, shape.y2 = self.mouse_pos_ratio_change_line(shape.x2, shape.y2) # shape.pos_refresh() if shape.prop == 'line' or shape.prop == 'base line': x_temp, y_temp = Pos_of_Line(*list(shape.pos[0]), *list(shape.pos[1])) self.canvas_blank = record_draw_shape(self.canvas_blank, \ np.array(x_temp), np.array(y_temp), \ shape.num) cv2.circle(self.img, shape.pos[0], 5, shape.color, 1) cv2.line(self.img, *shape.pos, shape.color, shape.width) cv2.putText(self.img, str(count), shape.pos[1], self.font, 0.7, \ shape.color, 1, cv2.LINE_AA) #print(self.get_distance(shape.pos[0][0], shape.pos[0][1],\ # shape.pos[1][0], shape.pos[1][1])) count += 1 if shape.show_distance: distance = self.calculate_distance(shape.x1, shape.y1, shape.x2, shape.y2) pos = (round((shape.x1 + shape.x2) / 2), round((shape.y1 + shape.y2) / 2)) cv2.putText(self.img, str(round(distance, 2)), pos, \ self.font, 0.7, (255,0,0), 1, cv2.LINE_AA) elif shape.prop == 'grating': cv2.putText(self.img, str(count), (shape.x2, shape.y2), self.font, 0.7, \ shape.color, 1, cv2.LINE_AA) count += 1 for grating in shape.grating_list: x_temp, y_temp = Pos_of_Line(*list(grating.pos[0]), *list(grating.pos[1])) self.canvas_blank = record_draw_shape(self.canvas_blank, \ np.array(x_temp), np.array(y_temp), \ shape.num) cv2.circle(self.img, grating.pos[0], 5, grating.color, 1) cv2.line(self.img, *grating.pos, grating.color, grating.width) def find_eraser_num(self): x_temp, y_temp = Pos_in_Circle(*list(self.draw_shape_action_list[-1].pos[0]), \ self.draw_shape_action_list[-1].size) for i in range(len(x_temp)): if x_temp[i] < self.canvas_blank.shape[1] and y_temp[ i] < self.canvas_blank.shape[0]: num = self.canvas_blank[y_temp[i], x_temp[i]] if num != 0: self.draw_shape_action_list[-1].num.append(num) break def start_refresh(self): self.refresh_timer.start(30) def show_on_screen(self): self.img_qi = QImage(self.img[:], self.img.shape[1], self.img.shape[0],\ self.img.shape[1] * 3, QImage.Format_RGB888) self.pixmap = QPixmap(self.img_qi) self.lbl_main.setPixmap(self.pixmap) def stop_cut(self): print('stop') def run_cut(self): draw_list_length = len(self.draw_shape_list) i = 0 while i < draw_list_length: shape = self.draw_shape_list[i] if shape.prop == 'grating': for grating in shape: shape_list = [shape] self.cutting(shape_list) else: shape_list = [shape] # shape_points = self.get_read_list(shape.pos[0][0], shape.pos[0][1],\ # shape.pos[1][0], shape.pos[1][1]) for j in range(i, draw_list_length - 1): shape_current = self.draw_shape_list[j] shape_next = self.draw_shape_list[j + 1] if shape_current.pos[1][0] == shape_next.pos[0][0] and \ shape_current.pos[1][1] == shape_next.pos[0][1]: # shape_points += self.get_read_list(shape_next.pos[0][0], shape_next.pos[0][1],\ # shape_next.pos[1][0], shape_next.pos[1][1]) shape_list.append(shape_next) i = j + 1 else: break #z_pos_read = self.read_z_on_line(shape_points) self.cutting(shape_list) #, z_pos_read) i += 1 # z_pos_read = self.read_z_on_line(shape.pos[0][0], shape.pos[0][1],\ # shape.pos[1][0], shape.pos[1][1]) # # self.cutting(shape.pos[0][0], shape.pos[0][1],\ # shape.pos[1][0], shape.pos[1][1],\ # z_pos_read) def get_hwnd(self): window_name = 'NanoDrive Innova Tapping' innova_hwnd = win32gui.FindWindow(None, window_name) hwnd = innova_hwnd hwndChildList = [] win32gui.EnumChildWindows(hwnd, lambda hwnd, param: param.append(hwnd), hwndChildList) z_position_hwnd = 0 z_offset_hwnd = 0 for hwnd_child in hwndChildList: name = win32gui.GetWindowText(hwnd_child) if name == 'z_position': z_position_hwnd = hwnd_child elif name == 'z_offset': z_offset_hwnd = hwnd_child hwnd = z_position_hwnd hwndChildList = [] win32gui.EnumChildWindows(hwnd, lambda hwnd, param: param.append(hwnd), hwndChildList) self.z_position_hwnd = hwndChildList[3] hwnd = z_offset_hwnd hwndChildList = [] win32gui.EnumChildWindows(hwnd, lambda hwnd, param: param.append(hwnd), hwndChildList) self.z_offset_button_hwnd = hwndChildList[0] self.z_offset_text_hwnd = hwndChildList[2] self.z_offset_Button = ButtonWrapper(self.z_offset_button_hwnd) self.z_Edit = EditWrapper(self.z_offset_text_hwnd) def drag_prob(self, x, y): self.x_Edit.set_text(str(x)) self.y_Edit.set_text(str(y)) win32api.SendMessage(self.new_y_hwnd, win32con.WM_CHAR, 13, 0) def read_z_pos(self): left, top, right, bottom = win32gui.GetWindowRect(self.z_position_hwnd) for i in range(5): screenshot = pyautogui.screenshot(region=[left+1,top+1,\ right-left-2,\ bottom-top-2]) screenshot = np.asarray(screenshot) ret, num = identify_num(screenshot, self.afp_dir, self.afp, self.bfp_dir, self.bfp) if ret: return True, num return False, num def set_offset(self, offset_number): self.z_Edit.set_text(str(round(offset_number, 4))) win32api.SendMessage(self.z_offset_text_hwnd, win32con.WM_CHAR, 13, 0) def cutting(self, shape_list, z_pos_read=[]): self.move_time_Edit.set_text(str(0.5)) win32api.SendMessage(self.move_time_hwnd, win32con.WM_CHAR, 13, 0) time.sleep(0.2) pos_x, pos_y = self.get_pos_on_screen(shape_list[0].pos[0][0], \ shape_list[0].pos[0][1]) self.drag_prob(pos_x, pos_y) time.sleep(0.6) for i in range(10): try: self.z_offset_Button.click() break except: time.sleep(0.1) time.sleep(0.5) text = 0 for i in range(26): text += 0.01 self.set_offset(text) time.sleep(0.2) # points = self.get_read_list(x1, y1, x2, y2) for shape in shape_list: distance = self.get_distance(shape.pos[0][0], shape.pos[0][1],\ shape.pos[1][0], shape.pos[1][1]) time_cut = self.scan_speed * distance #time_interval = time_cut/len(z_pos_read) time_cut = round(time_cut, 3) self.move_time_Edit.set_text(str(time_cut)) win32api.SendMessage(self.move_time_hwnd, win32con.WM_CHAR, 13, 0) #time.sleep(0.1) pos_x, pos_y = self.get_pos_on_screen(shape.pos[1][0], shape.pos[1][1]) self.drag_prob(pos_x, pos_y) #time.sleep(0.1) #self.z_offset_Button.click() #time.sleep(0.2) #time.sleep(time_cut-2) ''' for i in range(1, len(z_pos_read) + 1): if i < len(z_pos_read): diff = (int(z_pos_read[-i + -1]) - int(z_pos_read[-i]))/10000 else: diff = 0 text += diff print(text) self.set_offset(text) time.sleep(round(time_interval - 0.05, 6)) ''' ''' for i in range(1,len(points)+1): pos_x, pos_y = self.get_pos_on_screen(points[-i][0], points[-i][1]) self.drag_prob(pos_x, pos_y) time.sleep(0.4) if i < len(points): # if z_pos_read[i + 1] > z_pos_read[i]: diff = (int(z_pos_read[-i + -1]) - int(z_pos_read[-i]))/10000 else: diff = 0 text += diff print(text) #self.set_offset(text) #time.sleep(0.2) ''' for i in range(10): try: self.z_offset_Button.click() break except: time.sleep(0.1) time.sleep(0.2) self.move_time_Edit.set_text(str(0.5)) win32api.SendMessage(self.move_time_hwnd, win32con.WM_CHAR, 13, 0) time.sleep(0.5) def read_z_on_line(self, points): # points = self.get_read_list(x1, y1, x2, y2) z_pos_read = [] for point in points: pos_x, pos_y = self.get_pos_on_screen(point[0], point[1]) self.drag_prob(pos_x, pos_y) time.sleep(0.6) ret, z_temp = self.read_z_pos() print(z_temp) if ret: z_pos_read.append(z_temp) else: if len(z_pos_read) > 0: z_pos_read.append(z_pos_read[-1]) for i in range(len(points) - len(z_pos_read)): z_pos_read.append(z_pos_read[-1]) return z_pos_read def get_distance(self, x1, y1, x2, y2): total_pixel = self.img.shape[0] total_distance = self.total_range pixel = np.sqrt((x2 - x1)**2 + (y2 - y1)**2) distance = pixel / total_pixel * total_distance distance = round(distance, 2) return distance def get_pos_on_screen(self, x, y): x -= int((self.img.shape[1] / 2)) x_pos = self.get_distance(0, 0, x, 0) x_pos = round(x_pos, 4) if x < 0: x_pos = -x_pos y = -y y += int((self.img.shape[0]) / 2) y_pos = self.get_distance(0, 0, 0, y) y_pos = round(y_pos, 4) if y < 0: y_pos = -y_pos return x_pos, y_pos def get_read_list(self, x1, y1, x2, y2): x_temp, y_temp = Pos_of_Line(x1, y1, x2, y2) points = [[x1, y1]] x_start, y_start = x1, y1 for i in range(len(x_temp)): if self.get_distance(x_temp[i], y_temp[i], x_start, y_start) > 2: points.append([x_temp[i], y_temp[i]]) x_start, y_start = x_temp[i], y_temp[i] if points[-1][0] != x2 or points[-1][1] != y2: points.append([x2, y2]) return points def wait_cut(self): pass def repeat_cut(self): print('repeat cut')
class ImageViewerTab(GalacteekTab): def __init__(self, mainW): super().__init__(mainW) self.pinButton = QToolButton(self) self.pinButton.setIcon(getIcon('pin.png')) self.pinButton.setEnabled(True) self.zoomIn = QToolButton(self) self.zoomIn.setIcon(getIcon('zoom-in.png')) self.zoomIn.setShortcut(QKeySequence('Ctrl++')) self.zoomIn.setToolTip(iZoomIn()) self.zoomOut = QToolButton(self) self.zoomOut.setIcon(getIcon('zoom-out.png')) self.zoomOut.setShortcut(QKeySequence('Ctrl+-')) self.zoomOut.setToolTip(iZoomOut()) self.fitWindow = QToolButton(self) self.fitWindow.setCheckable(True) self.fitWindow.setToolTip('Fit to window') self.fitWindow.setIcon(getIcon('expand.png')) self.pathLabel = IPFSUrlLabel(None) self.pathClipB = IPFSPathClipboardButton(None) layout = QHBoxLayout() layout.addWidget(self.pathLabel, 0, Qt.AlignLeft) layout.addWidget(self.pathClipB, 0, Qt.AlignLeft) layout.addItem( QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)) layout.addWidget(self.pinButton, 0, Qt.AlignLeft) layout.addItem( QSpacerItem(10, 10, QSizePolicy.Minimum, QSizePolicy.Minimum)) layout.addWidget(self.zoomOut, 0, Qt.AlignLeft) layout.addWidget(self.zoomIn, 0, Qt.AlignLeft) layout.addWidget(self.fitWindow, 0, Qt.AlignLeft) self.vLayout.addLayout(layout) self.view = ImageView(self) self.view.imageLoaded.connect(self.onImageLoaded) self.view.qrCodesPresent.connect(self.onQrCodesListed) self.vLayout.addWidget(self.view) self.zoomIn.clicked.connect(self.view.zoomInClicked) self.zoomOut.clicked.connect(self.view.zoomOutClicked) self.fitWindow.clicked.connect( lambda: self.view.fitWindow(self.fitWindow.isChecked())) self.pinButton.clicked.connect(self.view.pinImage) def onImageLoaded(self, path, mimeType): self.pinButton.setEnabled(True) self.pathLabel.path = path self.pathClipB.path = path def onQrCodesListed(self, urls): # Create the scroll area and fix maximum height # TODO: set maximum size on resize as well scrollArea = QScrollArea() scrollArea.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) scrollArea.setWidgetResizable(True) scrollArea.setMaximumHeight(self.height() / 3) frame = QFrame(scrollArea) frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) layout = QVBoxLayout() layout.setSizeConstraint(QLayout.SetMinAndMaxSize) scrollArea.setWidget(frame) iconOpen = getIcon('open.png') lbl = QLabel() lbl.setText(iImageGotQrCodes(len(urls))) lbl.setObjectName('qrCodeCountLabel') lbl.setStyleSheet('QLabel { font-size: 14pt; text-align: center; }') layout.addWidget(lbl) layout.addItem( QSpacerItem(10, 10, QSizePolicy.Minimum, QSizePolicy.Minimum)) def onOpenItem(url): ensure(self.app.resourceOpener.open(url)) for url in urls: hLayout = QHBoxLayout() hLayout.setSizeConstraint(QLayout.SetMinAndMaxSize) urlString = str(url) if len(urlString) > 92: urlText = urlString[0:92] + '...' else: urlText = urlString lbl = QLabel() lbl.setText('<b>{}</b>'.format(urlText)) lbl.setToolTip(urlString) lbl.setStyleSheet('QLabel { font-size: 12pt }') clipBtn = QToolButton(self) clipBtn.setIcon(getIcon('clipboard.png')) clipBtn.setToolTip(iCopyToClipboard()) clipBtn.clicked.connect( functools.partial(self.app.setClipboardText, str(url))) openBtn = QToolButton(self) openBtn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) openBtn.setIcon(iconOpen) openBtn.setText(iOpen()) openBtn.clicked.connect(functools.partial(onOpenItem, url)) hLayout.addWidget(lbl) hLayout.addWidget(openBtn) hLayout.addWidget(clipBtn) layout.addLayout(hLayout) frame.setLayout(layout) self.vLayout.addWidget(scrollArea)
class CollapsibleWidget(QWidget): """ This widget defines a customized widget to hold information and can collapse on click. """ def __init__(self, title: str = ""): super().__init__() logging.debug("Creating CollapsibleWidget - %s", title) self.title = title layout_main = QVBoxLayout(self) layout_main.setContentsMargins(0, 0, 0, 0) layout_main.setSpacing(0) self.btn_toggle = QToolButton() self.btn_toggle.setStyleSheet("QToolButton { padding-left: 5px; }") self.btn_toggle.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) self.btn_toggle.setText(title) self.btn_toggle.setCheckable(True) self.btn_toggle.setChecked(False) self.btn_toggle.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.btn_toggle.setArrowType(Qt.RightArrow) self.btn_toggle.setIconSize(QSize(8, 8)) self.btn_toggle.pressed.connect(self.toggle) self.content = QWidget() self.content.hide() self.layout_content = QVBoxLayout(self.content) self.layout_content.setContentsMargins(13, 2, 13, 5) self.layout_content.setSpacing(2) layout_main.addWidget(self.btn_toggle) layout_main.addWidget(self.content) def toggle(self): """ this changes whether or not the QWidget is collapsed or not. :return: Returns nothing. """ logging.info("Toggling - %s", self.title) checked = self.btn_toggle.isChecked() self.btn_toggle.setArrowType(Qt.RightArrow if checked else Qt.DownArrow) self.content.setVisible(not checked) def collapse(self): """ this collapses the widget. :return: Returns nothing. """ logging.info("Collapsing - %s", self.title) self.btn_toggle.setChecked(True) self.toggle() def expand(self): """ this expands the widget. :return: Returns nothing. """ logging.info("Expanding - %s", self.title) self.btn_toggle.setChecked(False) self.toggle() def addElement(self, widget: QWidget): """ this adds a QWidget to the collapsible widget :param widget: Widget to add """ self.layout_content.addWidget(widget) def deleteElement(self, widget: QWidget): """ Removes an element from the layout :param widget: Widget to remove """ widget.setParent(None) self.layout_content.removeWidget(widget)
class CollapsibleBox(QWidget): def __init__(self, title="", parent=None): super(CollapsibleBox, self).__init__(parent) self.toggle_button = QToolButton(text=title, checkable=True, checked=False) self.toggle_button.setStyleSheet("QToolButton { border: none; }") self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.toggle_button.setArrowType(Qt.RightArrow) self.toggle_button.pressed.connect(self.on_pressed) self.toggle_animation = QParallelAnimationGroup(self) self.content_area = QScrollArea(maximumHeight=0, minimumHeight=0) self.content_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.content_area.setFrameShape(QFrame.NoFrame) self.content_area.setVisible(False) self.lay = QVBoxLayout(self) self.lay.setSpacing(0) self.lay.setContentsMargins(0, 0, 0, 0) self.lay.addWidget(self.toggle_button) self.lay.addWidget(self.content_area) self.toggle_animation.addAnimation( QPropertyAnimation(self, b"minimumHeight")) self.toggle_animation.addAnimation( QPropertyAnimation(self, b"maximumHeight")) self.toggle_animation.addAnimation( QPropertyAnimation(self.content_area, b"maximumHeight")) @pyqtSlot() def on_pressed(self): checked = self.toggle_button.isChecked() self.content_area.setVisible(not checked) self.toggle_button.setArrowType( Qt.DownArrow if not checked else Qt.RightArrow) self.toggle_animation.setDirection( QAbstractAnimation.Forward if not checked else QAbstractAnimation. Backward) self.toggle_animation.start() self.toggle_button.setChecked(not checked) def setContentLayout(self, layout): lay = self.content_area.layout() del lay self.content_area.setLayout(layout) self.content_area.setStyleSheet("background-color:transparent;") collapsed_height = (self.sizeHint().height() - self.content_area.maximumHeight()) content_height = layout.sizeHint().height() for i in range(self.toggle_animation.animationCount()): animation = self.toggle_animation.animationAt(i) animation.setDuration(500) animation.setStartValue(collapsed_height) animation.setEndValue(collapsed_height + content_height) content_animation = self.toggle_animation.animationAt( self.toggle_animation.animationCount() - 1) content_animation.setDuration(500) content_animation.setStartValue(0) content_animation.setEndValue(content_height)