class GalleryDownloaderUrlExtracter(QWidget): url_emit = pyqtSignal(str) def __init__(self, parent=None): super().__init__(parent, flags=Qt.Window|Qt.WindowStaysOnTopHint) self.main_layout = QVBoxLayout(self) self.text_area = QPlainTextEdit(self) self.text_area.setPlaceholderText("URLs are seperated by a newline") self.main_layout.addWidget(self.text_area) self.text_area.setWordWrapMode(QTextOption.NoWrap) add_to_queue = QPushButton('Add to queue') add_to_queue.adjustSize() add_to_queue.setFixedWidth(add_to_queue.width()) add_to_queue.clicked.connect(self.add_to_queue) self.main_layout.addWidget(add_to_queue, 0, Qt.AlignRight) self.setWindowIcon(QIcon(app_constants.APP_ICO_PATH)) self.show() def add_to_queue(self): txt = self.text_area.document().toPlainText() urls = txt.split('\n') for u in urls: if u: self.url_emit.emit(u) self.close()
def __init__(self, Wizard, parent=None): super(RequiresPage, self).__init__(parent) self.base = Wizard.base self.setTitle(self.tr("Requires page")) self.setSubTitle(self.tr("Write requires and provides")) buildRequiresLabel = QLabel("BuildRequires: ") self.bRequiresEdit = QPlainTextEdit() self.bRequiresEdit.setMaximumHeight(40) requiresLabel = QLabel("Requires: ") self.requiresEdit = QPlainTextEdit() self.requiresEdit.setMaximumHeight(40) preovidesLabel = QLabel("Provides: ") self.previdesEdit = QPlainTextEdit() grid = QGridLayout() grid.addWidget(buildRequiresLabel, 0, 0) grid.addWidget(self.bRequiresEdit, 1, 0) grid.addWidget(requiresLabel, 2, 0) grid.addWidget(self.requiresEdit, 3, 0,) grid.addWidget(preovidesLabel, 4, 0) grid.addWidget(self.previdesEdit, 5, 0) self.setLayout(grid)
def __init__(self, Wizard, parent=None): super(ScriptsPage, self).__init__(parent) self.base = Wizard.base self.setTitle(self.tr("Scripts page")) self.setSubTitle(self.tr("Write scripts")) prepareLabel = QLabel("%prepare: ") self.prepareEdit = QPlainTextEdit() buildLabel = QLabel("%build: ") self.buildEdit = QPlainTextEdit() installLabel = QLabel("%install: ") self.installEdit = QPlainTextEdit() checkLabel = QLabel("%check: ") self.checkEdit = QPlainTextEdit() buildArchLabel = QLabel("BuildArch: ") self.buildArchCheckbox = QCheckBox("noarch") grid = QGridLayout() grid.addWidget(prepareLabel, 0, 0) grid.addWidget(self.prepareEdit, 0, 1) grid.addWidget(buildLabel, 1, 0) grid.addWidget(self.buildEdit, 1, 1) grid.addWidget(installLabel, 2, 0) grid.addWidget(self.installEdit, 2, 1) grid.addWidget(checkLabel, 3, 0) grid.addWidget(self.checkEdit, 3, 1) grid.addWidget(buildArchLabel, 4, 0) grid.addWidget(self.buildArchCheckbox, 4, 1) self.setLayout(grid)
def show_info_dialog( caption, parent, initial_text ): dialog = QDialog( parent ) dialog.setWindowTitle( caption ) # Create OK and Cancel buttons in a horizontal box. ok_button = QPushButton("OK") ok_button.setDefault(True) ok_button.clicked.connect(dialog.accept) cancel_button = QPushButton("Cancel") cancel_button.setDefault(False) cancel_button.clicked.connect(dialog.reject) hbox = QHBoxLayout() hbox.addWidget(cancel_button,0) hbox.addStretch() hbox.addWidget(ok_button,0) # Lay out a Plain Text Edit above the buttons. vbox = QVBoxLayout() pt_editor = QPlainTextEdit() pt_editor.document().setPlainText( initial_text ) vbox.addWidget(pt_editor,1) vbox.addLayout(hbox,0) dialog.setLayout(vbox) result = dialog.exec_() if result : return pt_editor.document().toPlainText() else : return None
def keyPressEvent(self, e): if self.isReadOnly(): return if self.is_special_key(e): e.ignore() return QPlainTextEdit.keyPressEvent(self, e) ctrlOrShift = e.modifiers() and (Qt.ControlModifier or Qt.ShiftModifier) if self.completer is None or (ctrlOrShift and not e.text()): return if not self.suggestions_enabled: return eow = "~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-=" hasModifier = (e.modifiers() != Qt.NoModifier) and not ctrlOrShift completionPrefix = self.text_under_cursor() if hasModifier or not e.text() or len(completionPrefix) < 1 or eow.find(e.text()[-1]) >= 0: self.completer.popup().hide() return if completionPrefix != self.completer.completionPrefix(): self.completer.setCompletionPrefix(completionPrefix) self.completer.popup().setCurrentIndex(self.completer.completionModel().index(0, 0)) cr = self.cursorRect() cr.setWidth(self.completer.popup().sizeHintForColumn(0) + self.completer.popup().verticalScrollBar().sizeHint().width()) self.completer.complete(cr)
def __init__(self, parent=None, text=None, EditorHighlighterClass=PythonHighlighter, indenter=PythonCodeIndenter): QPlainTextEdit.__init__(self, parent) self.setFrameStyle(QFrame.NoFrame) self.setTabStopWidth(4) self.setLineWrapMode(QPlainTextEdit.NoWrap) font = QFont() font.setFamily("lucidasanstypewriter") font.setFixedPitch(True) font.setPointSize(10) self.setFont(font) self.highlighter = EditorHighlighterClass(self) if text: self.setPlainText(text) self.frame_style = self.frameStyle() self.draw_line = True self.print_width = self.fontMetrics().width("x" * 78) self.line_pen = QPen(QColor("lightgrey")) self.last_row = self.last_col = -1 self.last_block = None self.highlight_line = True self.highlight_color = self.palette().highlight().color().light(175) self.highlight_brush = QBrush(QColor(self.highlight_color)) self.cursorPositionChanged.connect(self.onCursorPositionChanged) self.indenter = indenter(RopeEditorWrapper(self)) # True if you want to catch Emacs keys in actions self.disable_shortcuts = False self.prj = get_no_project() self.prj.root = None self.calltip = CallTip(self) self.autocomplete = AutoComplete(self)
class PackageTab(QWidget): configChanged = pyqtSignal() def __init__(self): super(QWidget, self).__init__() layout = QFormLayout() self.setLayout(layout) self.buildDependencies = QPlainTextEdit() self.buildDependencies.textChanged.connect(self.buildDependenciesChanged) self.buildDependencies.setMinimumHeight(70) layout.addRow('Build Dependencies', self.buildDependencies) self.runDependencies = QPlainTextEdit() self.runDependencies.textChanged.connect(self.runDependenciesChanged) self.runDependencies.setMinimumHeight(70) layout.addRow('Run Dependencies', self.runDependencies) def buildDependenciesChanged(self): if self.config is not None: self.config.setBuildDependencies(self.buildDependencies.toPlainText()) self.configChanged.emit() def runDependenciesChanged(self): if self.config is not None: self.config.setRunDependencies(self.runDependencies.toPlainText()) self.configChanged.emit() def setConfig(self, config): self.config = config self.buildDependencies.setPlainText(self.config.getBuildDependenciesAsText()) self.runDependencies.setPlainText(self.config.getRunDependenciesAsText())
class Window(QWidget): def __init__(self): super().__init__() # Make widgets ################# self.edit = QPlainTextEdit() self.btn = QPushButton("Print") self.edit.setPlaceholderText("Type something here and press the 'Print' button") # Set button slot ############## self.btn.clicked.connect(self.printText) # Set the layout ############### vbox = QVBoxLayout() vbox.addWidget(self.edit) vbox.addWidget(self.btn) self.setLayout(vbox) def printText(self): print(self.edit.toPlainText())
def previewWidget(self): t = QTabWidget() t.setDocumentMode(True) t.setStyleSheet(""" QTabBar::tab{ background-color: #BBB; padding: 3px 25px; border: none; } QTabBar::tab:selected, QTabBar::tab:hover{ background-color:skyblue; } """) w0 = QPlainTextEdit() w0.setFrameShape(QFrame.NoFrame) w0.setReadOnly(True) w1 = QPlainTextEdit() w1.setFrameShape(QFrame.NoFrame) w1.setReadOnly(True) t.addTab(w0, qApp.translate("Export", "Markdown source")) t.addTab(w1, qApp.translate("Export", "HTML Source")) if webView: w2 = webView() t.addTab(w2, qApp.translate("Export", "HTML Output")) t.setCurrentIndex(2) return t
def __init__(self): """ Widget initialization """ super().__init__('Show changes') self.beforePTE = QPlainTextEdit() self.afterPTE = QPlainTextEdit() # widgets are read-only self.beforePTE.setReadOnly(True) self.afterPTE.setReadOnly(True) # bind the scroll position of the two widgets beforeScrollbar = self.beforePTE.verticalScrollBar() afterScrollbar = self.afterPTE.verticalScrollBar() beforeScrollbar.valueChanged.connect(afterScrollbar.setValue) afterScrollbar.valueChanged.connect(beforeScrollbar.setValue) hbox = QHBoxLayout() hbox.addWidget(self.beforePTE) hbox.addWidget(self.afterPTE) widget = QWidget() widget.setLayout(hbox) # # sizeHint for the widget # def sizeHint(self): # return QSize(self.width(), 150) # widget.sizeHint = types.MethodType(sizeHint, widget) self.setWidget(widget)
class QTextInputDialog(QDialog): def __init__(self, initial='', parent=None): super().__init__(parent) self.setWindowModality(QtCore.Qt.ApplicationModal) self.setMaximumSize(400, 230) self.setMinimumSize(400, 230) self.resize(400, 230) self.scrollArea = QScrollArea(self) self.scrollArea.setGeometry(QtCore.QRect(5, 5, 390, 190)) self.scrollArea.setWidgetResizable(True) self.plainTextEdit = QPlainTextEdit() self.plainTextEdit.setGeometry(QtCore.QRect(0, 0, 390, 190)) self.plainTextEdit.setPlainText(initial) self.scrollArea.setWidget(self.plainTextEdit) self.acceptButton = QPushButton(self) self.acceptButton.setGeometry(QtCore.QRect(280, 200, 100, 25)) self.acceptButton.setText("Ok") self.rejectButton = QPushButton(self) self.rejectButton.setGeometry(QtCore.QRect(160, 200, 100, 25)) self.rejectButton.setText("Cancel") self.rejectButton.clicked.connect(self.reject) self.acceptButton.clicked.connect(self.accept)
def keyPressEvent(self, event): if self.isReadOnly(): return modifiers = event.modifiers() if modifiers in (Qt.AltModifier, Qt.ControlModifier): return if modifiers == Qt.ShiftModifier: if not event.text(): return key = event.key() if key == Qt.Key_Backspace: text_selected = self.textCursor().selectedText() if text_selected: del self.__input[-len(text_selected):] else: try: self.__input.pop() except IndexError: return elif key in (Qt.Key_Left, Qt.Key_Right, Qt.Key_Up, Qt.Key_Down, Qt.Key_CapsLock): return elif key in (Qt.Key_Enter, Qt.Key_Return): data = "".join(self.__input) self.inputRequested.emit(data) self.__input.clear() else: self.__input.append(event.text()) QPlainTextEdit.keyPressEvent(self, event)
def mousePressEvent(self, event): """ When the execution fail, allow to press the links in the traceback, to go to the line when the error occur. """ QPlainTextEdit.mousePressEvent(self, event) self.go_to_error(event)
def __init__(self): super(self.__class__, self).__init__() self.name_label = QLabel("Name (optional):") self.name_line_edit = QLineEdit() self.introducer_label = QLabel("Introducer fURL:") self.introducer_text_edit = QPlainTextEdit() self.introducer_text_edit.setMaximumHeight(70) self.introducer_text_edit.setTabChangesFocus(True) self.description_label = QLabel("Description (optional):") self.description_text_edit = QPlainTextEdit() self.description_text_edit.setMaximumHeight(70) self.description_text_edit.setTabChangesFocus(True) self.push_button = QPushButton("Save") form = QFormLayout() form.setWidget(0, QFormLayout.LabelRole, self.name_label) form.setWidget(0, QFormLayout.FieldRole, self.name_line_edit) form.setWidget(1, QFormLayout.LabelRole, self.introducer_label) form.setWidget(1, QFormLayout.FieldRole, self.introducer_text_edit) #form.setWidget(2, QFormLayout.LabelRole, self.description_label) #form.setWidget(2, QFormLayout.FieldRole, self.description_text_edit) form.setWidget(3, QFormLayout.FieldRole, self.push_button) hbox = QHBoxLayout(self) #hbox.addItem(QSpacerItem(100, 0, QSizePolicy.Preferred, 0)) hbox.addLayout(form)
def keyPressEvent(self, event): #if self.completer.popup().isVisible(): #if event.key() in (Qt.Key_Enter, Qt.Key_Return, Qt.Key_Tab): #event.ignore() #self.completer.popup().hide() #return #elif event.key in (Qt.Key_Space, Qt.Key_Escape, Qt.Key_Backtab): #self.completer.popup().hide() self._check_event_on_selection(event) if self._pre_key_press.get(event.key(), lambda x: False)(event): return if event.text() in (set(BRACES.values()) - set(["'", '"'])): cursor = self.textCursor() cursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor) brace = cursor.selection().toPlainText() cursor = self.textCursor() cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor) braceClose = cursor.selection().toPlainText() if BRACES.get(brace, False) == event.text() and \ braceClose == event.text(): self.moveCursor(QTextCursor.Right) return QPlainTextEdit.keyPressEvent(self, event) if event.text() in BRACES: cursor = self.textCursor() cursor.movePosition(QTextCursor.StartOfLine, QTextCursor.KeepAnchor) self.textCursor().insertText( BRACES[event.text()]) self.moveCursor(QTextCursor.Left)
def resizeEvent(self, e): QPlainTextEdit.resizeEvent(self, e) self.cr = self.contentsRect() self.lineNumberArea.setGeometry(self.cr.left(), self.cr.top(), self.lineNumberAreaWidth(), self.cr.height())
def wheelEvent(self, event): if (event.modifiers() & Qt.ControlModifier): self.y = event.angleDelta() / 120 # print('wheel is ',self.x.y()) delta = self.y.y() self.zoomOption(delta) else: QPlainTextEdit.wheelEvent(self, event)
class QPlainTextEditLogger(logging.Handler): def __init__(self, parent): super().__init__() self.widget = QPlainTextEdit(parent) self.widget.setReadOnly(True) def emit(self, record): msg = self.format(record) self.widget.appendPlainText(msg)
def mouseMoveEvent(self, event): cursor = self.cursorForPosition(event.pos()) text = cursor.block().text() if text: if self.patLink.match(text): self.viewport().setCursor(Qt.PointingHandCursor) else: self.viewport().setCursor(Qt.IBeamCursor) QPlainTextEdit.mouseMoveEvent(self, event)
def create_textbox_dialog(content: str, title: str, parent) -> QDialog: d = QDialog(parent) d.resize(800, 600) d.setWindowTitle(title) layout = QVBoxLayout(d) text_edit = QPlainTextEdit(content) text_edit.setReadOnly(True) layout.addWidget(text_edit) d.setLayout(layout) return d
def __init_layout(self) -> QVBoxLayout: self.__sql_input = QPlainTextEdit() self.__sql_input.setFixedHeight(self.__SQL_INPUT_HEIGHT) self.__output = QPlainTextEdit() vbox = QVBoxLayout() vbox.addLayout(self.__init_sql_query_layout()) vbox.addWidget(self.__sql_input) vbox.addLayout(self.__init_sql_template_button_layout()) vbox.addWidget(self.__output) return vbox
def __init__(self): QPlainTextEdit.__init__(self) EditorMixin.__init__(self) # Word separators # Can be used by code completion and the link emulator self.word_separators = "`~!@#$%^&*()-=+[{]}\\|;:'\",.<>/?" # Style self.__init_style() self.__apply_style() self.__visible_blocks = []
class CommentEditor(QWidget): textChanged = pyqtSignal() def __init__(self, comments=""): """ Just holds a TextEdit and a label """ super(CommentEditor, self).__init__() self.top_layout = WidgetUtils.addLayout(vertical=True) self.setLayout(self.top_layout) self.editor = QPlainTextEdit(self) self.editor.resize(10, 10) self.editor.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.editor.setPlainText(comments) self.label = WidgetUtils.addLabel(self.top_layout, self, "Comment") self.top_layout.addWidget(self.editor) self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.setMinimumSize(0, 20) self.editor.textChanged.connect(self.textChanged) def setComments(self, comments): self.editor.setPlainText(comments) def getComments(self): return str(self.editor.toPlainText())
class ErrorReportDialog(QDialog): def __init__(self, parent, github_url, error, **kwargs): flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint super().__init__(parent, flags, **kwargs) self._setupUi() name = QCoreApplication.applicationName() version = QCoreApplication.applicationVersion() errorText = "Application Name: {}\nVersion: {}\n\n{}".format(name, version, error) # Under windows, we end up with an error report without linesep if we don't mangle it errorText = errorText.replace('\n', os.linesep) self.errorTextEdit.setPlainText(errorText) self.github_url = github_url self.sendButton.clicked.connect(self.goToGithub) self.dontSendButton.clicked.connect(self.reject) def _setupUi(self): self.setWindowTitle(tr("Error Report")) self.resize(553, 349) self.verticalLayout = QVBoxLayout(self) self.label = QLabel(self) self.label.setText(tr("Something went wrong. How about reporting the error?")) self.label.setWordWrap(True) self.verticalLayout.addWidget(self.label) self.errorTextEdit = QPlainTextEdit(self) self.errorTextEdit.setReadOnly(True) self.verticalLayout.addWidget(self.errorTextEdit) msg = tr( "Error reports should be reported as Github issues. You can copy the error traceback " "above and paste it in a new issue (bonus point if you run a search to make sure the " "issue doesn't already exist). What usually really helps is if you add a description " "of how you got the error. Thanks!" "\n\n" "Although the application should continue to run after this error, it may be in an " "unstable state, so it is recommended that you restart the application." ) self.label2 = QLabel(msg) self.label2.setWordWrap(True) self.verticalLayout.addWidget(self.label2) self.horizontalLayout = QHBoxLayout() self.horizontalLayout.addItem(horizontalSpacer()) self.dontSendButton = QPushButton(self) self.dontSendButton.setText(tr("Close")) self.dontSendButton.setMinimumSize(QSize(110, 0)) self.horizontalLayout.addWidget(self.dontSendButton) self.sendButton = QPushButton(self) self.sendButton.setText(tr("Go to Github")) self.sendButton.setMinimumSize(QSize(110, 0)) self.sendButton.setDefault(True) self.horizontalLayout.addWidget(self.sendButton) self.verticalLayout.addLayout(self.horizontalLayout) def goToGithub(self): open_url(self.github_url)
def paintEvent(self, event): painter = QPainter(self.viewport()) if self.highlight_line: r = self.cursorRect() r.setX(0) r.setWidth(self.viewport().width()) painter.fillRect(r, self.highlight_brush) if self.draw_line: painter.setPen(self.line_pen) painter.drawLine(self.line) painter.end() QPlainTextEdit.paintEvent(self, event)
class TracebackWidget(QWidget): """ Represents a python traceback """ def __init__(self, traceback_msg): super(TracebackWidget, self).__init__() vbox = QVBoxLayout(self) self._editor = QPlainTextEdit() vbox.addWidget(QLabel(_translate("TracebackWidget", 'Traceback'))) vbox.addWidget(self._editor) self._editor.setReadOnly(True) self._editor.insertPlainText(traceback_msg)
class ScriptsPage(QtWidgets.QWizardPage): def __init__(self, Wizard, parent=None): super(ScriptsPage, self).__init__(parent) self.base = Wizard.base self.setTitle(self.tr("Scripts page")) self.setSubTitle(self.tr("Write scripts")) prepareLabel = QLabel("%prepare: ") self.prepareEdit = QPlainTextEdit() buildLabel = QLabel("%build: ") self.buildEdit = QPlainTextEdit() installLabel = QLabel("%install: ") self.installEdit = QPlainTextEdit() checkLabel = QLabel("%check: ") self.checkEdit = QPlainTextEdit() buildArchLabel = QLabel("BuildArch: ") self.buildArchCheckbox = QCheckBox("noarch") grid = QGridLayout() grid.addWidget(prepareLabel, 0, 0) grid.addWidget(self.prepareEdit, 0, 1) grid.addWidget(buildLabel, 1, 0) grid.addWidget(self.buildEdit, 1, 1) grid.addWidget(installLabel, 2, 0) grid.addWidget(self.installEdit, 2, 1) grid.addWidget(checkLabel, 3, 0) grid.addWidget(self.checkEdit, 3, 1) grid.addWidget(buildArchLabel, 4, 0) grid.addWidget(self.buildArchCheckbox, 4, 1) self.setLayout(grid) def validatePage(self): self.base.spec.scripts['%prep'] = Command(self.prepareEdit.toPlainText()) self.base.spec.scripts['%build'] = Command(self.buildEdit.toPlainText()) self.base.spec.scripts['%install'] = Command(self.installEdit.toPlainText()) self.base.spec.scripts['%check'] = Command(self.checkEdit.toPlainText()) if self.buildArchCheckbox.isChecked(): self.base.spec.tags['BuildArch'] = "noarch" else: self.base.spec.tags.pop('BuildArch', None) return True def nextId(self): return Wizard.PageRequires
class GalleryListEdit(misc.BasePopup): apply = pyqtSignal() def __init__(self, parent=None): super().__init__(parent, blur=False) main_layout = QFormLayout(self.main_widget) self.name_edit = QLineEdit(self) main_layout.addRow("Name:", self.name_edit) self.filter_edit = QPlainTextEdit(self) self.filter_edit.setPlaceholderText("tag1, namespace:tag2, namespace2:[tag1, tag2] ...") self.filter_edit.setFixedHeight(100) what_is_filter = misc.ClickedLabel("What is Filter/Enforce? (Hover)") what_is_filter.setToolTip(app_constants.WHAT_IS_FILTER) what_is_filter.setToolTipDuration(9999999999) self.enforce = QCheckBox(self) self.regex = QCheckBox(self) self.case = QCheckBox(self) self.strict = QCheckBox(self) main_layout.addRow(what_is_filter) main_layout.addRow("Filter", self.filter_edit) main_layout.addRow("Enforce", self.enforce) main_layout.addRow("Regex", self.regex) main_layout.addRow("Case sensitive", self.case) main_layout.addRow("Match whole terms", self.strict) main_layout.addRow(self.buttons_layout) self.add_buttons("Close")[0].clicked.connect(self.hide) self.add_buttons("Apply")[0].clicked.connect(self.accept) old_v = self.width() self.adjustSize() self.resize(old_v, self.height()) def set_list(self, gallery_list, item): self.gallery_list = gallery_list self.name_edit.setText(gallery_list.name) self.enforce.setChecked(gallery_list.enforce) self.regex.setChecked(gallery_list.regex) self.case.setChecked(gallery_list.case) self.strict.setChecked(gallery_list.strict) self.item = item if gallery_list.filter: self.filter_edit.setPlainText(gallery_list.filter) else: self.filter_edit.setPlainText('') def accept(self): name = self.name_edit.text() self.item.setText(name) self.gallery_list.name = name self.gallery_list.filter = self.filter_edit.toPlainText() self.gallery_list.enforce = self.enforce.isChecked() self.gallery_list.regex = self.regex.isChecked() self.gallery_list.case = self.case.isChecked() self.gallery_list.strict = self.strict.isChecked() gallerydb.execute(gallerydb.ListDB.modify_list, True, self.gallery_list) self.apply.emit() self.hide()
class ConfigFile: def __init__(self, display_name, absolute_name, tab, deletable=True): self.display_name = display_name # is unique self.absolute_name = absolute_name # is also unique self.tab = tab self.deletable = deletable self.index = -1 self.modified = False self.content = None self.edit = QPlainTextEdit() font = QFont('monospace') font.setStyleHint(QFont.TypeWriter) self.edit.setWordWrapMode(QTextOption.NoWrap) self.edit.setFont(font) self.edit.textChanged.connect(self.check_content) def check_content(self): self.set_modified(self.content != self.edit.toPlainText()) def set_modified(self, modified): if self.modified == modified: return self.modified = modified self.tab.combo_config.setItemText(self.index, self.get_combo_item()) self.tab.update_ui_state() def set_content(self, content): # FIXME: QPlainTextEdit does not preserve the original line endings, but # converts all line endings to \n. this results in a difference # between self.content and the content stored in the QPlainTextEdit # even if the user did not edit the content. avoid this problem # by converting all line endings to \n before setting the content # of the QPlainTextEdit content = content.replace('\r\n', '\n') if self.content == None: self.edit.setPlainText(content) self.content = content self.check_content() def get_combo_item(self): if self.modified: return self.display_name + ' (modified)' else: return self.display_name def discard_changes(self): self.edit.setPlainText(self.content) self.set_modified(False)
def __init__(self): super(QWidget, self).__init__() layout = QFormLayout() self.setLayout(layout) self.buildDependencies = QPlainTextEdit() self.buildDependencies.textChanged.connect(self.buildDependenciesChanged) self.buildDependencies.setMinimumHeight(70) layout.addRow('Build Dependencies', self.buildDependencies) self.runDependencies = QPlainTextEdit() self.runDependencies.textChanged.connect(self.runDependenciesChanged) self.runDependencies.setMinimumHeight(70) layout.addRow('Run Dependencies', self.runDependencies)
def previewWidget(self): w = QPlainTextEdit() w.setFrameShape(QFrame.NoFrame) w.setReadOnly(True) return w
def initUI(self): # Creating an Automaton class instance self.Automaton = Automaton() # Creating a Input_String class instance self.Strings = Input_Strings() # Creating a Configuration_Setting instance self.Config_Setting = Configuration_Settings() # A attribute to remember the def_path self.def_path = '' # A attribute to remember if the automaton was opened self.automaton_open = False self.setWindowTitle("Pushdown Automaton") self.resize(640, 480) self.mainMenu = self.menuBar() self.fileMenu = self.mainMenu.addMenu("File") self.fileMenu.addAction("Open Automaton Ctrl+O", self.open_automaton_action) self.openShorcut = QShortcut(QKeySequence("Ctrl+O"), self) self.openShorcut.activated.connect(self.open_automaton_action) #self.fileMenu.addAction("View Automaton", self.view_automaton_action) self.fileMenu.addAction("Quit Ctrl+Shift+Q", self.quit_action) self.quitAppShorcut = QShortcut(QKeySequence("Ctrl+Shift+Q"), self) self.quitAppShorcut.activated.connect(self.quit_action) self.helpMenu = self.mainMenu.addMenu("Help") self.helpMenu.addAction("User Manual Ctrl+H", self.user_manual_action) self.userManualShorcut = QShortcut(QKeySequence("Ctrl+H"), self) self.userManualShorcut.activated.connect(self.user_manual_action) self.inputStringLabel = QLabel(self) self.inputStringLabel.setGeometry(20, 40, 111, 16) self.inputStringLabel.setText("Input String") self.inputStringLineEdit = QLineEdit(self) self.inputStringLineEdit.setGeometry(20, 60, 231, 20) self.addToListPushButton = QPushButton(self) self.addToListPushButton.setGeometry(80, 90, 111, 23) self.addToListPushButton.setText("Add to List") self.addToListPushButton.clicked.connect(self.add_to_list_clicked) self.addToListShorcut = QShortcut(QKeySequence("Ctrl+Shift+A"), self) self.addToListShorcut.activated.connect(self.add_to_list_clicked) self.addToListPushButton.setToolTip("Ctrl+Shift+A") self.inputStringListLabel = QLabel(self) self.inputStringListLabel.setGeometry(20, 125, 111, 16) self.inputStringListLabel.setText("Input String List") self.inputStringListWidget = QListWidget(self) self.inputStringListWidget.setGeometry(20, 145, 231, 260) self.runStringPushButton = QPushButton(self) self.runStringPushButton.setGeometry(80, 415, 111, 23) self.runStringPushButton.setText("Run String") self.runStringPushButton.clicked.connect(self.run_string_clicked) self.runStringShorcut = QShortcut(QKeySequence("Ctrl+R"), self) self.runStringShorcut.activated.connect(self.run_string_clicked) self.runStringPushButton.setToolTip("Ctrl+R") self.fileNameLabel = QLabel(self) self.fileNameLabel.setGeometry(440, 40, 160, 16) self.fileNameLabel.setText("Automaton Title") self.fileNameLabel.setStyleSheet("color: blue") self.outputLabel = QLabel(self) self.outputLabel.setGeometry(300, 60, 47, 16) self.outputLabel.setText("Output") self.maxTransitionsLabel = QLabel(self) self.maxTransitionsLabel.setGeometry(370, 60, 80, 16) self.maxTransitionsLabel.setText("Max. Transitions") self.maxTransitionsSpinBox = QSpinBox(self) self.maxTransitionsSpinBox.setGeometry(455, 57, 42, 20) self.maxTransitionsSpinBox.setMinimum(1) #access value with self.maxTransitionsSpinBox.value self.displayPathsCheckBox = QCheckBox(self) self.displayPathsCheckBox.setGeometry(530, 60, 101, 17) self.displayPathsCheckBox.setText("Display Paths") #access true or false with self.displayPathsCheckBox.checked self.outputPlainTextEdit = QPlainTextEdit(self) self.outputPlainTextEdit.setGeometry(300, 80, 271, 253) #300, 80, 281, 283 self.stackPlainTextEdit = QPlainTextEdit(self) self.stackPlainTextEdit.setGeometry(581, 80, 30, 253) self.pathLabel = QLabel(self) self.pathLabel.setGeometry(300, 335, 47, 16) self.pathLabel.setText("Path") self.pathPlainTextEdit = QPlainTextEdit(self) self.pathPlainTextEdit.setGeometry(300, 355, 311, 50) self.quitRunningStringPushButton = QPushButton(self) self.quitRunningStringPushButton.setGeometry(335, 415, 111, 23) self.quitRunningStringPushButton.setText("Quit Running String") self.quitRunningStringPushButton.clicked.connect( self.quit_running_string_clicked) self.quitRunningStringShorcut = QShortcut(QKeySequence("Ctrl+Q"), self) self.quitRunningStringShorcut.activated.connect( self.quit_running_string_clicked) self.quitRunningStringPushButton.setToolTip("Ctrl+Q") self.closeAutomatonPushButton = QPushButton(self) self.closeAutomatonPushButton.setGeometry(465, 415, 111, 23) self.closeAutomatonPushButton.setText("Close Automaton") self.closeAutomatonPushButton.clicked.connect( self.close_automaton_clicked) self.closeAutomatonShorcut = QShortcut(QKeySequence("Ctrl+Alt+C"), self) self.closeAutomatonShorcut.activated.connect( self.close_automaton_clicked) self.closeAutomatonPushButton.setToolTip("Ctrl+Alt+C") # Style for status label text self.styleError = 'font: 15pt Arial; color: maroon' self.styleNormal = 'font:15pt Arial; color: green' self.statusBar = self.statusBar() self.statusLabel = QLabel( "application status messages will go here (when something completes, etc.)" ) self.statusLabel.setStyleSheet(self.styleNormal) self.statusBar.addPermanentWidget(self.statusLabel) self.show()
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.commandslist = [] self.tracker = 0 os.chdir(os.path.expanduser("~")) # print(os.getcwd()) self.name = (str(getpass.getuser()) + "@" + str(socket.gethostname()) + ":" + str(os.getcwd()) + "$ ") self.setWindowTitle('PyQt5Terminal') self.setWindowIcon(QIcon.fromTheme("terminal-emulator")) self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.MergedChannels) self.process.readyRead.connect(self.dataReady) self.process.readyReadStandardError.connect( self.onReadyReadStandardError) self.process.readyReadStandardOutput.connect( self.onReadyReadStandardOutput) self.process.finished.connect(self.isFinished) self.process.setWorkingDirectory(os.getcwd()) self.createStatusBar() self.commandfield = QPlainTextEdit() self.commandfield.setLineWrapMode(QPlainTextEdit.NoWrap) self.commandfield.setFixedHeight(44) self.commandfield.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.commandfield.setAcceptDrops(True) self.cursor = self.commandfield.textCursor() self.textWindow = QPlainTextEdit(self) self.setStyleSheet(mystylesheet(self)) self.textWindow.setReadOnly(True) layout = QVBoxLayout() layout.addWidget(self.textWindow) layout.addWidget(self.commandfield) self.wid = QWidget() self.wid.setLayout(layout) self.setCentralWidget(self.wid) self.setGeometry(0, 0, 600, 500) self.commandfield.setPlainText(self.name) self.cursorEnd() self.commandfield.setFocus() self.copySelectedTextAction = QAction(QIcon.fromTheme("edit-copy"), "Copy", shortcut="Shift+Ctrl+c", triggered=self.copyText) self.textWindow.addAction(self.copySelectedTextAction) self.pasteTextAction = QAction(QIcon.fromTheme("edit-paste"), "Copy", shortcut="Shift+Ctrl+v", triggered=self.pasteText) self.commandfield.addAction(self.pasteTextAction) # self.cancelAction = QAction("Cancel", shortcut="Ctrl+c", triggered=self.killProcess) self.textWindow.addAction(self.cancelAction) self.commandfield.installEventFilter(self) # self.textWindow.installEventFilter(self) QApplication.setCursorFlashTime(1000) self.cursorEnd() print(self.process.workingDirectory()) self.settings = QSettings("QTerminal", "QTerminal") self.readSettings() def closeEvent(self, e): self.writeSettings() def cursorEnd(self): self.name = (str(getpass.getuser()) + "@" + str(socket.gethostname()) + ":" + str(os.getcwd()) + "$ ") self.commandfield.setPlainText(self.name) cursor = self.commandfield.textCursor() cursor.movePosition(11, 0) self.commandfield.setTextCursor(cursor) self.commandfield.setFocus() def eventFilter(self, source, event): if source == self.commandfield: if (event.type() == QEvent.DragEnter): event.accept() return True elif (event.type() == QEvent.Drop): print('Drop') self.setDropEvent(event) return True elif (event.type() == QEvent.KeyPress): cursor = self.commandfield.textCursor() # print('key press:', (event.key(), event.text())) if event.key() == Qt.Key_Backspace: if cursor.positionInBlock() <= len(self.name): return True else: return False elif event.key() == Qt.Key_Return: self.run() return True elif event.key() == Qt.Key_Left: if cursor.positionInBlock() <= len(self.name): return True else: return False elif event.key() == Qt.Key_Delete: if cursor.positionInBlock() <= len(self.name) - 1: return True else: return False elif event.modifiers() == Qt.ControlModifier and event.key( ) == Qt.Key_C: self.killProcess() return True elif event.key() == Qt.Key_Up: try: if self.tracker != 0: cursor.select(QTextCursor.BlockUnderCursor) cursor.removeSelectedText() self.commandfield.appendPlainText(self.name) self.commandfield.insertPlainText( self.commandslist[self.tracker]) self.tracker -= 1 except IndexError: self.tracker = 0 return True elif event.key() == Qt.Key_Down: try: if self.tracker != 0: cursor.select(QTextCursor.BlockUnderCursor) cursor.removeSelectedText() self.commandfield.appendPlainText(self.name) self.commandfield.insertPlainText( self.commandslist[self.tracker]) self.tracker += 1 except IndexError: self.tracker = 0 return True else: return False else: return False else: return False def copyText(self): self.textWindow.copy() def pasteText(self): self.commandfield.paste() def killProcess(self): print("cancelled") self.process.kill() self.textWindow.appendPlainText("cancelled") self.cursorEnd() def createStatusBar(self): sysinfo = QSysInfo() myMachine = "current CPU Architecture: " + sysinfo.currentCpuArchitecture( ) + " *** " + sysinfo.prettyProductName( ) + " *** " + sysinfo.kernelType() + " " + sysinfo.kernelVersion() self.statusBar().showMessage(myMachine, 0) def setDropEvent(self, event): self.commandfield.setFocus() if event.mimeData().hasUrls(): f = str(event.mimeData().urls()[0].toLocalFile()) print("is file:", f) if " " in f: self.commandfield.insertPlainText("'{}'".format(f)) else: self.commandfield.insertPlainText(f) event.accept() elif event.mimeData().hasText(): ft = event.mimeData().text() print("is text:", ft) if " " in ft: self.commandfield.insertPlainText("'{}'".format(ft)) else: self.commandfield.insertPlainText(ft) else: event.ignore() def run(self): print("started") cli = [] cmd = "" t = "" self.textWindow.setFocus() self.textWindow.appendPlainText(self.commandfield.toPlainText()) cli = shlex.split(self.commandfield.toPlainText().replace( self.name, '').replace("'", '"'), posix=False) cmd = str(cli[0]) ### is the executable if cmd == "exit": quit() elif cmd == "cd": del cli[0] path = " ".join(cli) os.chdir(os.path.abspath(path)) self.process.setWorkingDirectory(os.getcwd()) print("workingDirectory:", self.process.workingDirectory()) self.cursorEnd() else: self.process.setWorkingDirectory(os.getcwd()) print("workingDirectory", self.process.workingDirectory()) del cli[0] if (QStandardPaths.findExecutable(cmd)): self.commandslist.append( self.commandfield.toPlainText().replace(self.name, "")) print("command", cmd, "found") t = " ".join(cli) if self.process.state() != 2: self.process.waitForStarted() self.process.waitForFinished() if "|" in t or ">" in t or "<" in t: print("special characters") self.process.start('sh -c "' + cmd + ' ' + t + '"') print("running", ('sh -c "' + cmd + ' ' + t + '"')) else: self.process.start(cmd + " " + t) print("running", (cmd + " " + t)) else: print("command not found ...") self.textWindow.appendPlainText("command not found ...") self.cursorEnd() def dataReady(self): out = "" try: out = str(self.process.readAll(), encoding='utf8').rstrip() except TypeError: out = str(self.process.readAll()).rstrip() self.textWindow.moveCursor(self.cursor.Start) ### changed self.textWindow.appendPlainText(out) def onReadyReadStandardError(self): self.error = self.process.readAllStandardError().data().decode() self.textWindow.appendPlainText(self.error.strip('\n')) self.cursorEnd() def onReadyReadStandardOutput(self): self.result = self.process.readAllStandardOutput().data().decode() self.textWindow.appendPlainText(self.result.strip('\n')) self.cursorEnd() self.state = self.process.state() def isFinished(self): print("finished") self.name = (str(getpass.getuser()) + "@" + str(socket.gethostname()) + ":" + str(os.getcwd()) + "$ ") self.commandfield.setPlainText(self.name) self.cursorEnd() def readSettings(self): if self.settings.contains("commands"): self.commandslist = self.settings.value("commands") if self.settings.contains("pos"): pos = self.settings.value("pos", QPoint(200, 200)) self.move(pos) if self.settings.contains("size"): size = self.settings.value("size", QSize(400, 400)) self.resize(size) def writeSettings(self): self.settings.setValue("commands", self.commandslist) self.settings.setValue("pos", self.pos()) self.settings.setValue("size", self.size())
def resizeEvent(self, e): o = QPlainTextEdit.resizeEvent(self, e) self.resizeButtons() return o
class DebugWindow(QMainWindow): """A main window to edit text and examine the generated token structure. Example:: from PyQt5.Qt import * a=QApplication([]) from parceqt.debug import DebugWindow w = DebugWindow() w.resize(1200,900) w.show() w.set_theme("default", True) from parce.lang.css import * w.set_root_lexicon(Css.root) w.set_text(open("path/to/parce/themes/default.css").read()) In the debug window you can edit the text at the left and directly at the right examine the tree structure. Along the top of the window the path to the token at the current cursor position is displayed, from the root lexicon upto the token, from which the action is displayed. Clicking a button selects the associated range of the context or token in the text view. Clicking an item in the tree also selects that range in the text. Moving the cursor in the text updates the current item in the tree, and the displayed ancestor path. """ show_updated_region_enabled = False def __init__(self, parent=None): super().__init__(parent, windowTitle="parceqt debugger") f = self._updated_format = QTextCharFormat() c = QColor("palegreen") c.setAlpha(64) f.setBackground(c) f = self._currentline_format = QTextCharFormat() f.setProperty(QTextCharFormat.FullWidthSelection, True) self._actions = Actions(self) self._actions.add_menus(self.menuBar()) widget = QWidget(self) self.setCentralWidget(widget) layout = QVBoxLayout(margin=4, spacing=2) widget.setLayout(layout) top_layout = QHBoxLayout(margin=0, spacing=0) self.guessButton = QToolButton(self, clicked=self.guess_root_lexicon, toolTip="Guess Language", icon=self.style().standardIcon( QStyle.SP_BrowserReload)) self.lexiconChooser = LexiconChooser(self) self.ancestorView = AncestorView(self) top_layout.addWidget(self.guessButton) top_layout.addWidget(self.lexiconChooser) top_layout.addWidget(self.ancestorView) top_layout.addStretch(10) layout.addLayout(top_layout) self.guessButton.setFixedHeight( self.lexiconChooser.sizeHint().height()) splitter = QSplitter(self, orientation=Qt.Horizontal) layout.addWidget(splitter, 100) self.textEdit = QPlainTextEdit(lineWrapMode=QPlainTextEdit.NoWrap, cursorWidth=2) self.treeView = QTreeView() splitter.addWidget(self.textEdit) splitter.addWidget(self.treeView) splitter.setStretchFactor(0, 3) splitter.setStretchFactor(1, 2) self.extraSelectionManager = ExtraSelectionManager(self.textEdit) self.document = d = self.textEdit.document() self.textEdit.setDocument(self.document) self.worker = w = parceqt.worker(d) self.builder = b = w.builder() w.debugging = True self.setStatusBar(QStatusBar()) self.create_model() # signal connections self.textEdit.viewport().installEventFilter(self) self.textEdit.installEventFilter(self) self.lexiconChooser.lexicon_changed.connect( self.slot_root_lexicon_changed) self.ancestorView.node_clicked.connect(self.slot_node_clicked) w.started.connect(self.slot_build_started) w.tree_updated.connect(self.slot_build_updated) self.textEdit.cursorPositionChanged.connect( self.slot_cursor_position_changed) self.treeView.clicked.connect(self.slot_item_clicked) self.textEdit.setFocus() self.set_theme() # somewhat larger font by default font = self.textEdit.font() font.setPointSizeF(11) self.textEdit.setFont(font) def create_model(self): """Instantiate a tree model for the tree view.""" m = self.treeView.model() if not m: m = parceqt.treemodel.TreeModel(self.builder.root) m.connect_debugging_builder(self.builder) self.treeView.setModel(m) def delete_model(self): """Delete the model and remove it from the tree.""" m = self.treeView.model() if m: m.disconnect_debugging_builder(self.builder) self.treeView.setModel(None) m.deleteLater() def set_text(self, text): """Set the text in the text edit.""" self.document.setPlainText(text) def set_root_lexicon(self, lexicon): """Set the root lexicon to use.""" self.lexiconChooser.set_root_lexicon(lexicon) def guess_root_lexicon(self): """Again choose the root lexicon based on the text.""" text = self.document.toPlainText() if text: self.set_root_lexicon(parce.find(contents=text)) def open_file(self, filename): """Read a file from disk and guess the language.""" text = read_file(filename) root_lexicon = parce.find(filename=filename, contents=text) self.set_text(text) self.set_root_lexicon(root_lexicon) c = self.textEdit.textCursor() c.setPosition(0) self.textEdit.setTextCursor(c) def set_theme(self, theme="default", adjust_widget=True): """Set the theme to use for the text edit.""" if isinstance(theme, str): theme = parce.theme_by_name(theme) formatter = parceqt.formatter.Formatter(theme) if theme else None if adjust_widget: if formatter: font = formatter.font(self) self.textEdit.setPalette(formatter.palette(self)) else: font = QApplication.font(self) self.textEdit.setPalette(QApplication.palette(self)) font.setPointSizeF(self.textEdit.font().pointSizeF()) # keep size self.textEdit.setFont(font) self.highlight_current_line() h = parceqt.highlighter.SyntaxHighlighter.instance(self.worker) h.set_formatter(formatter) def slot_build_started(self): """Called when the tree builder has started a build.""" self.treeView.setCursor(Qt.BusyCursor) def slot_build_updated(self): """Called when the tree builder has finished a build.""" self.treeView.unsetCursor() self.slot_cursor_position_changed() self.statusBar().showMessage(", ".join( lexicon_names(self.builder.lexicons))) tree = self.worker.get_root() self.lexiconChooser.setToolTip( parceqt.treemodel.TreeModel.node_tooltip(tree)) if self.show_updated_region_enabled: self.show_updated_region() def slot_cursor_position_changed(self): """Called when the text cursor moved.""" tree = self.worker.get_root() if tree: pos = self.textEdit.textCursor().position() doc = parceqt.document.Document(self.document) token = doc.token(pos) if token: self.ancestorView.set_token_path(token) model = self.treeView.model() if model: index = model.get_model_index(token) self.treeView.setCurrentIndex(index) elif tree is not None: self.ancestorView.clear() self.highlight_current_line() def slot_item_clicked(self, index): """Called when a node in the tree view is clicked.""" tree = self.worker.get_root() if tree: model = self.treeView.model() if model: node = self.treeView.model().get_node(index) cursor = self.textEdit.textCursor() cursor.setPosition(node.end) cursor.setPosition(node.pos, QTextCursor.KeepAnchor) self.textEdit.setTextCursor(cursor) self.textEdit.setFocus() def slot_node_clicked(self, node): """Called when a button in the ancestor view is clicked.""" tree = self.worker.get_root() if tree and node.root() is tree: cursor = self.textEdit.textCursor() cursor.setPosition(node.end) cursor.setPosition(node.pos, QTextCursor.KeepAnchor) self.textEdit.setTextCursor(cursor) self.textEdit.setFocus() model = self.treeView.model() if model: index = model.get_model_index(node) self.treeView.expand(index) self.treeView.setCurrentIndex(index) def slot_root_lexicon_changed(self, lexicon): """Called when the root lexicon is changed.""" parceqt.set_root_lexicon(self.document, lexicon) def highlight_current_line(self): """Highlight the current line.""" group = QPalette.Active if self.textEdit.hasFocus( ) else QPalette.Inactive p = self.textEdit.palette() color = p.color(group, QPalette.AlternateBase) self._currentline_format.setBackground(color) if color != p.color(group, QPalette.Base): c = self.textEdit.textCursor() c.clearSelection() self.extraSelectionManager.highlight(self._currentline_format, [c]) else: self.extraSelectionManager.clear(self._currentline_format) def show_updated_region(self): """Highlight the updated region for 2 seconds.""" end = self.builder.end if end >= self.document.characterCount() - 1: end = self.document.characterCount() - 1 if self.builder.start == 0: return c = QTextCursor(self.document) c.setPosition(end) c.setPosition(self.builder.start, QTextCursor.KeepAnchor) self.extraSelectionManager.highlight(self._updated_format, [c], msec=2000) def clear_updated_region(self): self.extraSelectionManager.clear(self._updated_format) def eventFilter(self, obj, ev): """Implemented to support Ctrl+wheel zooming and keybfocus handling.""" if obj == self.textEdit: if ev.type() in (QEvent.FocusIn, QEvent.FocusOut): self.highlight_current_line() else: # viewport if ev.type() == QEvent.Wheel and ev.modifiers( ) == Qt.ControlModifier: if ev.angleDelta().y() > 0: self.textEdit.zoomIn() elif ev.angleDelta().y() < 0: self.textEdit.zoomOut() return True return False
class RemoteWidget(QWidget): """Main Widget.""" def __init__(self, parent: QWidget = None) -> None: super().__init__(parent) self._connected_sensors = {} self.resize(700, 500) # Varibles for PowerReport self.window_power_r = None self.power_config_name = [] self.power_config_id = [] self.power_th = [] self.power_pol = [] self.power_data_acc = False # debug messages self.debug_label = QLabel(self.tr('Debug')) self.debug_textedit = QPlainTextEdit() self.debug_textedit.setReadOnly(True) self.debug_label.setBuddy(self.debug_textedit) self._debug = CustomDebug(self.debug_textedit) # Refresh COM Ports self.refresh_com_ports_btn = QPushButton(self.tr('Refresh')) self.refresh_com_ports_btn.pressed.connect(self.update_com_ports) # Refresh COM Ports self.connect_btn = QPushButton(self.tr('Connect')) self.connect_btn.pressed.connect(self.on_connect_btn_pressed) # Port Combobox self.port_label = QLabel(self.tr('COM Port:')) self.port_combobox = QComboBox() self.port_label.setBuddy(self.port_combobox) self.port_combobox.currentIndexChanged.connect( self.on_port_combobox_change) self.update_com_ports() # Connect and Disconnect Buttons self.connect_btn = QPushButton(self.tr('Connect')) self.disconnect_btn = QPushButton(self.tr('Disconnect')) self.disconnect_btn.setVisible(False) self.connect_btn.pressed.connect(self.on_connect_btn_pressed) self.disconnect_btn.pressed.connect(self.on_disconnect_btn_pressed) # New Configuration Button self.new_config_btn = QPushButton(self.tr('New')) self.new_config_btn.setVisible(False) self.new_config_btn.pressed.connect(self.on_new_config_pressed) # Test connection self.test_btn = QPushButton(self.tr('Test')) self.test_btn.setVisible(False) self.connect_btn.pressed.connect(self.on_test_btn_pressed) # poll messages # Enabled? # self.poll_checkbox = QCheckBox("Poll?", self) # self.poll_checkbox.stateChanged.connect(self.click_poll_sensor) # Seconds self.poll_label = QLabel(self.tr('Poll interval (minutes):')) self.poll_lineedit = QLineEdit() self.poll_label.setBuddy(self.poll_lineedit) self.poll_label.setVisible(False) self.poll_lineedit.setEnabled(True) self.poll_lineedit.setVisible(False) # self.poll_lineedit.returnPressed.connect(self.) # threshold # per metric # Enabled? self.threshold_label_1 = QLabel(self.tr('Metric 1:')) self.threshold_label_2 = QLabel(self.tr('Metric 2:')) self.threshold_label_2.setVisible(False) self.threshold_label_3 = QLabel(self.tr('Metric 3:')) self.threshold_label_3.setVisible(True) self.threshold_label_4 = QLabel(self.tr('Metric 4:')) self.threshold_label_4.setVisible(True) self.threshold_checkbox_1 = QCheckBox("Threshold ?", self) self.threshold_checkbox_1.stateChanged.connect( self.click_threshold_checkbox_1) self.threshold_checkbox_1.setVisible(False) self.threshold_checkbox_2 = QCheckBox("Threshold ?", self) self.threshold_checkbox_2.stateChanged.connect( self.click_threshold_checkbox_2) self.threshold_checkbox_2.setVisible(False) self.threshold_checkbox_3 = QCheckBox("Threshold ?", self) self.threshold_checkbox_3.stateChanged.connect( self.click_threshold_checkbox_3) self.threshold_checkbox_3.setVisible(False) self.threshold_checkbox_4 = QCheckBox("Threshold ?", self) self.threshold_checkbox_4.stateChanged.connect( self.click_threshold_checkbox_4) self.threshold_checkbox_4.setVisible(False) # threshold high self.threshold_high_label_1 = QLabel(self.tr('High:')) self.threshold_high_lineedit_1 = QLineEdit() self.threshold_high_label_1.setBuddy(self.threshold_high_lineedit_1) self.threshold_high_lineedit_1.setEnabled(True) self.threshold_high_label_2 = QLabel(self.tr('High:')) self.threshold_high_lineedit_2 = QLineEdit() self.threshold_high_label_2.setBuddy(self.threshold_high_lineedit_2) self.threshold_high_lineedit_2.setEnabled(True) self.threshold_high_label_3 = QLabel(self.tr('High:')) self.threshold_high_lineedit_3 = QLineEdit() self.threshold_high_label_3.setBuddy(self.threshold_high_lineedit_3) self.threshold_high_lineedit_3.setEnabled(True) self.threshold_high_label_4 = QLabel(self.tr('High:')) self.threshold_high_lineedit_4 = QLineEdit() self.threshold_high_label_4.setBuddy(self.threshold_high_lineedit_4) self.threshold_high_lineedit_4.setEnabled(True) # threshold Low self.threshold_low_label_1 = QLabel(self.tr('Low:')) self.threshold_low_lineedit_1 = QLineEdit() self.threshold_low_label_1.setBuddy(self.threshold_low_lineedit_1) self.threshold_low_lineedit_1.setEnabled(True) self.threshold_low_label_2 = QLabel(self.tr('Low:')) self.threshold_low_lineedit_2 = QLineEdit() self.threshold_low_label_2.setBuddy(self.threshold_low_lineedit_2) self.threshold_low_lineedit_2.setEnabled(True) self.threshold_low_label_3 = QLabel(self.tr('Low:')) self.threshold_low_lineedit_3 = QLineEdit() self.threshold_low_label_3.setBuddy(self.threshold_low_lineedit_3) self.threshold_low_lineedit_3.setEnabled(True) self.threshold_low_label_4 = QLabel(self.tr('Low:')) self.threshold_low_lineedit_4 = QLineEdit() self.threshold_low_label_4.setBuddy(self.threshold_low_lineedit_4) self.threshold_low_lineedit_4.setEnabled(True) # Sensor Combobox self.sensor_label = QLabel(self.tr('Sensor:')) self.sensor_combobox = QComboBox() self.sensor_label.setBuddy(self.sensor_combobox) self.sensor_combobox.currentIndexChanged.connect( self.on_sensor_combobox_change) self.update_com_ports() self.sensor_btn = QPushButton(self.tr('Load')) self.sensor_btn.setVisible(False) self.sensor_btn.pressed.connect(self.on_sensor_btn_pressed) # Save and Disconnect Buttons self.save_btn = QPushButton(self.tr('Save')) # disable visivibility and only show when there is a connection self.save_btn.setVisible(False) self.disconnect_btn = QPushButton(self.tr('Disconnect')) self.disconnect_btn.setVisible(False) self.save_btn.pressed.connect(self.on_save_btn_pressed) self.disconnect_btn.pressed.connect(self.on_disconnect_btn_pressed) # Power Report Button # self.power_report_btn = QPushButton(self.tr('Power Report')) # self.power_report_btn.setVisible(False) # self.power_report_btn.pressed.connect(self.on_power_report_btn_pressed) # Data Accumulation Enabling/Disabling self.accumulation_checkbox = QCheckBox("Data Accumulation ?", self) self.accumulation_checkbox.stateChanged.connect(self.click_accumulation_checkbox) self.accumulation_checkbox.setVisible(False) # Arrange Layout layout = QGridLayout() # COM Port line layout.addWidget(self.port_label, 0, 0) layout.addWidget(self.port_combobox, 0, 1, 1, 3) layout.addWidget(self.connect_btn, 0, 4) layout.addWidget(self.refresh_com_ports_btn, 0, 5) # layout.addWidget(self.port_motherboard, 0, 1, 2) # Sensors line layout.addWidget(self.sensor_label, 1, 0) layout.addWidget(self.sensor_combobox, 1, 1, 1, 3) layout.addWidget(self.sensor_btn, 1, 4) layout.addWidget(self.save_btn, 1, 5) # Polling line # layout.addWidget(self.poll_checkbox, 2, 0) layout.addWidget(self.poll_label, 3, 1) layout.addWidget(self.poll_lineedit, 3, 2) # threshold line layout.addWidget(self.threshold_label_1, 4, 0) layout.addWidget(self.threshold_checkbox_1, 4, 1) layout.addWidget(self.threshold_high_label_1, 4, 2) layout.addWidget(self.threshold_high_lineedit_1, 4, 3) layout.addWidget(self.threshold_low_label_1, 4, 4) layout.addWidget(self.threshold_low_lineedit_1, 4, 5) layout.addWidget(self.threshold_label_2, 5, 0) layout.addWidget(self.threshold_checkbox_2, 5, 1) layout.addWidget(self.threshold_high_label_2, 5, 2) layout.addWidget(self.threshold_high_lineedit_2, 5, 3) layout.addWidget(self.threshold_low_label_2, 5, 4) layout.addWidget(self.threshold_low_lineedit_2, 5, 5) layout.addWidget(self.threshold_label_3, 6, 0) layout.addWidget(self.threshold_checkbox_3, 6, 1) layout.addWidget(self.threshold_high_label_3, 6, 2) layout.addWidget(self.threshold_high_lineedit_3, 6, 3) layout.addWidget(self.threshold_low_label_3, 6, 4) layout.addWidget(self.threshold_low_lineedit_3, 6, 5) layout.addWidget(self.threshold_label_4, 7, 0) layout.addWidget(self.threshold_checkbox_4, 7, 1) layout.addWidget(self.threshold_high_label_4, 7, 2) layout.addWidget(self.threshold_high_lineedit_4, 7, 3) layout.addWidget(self.threshold_low_label_4, 7, 4) layout.addWidget(self.threshold_low_lineedit_4, 7, 5) # Debug layout.addWidget(self.debug_label, 8, 0) layout.addWidget(self.debug_textedit, 9, 0, 1, 6) # Save and disconnect layout layout.addWidget(self.disconnect_btn, 10, 4) layout.addWidget(self.test_btn, 10, 5) # Power Report Button # layout.addWidget(self.power_report_btn, 10, 0) # Accumulation Checkbox layout.addWidget(self.accumulation_checkbox, 2, 1) # New Configuration Button layout.addWidget(self.new_config_btn, 10, 4) self.remove_metric_rows_from_gui() self.setLayout(layout) # self._load_settings() self._debug.write("GUI", "Application started successfully") self._debug.write("GUI", VERSION) self.update_com_ports() # def _load_settings(self) -> None: # """Load settings on startup.""" # settings = QSettings() # # port name # port_name = settings.value(SETTING_PORT_NAME) # if port_name is not None: # index = self.port_combobox.findData(port_name) # if index > -1: # self.port_combobox.setCurrentIndex(index) # # last message # msg = settings.value(SETTING_MESSAGE) # if msg is not None: # self.msg_lineedit.setText(msg) # def _save_settings(self) -> None: # """Save settings on shutdown.""" # settings = QSettings() # settings.setValue(SETTING_PORT_NAME, self.port) # settings.setValue(SETTING_MESSAGE, self.msg_lineedit.text()) def on_test_btn_pressed(self): self._debug.write( "GUI", F"TODO") def show_error_message(self, msg: str) -> None: """Show a Message Box with the error message.""" QMessageBox.critical(self, QApplication.applicationName(), str(msg)) def update_com_ports(self) -> None: """Update COM Port list in GUI.""" self._debug.write("COM", "Searching for COM ports") self.port_combobox.clear() for name, device in gen_serial_ports(): self.port_combobox.addItem(name, device) self._debug.write("COM", F"Found name: {name}, device: {device}") def on_sensor_combobox_change(self, i): # TODO pass def on_port_combobox_change(self, i): self._debug.write( "GUI", F"Selected {self.port_combobox.currentText()} COM ports") def remove_metric_rows_from_gui(self): self.poll_lineedit.setVisible(False) self.poll_label.setVisible(False) self.threshold_label_1.setVisible(False) self.threshold_label_2.setVisible(False) self.threshold_label_3.setVisible(False) self.threshold_label_4.setVisible(False) self.threshold_checkbox_1.setVisible(False) self.threshold_checkbox_2.setVisible(False) self.threshold_checkbox_3.setVisible(False) self.threshold_checkbox_4.setVisible(False) self.threshold_high_label_1.setVisible(False) self.threshold_high_label_2.setVisible(False) self.threshold_high_label_3.setVisible(False) self.threshold_high_label_4.setVisible(False) self.threshold_low_label_1.setVisible(False) self.threshold_low_label_2.setVisible(False) self.threshold_low_label_3.setVisible(False) self.threshold_low_label_4.setVisible(False) self.threshold_high_lineedit_1.setVisible(False) self.threshold_high_lineedit_2.setVisible(False) self.threshold_high_lineedit_3.setVisible(False) self.threshold_high_lineedit_4.setVisible(False) self.threshold_low_lineedit_1.setVisible(False) self.threshold_low_lineedit_2.setVisible(False) self.threshold_low_lineedit_3.setVisible(False) self.threshold_low_lineedit_4.setVisible(False) def on_sensor_btn_pressed(self): self.save_btn.setVisible(True) self.remove_metric_rows_from_gui() sensor_str = self.sensor_combobox.currentText() selected_sensor = self._connected_sensors[sensor_str] self._debug.write("APP", F"Loading sensor data from {selected_sensor}") Motherboard.load_data(selected_sensor, self._debug, ser) # self.poll_checkbox.setCheckState(selected_sensor._polling_enabled) if selected_sensor.get_name() == 'Button Sensor': self.poll_label.setVisible(False) self.poll_lineedit.setVisible(False) self.poll_lineedit.setEnabled(False) else: self.poll_label.setVisible(True) self.poll_lineedit.setVisible(True) self.poll_lineedit.setEnabled(True) self.poll_lineedit.setText(str(selected_sensor._polling_interval_sec // 60)) for idx, (th_e, th_h, th_l, label) in enumerate(zip(selected_sensor._thresholds_enabled, selected_sensor.get_thresholds(which_th=Motherboard.TH_HIGH, to_machine=False), selected_sensor.get_thresholds(which_th=Motherboard.TH_LOW, to_machine=False), selected_sensor._metric_labels)): th_h = str(th_h) th_l = str(th_l) if idx == 0: self.threshold_label_1.setText(label) self.threshold_label_1.setVisible(True) self.threshold_checkbox_1.setCheckState(th_e) self.threshold_checkbox_1.setVisible(True) self.threshold_high_lineedit_1.setText(th_h) self.threshold_high_lineedit_1.setVisible(True) self.threshold_low_lineedit_1.setText(th_l) self.threshold_low_lineedit_1.setVisible(True) self.threshold_low_label_1.setVisible(True) self.threshold_high_label_1.setVisible(True) if idx == 1: self.threshold_label_2.setText(label) self.threshold_label_2.setVisible(True) self.threshold_checkbox_2.setCheckState(th_e) self.threshold_checkbox_2.setVisible(True) self.threshold_high_lineedit_2.setText(th_h) self.threshold_high_lineedit_2.setVisible(True) self.threshold_low_lineedit_2.setText(th_l) self.threshold_low_lineedit_2.setVisible(True) self.threshold_low_label_2.setVisible(True) self.threshold_high_label_2.setVisible(True) if idx == 2: self.threshold_label_3.setText(label) self.threshold_label_3.setVisible(True) self.threshold_checkbox_3.setCheckState(th_e) self.threshold_checkbox_3.setVisible(True) self.threshold_high_lineedit_3.setText(th_h) self.threshold_high_lineedit_3.setVisible(True) self.threshold_low_lineedit_3.setText(th_l) self.threshold_low_lineedit_3.setVisible(True) self.threshold_low_label_3.setVisible(True) self.threshold_high_label_3.setVisible(True) if idx == 3: self.threshold_label_4.setText(label) self.threshold_label_4.setVisible(True) self.threshold_checkbox_4.setCheckState(th_e) self.threshold_checkbox_4.setVisible(True) self.threshold_high_lineedit_4.setText(th_h) self.threshold_high_lineedit_4.setVisible(True) self.threshold_low_lineedit_4.setText(th_l) self.threshold_low_lineedit_4.setVisible(True) self.threshold_low_label_4.setVisible(True) self.threshold_high_label_4.setVisible(True) def on_power_report_btn_pressed(self): """Display Power Measurement for the selected configuration """ # TODO if self.window_power_r is None: self.power_report_btn.setVisible(False) nb_bd = len(self.power_config_id) if nb_bd == 0: self.window_power_r = PowerReport.PowerReport(data_acc=self.power_data_acc) elif nb_bd == 1: self.window_power_r = PowerReport.PowerReport(data_acc=self.power_data_acc, id_config_1=self.power_config_id[0], poll_interval_1=self.power_pol[0], thresholds_1=self.power_th[0]) elif nb_bd == 2: self.window_power_r = PowerReport.PowerReport(data_acc=self.power_data_acc, id_config_1=self.power_config_id[0], poll_interval_1=self.power_pol[0], thresholds_1=self.power_th[0], id_config_2=self.power_config_id[1], poll_interval_2=self.power_pol[1], thresholds_2=self.power_th[1]) elif nb_bd == 3: self.window_power_r = PowerReport.PowerReport(data_acc=self.power_data_acc, id_config_1=self.power_config_id[0], poll_interval_1=self.power_pol[0], thresholds_1=self.power_th[0], id_config_2=self.power_config_id[1], poll_interval_2=self.power_pol[1], thresholds_2=self.power_th[1], id_config_3=self.power_config_id[2], poll_interval_3=self.power_pol[2], thresholds_3=self.power_th[2]) elif nb_bd == 4: self.window_power_r = PowerReport.PowerReport(data_acc=self.power_data_acc, id_config_1=self.power_config_id[0], poll_interval_1=self.power_pol[0], thresholds_1=self.power_th[0], id_config_2=self.power_config_id[1], poll_interval_2=self.power_pol[1], thresholds_2=self.power_th[1], id_config_3=self.power_config_id[2], poll_interval_3=self.power_pol[2], thresholds_3=self.power_th[2], id_config_4=self.power_config_id[3], poll_interval_4=self.power_pol[3], thresholds_4=self.power_th[3]) elif nb_bd == 5: self.window_power_r = PowerReport.PowerReport(data_acc=self.power_data_acc, id_config_1=self.power_config_id[0], poll_interval_1=self.power_pol[0], thresholds_1=self.power_th[0], id_config_2=self.power_config_id[1], poll_interval_2=self.power_pol[1], thresholds_2=self.power_th[1], id_config_3=self.power_config_id[2], poll_interval_3=self.power_pol[2], thresholds_3=self.power_th[2], id_config_4=self.power_config_id[3], poll_interval_4=self.power_pol[3], thresholds_4=self.power_th[3], id_config_5=self.power_config_id[4], poll_interval_5=self.power_pol[4], thresholds_5=self.power_th[4]) elif nb_bd == 6: self.window_power_r = PowerReport.PowerReport(data_acc=self.power_data_acc, id_config_1=self.power_config_id[0], poll_interval_1=self.power_pol[0], thresholds_1=self.power_th[0], id_config_2=self.power_config_id[1], poll_interval_2=self.power_pol[1], thresholds_2=self.power_th[1], id_config_3=self.power_config_id[2], poll_interval_3=self.power_pol[2], thresholds_3=self.power_th[2], id_config_4=self.power_config_id[3], poll_interval_4=self.power_pol[3], thresholds_4=self.power_th[3], id_config_5=self.power_config_id[4], poll_interval_5=self.power_pol[4], thresholds_5=self.power_th[4], id_config_6=self.power_config_id[5], poll_interval_6=self.power_pol[5], thresholds_6=self.power_th[5]) self.window_power_r.show() @property def port(self) -> str: """Return the current serial port.""" return self.port_combobox.currentData() def closeEvent(self, event: QCloseEvent) -> None: """Handle Close event of the Widget.""" if ser.is_open: ser.close() # self._save_settings() event.accept() def click_poll_sensor(self): # TODO pass def click_threshold_checkbox_1(self): pass # TODO def click_threshold_checkbox_2(self): pass # TODO def click_threshold_checkbox_3(self): pass # TODO def click_threshold_checkbox_4(self): pass # TODO def click_accumulation_checkbox(self): (err, acc_confirm) = Motherboard.set_accumulation( ser, self._debug, enable=self.accumulation_checkbox.isChecked()) if (not err): self._debug.write("APP", F"Accumulation {acc_confirm}") self.power_data_acc = self.accumulation_checkbox.isChecked() def on_save_btn_pressed(self): sensor_str = self.sensor_combobox.currentText() selected_sensor = self._connected_sensors[sensor_str] self._debug.write("APP", F"Saving data from {sensor_str}") # check which metrics are visible # update data from input to selected_sensor object # update motherboard # selected_sensor._polling_enabled = self.poll_checkbox.isChecked() if selected_sensor.get_name() != 'Button Sensor': selected_sensor._polling_interval_sec = int(self.poll_lineedit.text()) * 60 if self.threshold_label_1.isVisible(): # read data from threshold 1 selected_sensor._thresholds_enabled[0] = self.threshold_checkbox_1.isChecked( ) selected_sensor.set_threshold(float(self.threshold_high_lineedit_1.text( )), metric_idx=0, to_machine=True, which_th=Motherboard.TH_HIGH) selected_sensor.set_threshold(float(self.threshold_low_lineedit_1.text( )), metric_idx=0, to_machine=True, which_th=Motherboard.TH_LOW) self._debug.write("APP", F"Saving metric 1 from {sensor_str}") # metric 2 is only visible when 1 is also visible if self.threshold_label_2.isVisible(): selected_sensor._thresholds_enabled[1] = self.threshold_checkbox_2.isChecked( ) selected_sensor.set_threshold(float(self.threshold_high_lineedit_2.text( )), metric_idx=1, to_machine=True, which_th=Motherboard.TH_HIGH) selected_sensor.set_threshold(float(self.threshold_low_lineedit_2.text( )), metric_idx=1, to_machine=True, which_th=Motherboard.TH_LOW) self._debug.write( "APP", F"Saving metric 2 from {sensor_str}") if self.threshold_label_3.isVisible(): selected_sensor._thresholds_enabled[2] = self.threshold_checkbox_3.isChecked( ) selected_sensor.set_threshold(float(self.threshold_high_lineedit_3.text( )), metric_idx=2, to_machine=True, which_th=Motherboard.TH_HIGH) selected_sensor.set_threshold(float(self.threshold_low_lineedit_3.text( )), metric_idx=2, to_machine=True, which_th=Motherboard.TH_LOW) self._debug.write( "APP", F"Saving metric 3 from {sensor_str}") if self.threshold_label_4.isVisible(): selected_sensor._thresholds_enabled[3] = self.threshold_checkbox_4.isChecked( ) selected_sensor.set_threshold(float(self.threshold_high_lineedit_4.text( )), metric_idx=3, to_machine=True, which_th=Motherboard.TH_HIGH) selected_sensor.set_threshold(float(self.threshold_low_lineedit_4.text( )), metric_idx=3, to_machine=True, which_th=Motherboard.TH_LOW) self._debug.write( "APP", F"Saving metric 4 from {sensor_str}") Motherboard.upload_sensor(selected_sensor, ser, self._debug) # For the power report ----------------------------------------------------------------------------------------- idc = self.power_config_name.index(selected_sensor.get_name()) if selected_sensor.get_polling_interval_sec() != 65535: if selected_sensor.get_polling_interval_sec() != 0: self.power_pol[idc] = int(selected_sensor.get_polling_interval_sec() / 60) flag = False for metrics in range(selected_sensor.get_num_metrics()): if selected_sensor.get_thresholds_enabled(metrics) is True: flag = True break if flag is True: self.power_th[idc] = True if selected_sensor.get_name() == 'Power Sensor': self.power_config_id[idc] = 3 elif selected_sensor.get_name() == 'Sound Sensor': self.power_config_id[idc] = 5 elif selected_sensor.get_name() == 'Environmental Sensor': self.power_config_id[idc] = 7 else: self.power_th[idc] = False if selected_sensor.get_name() == 'Power Sensor': self.power_config_id[idc] = 2 elif selected_sensor.get_name() == 'Sound Sensor': self.power_config_id[idc] = 4 elif selected_sensor.get_name() == 'Environmental Sensor': self.power_config_id[idc] = 6 if self.window_power_r is not None: self.window_power_r = None self.power_report_btn.setVisible(True) # -------------------------------------------------------------------------------------------------------------- def on_connect_btn_pressed(self) -> None: """Open serial connection to the specified port.""" self._debug.write( "APP", F"Trying to access motherbaord on port {self.port}") if ser.is_open: ser.close() ser.port = self.port try: ser.open() except Exception as e: self.show_error_message(str(e)) if ser.is_open: self._debug.write( "COM", F"Serial port {self.port} is open.") (err, motherboard_id) = Motherboard.handle_ping(ser, self._debug) if not err: self._debug.write("COM", F"Connected to {motherboard_id}") self.connect_btn.setEnabled(False) self.test_btn.setVisible(True) self.disconnect_btn.setVisible(True) self.disconnect_btn.pressed.connect(self.on_disconnect_btn_pressed) self.sensor_btn.pressed.connect(self.on_sensor_btn_pressed) self.save_btn.pressed.connect(self.on_save_btn_pressed) self.port_combobox.setDisabled(True) self.save_btn.setEnabled(True) self.load_sensors() (err2, acc_state) = Motherboard.request_acc(ser, self._debug) if (not err2): self.accumulation_checkbox.setVisible(True) self.accumulation_checkbox.setCheckState(acc_state) else: self._debug.write( "ERR", F"Serial port {self.port} is not open :(.") # loop.create_task(self.receive_serial_async()) def load_sensors(self): self._connected_sensors = {} """request the connected sensors on the motherboard""" _sensors = [] (_err, _sensors) = Motherboard.request_sensors(ser, self._debug) if (not _err): if len(_sensors) > 0: self.sensor_btn.setVisible(True) for s in _sensors: _name = s.get_name() _id = s.get_addr() # For the power report --------------------------------------------------------------------------------- self.power_config_name.append(_name) if _name == 'Button Sensor': self.power_config_id.append(1) elif _name == 'Power Sensor': self.power_config_id.append(2) elif _name == 'Sound Sensor': self.power_config_id.append(4) elif _name == 'Environmental Sensor': self.power_config_id.append(6) self.power_pol.append(False) self.power_th.append(False) # self.power_report_btn.setVisible(True) # ------------------------------------------------------------------------------------------------------ _sensor_str = F"{_name} [{_id}]" self._debug.write("GUI", F"Adding Sensor: {_sensor_str}") self.sensor_combobox.addItem(_sensor_str) self._connected_sensors.update({ _sensor_str: s }) # def load_sensor_data(self): # for sensor_str, sensor in self._connected_sensors.items(): # Motherboard.load_data(sensor, self._debug) def on_disconnect_btn_pressed(self) -> None: """Close current serial connection.""" self.disconnect_btn.pressed.disconnect() self.new_config_btn.setVisible(True) self.save_btn.pressed.disconnect() self.sensor_btn.pressed.disconnect() Motherboard.close(ser, self._debug) if ser.is_open: ser.close() self.update_com_ports() def on_send_btn_pressed(self) -> None: """Send message to serial port.""" msg = self.msg_lineedit.text() + '\r\n' loop.call_soon(send_serial_async, msg) def on_new_config_pressed(self): """Reset all variables to restart a new configuration""" self._connected_sensors = {} self.window_power_r = None self.power_config_name = [] self.power_config_id = [] self.power_th = [] self.power_pol = [] self.power_data_acc = False self._debug = CustomDebug(self.debug_textedit) self.update_com_ports() self.remove_metric_rows_from_gui() self._debug.write("GUI", "Application started successfully") self._debug.write("GUI", VERSION) self.update_com_ports() self.sensor_combobox.clear() self.sensor_btn.setVisible(False) self.save_btn.setVisible(False) self.accumulation_checkbox.setVisible(False) self.new_config_btn.setVisible(False) self.disconnect_btn.setVisible(False) self.connect_btn.setEnabled(True) self.port_combobox.setEnabled(True) async def receive_serial_async(self) -> None: """Wait for incoming data, convert it to text and add to Textedit.""" while True: msg = ser.readline() if msg != b'': text = msg.decode().strip() self.received_textedit.appendPlainText(text) await asyncio.sleep(0)
class PostProcessor(QMainWindow): sim_results_changed = pyqtSignal() post_results_changed = pyqtSignal() figures_changed = pyqtSignal(list, str) def __init__(self, parent=None): QMainWindow.__init__(self, parent) self._settings = QSettings() self._logger = logging.getLogger(self.__class__.__name__) self.setWindowTitle("Processing") self.setWindowIcon(QIcon(get_resource("processing.png"))) self.mainFrame = QWidget(self) self.resize(1000, 600) # toolbar self.toolBar = QToolBar("file control") self.toolBar.setIconSize(QSize(24, 24)) self.addToolBar(self.toolBar) self.actLoad = QAction(self) self.actLoad.setText("load result file") self.actLoad.setIcon(QIcon(get_resource("load.png"))) self.actLoad.setDisabled(False) self.actLoad.triggered.connect(self.load_result_files) self.actPostLoad = QAction(self) self.actPostLoad.setText("load post-result file") self.actPostLoad.setIcon(QIcon(get_resource("load.png"))) self.actPostLoad.setDisabled(False) self.actPostLoad.triggered.connect(self.load_post_result_files) self.actSwitch = QAction(self) self.actSwitch.setText("switch display mode") self.actSwitch.setIcon(QIcon(get_resource("left_mode.png"))) self.actSwitch.setDisabled(False) self.actSwitch.triggered.connect(self.switch_sides) self.displayLeft = True self.spacer1 = QWidget() self.spacer2 = QWidget() self.spacer1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.actReloadMethods = QAction(self) self.actReloadMethods.setText("reload methods") self.actReloadMethods.setIcon(QIcon(get_resource("reload.png"))) self.actReloadMethods.setDisabled(False) self.actReloadMethods.triggered.connect(self.update_post_method_list) self.actReloadMetaMethods = QAction(self) self.actReloadMetaMethods.setText("reload meta methods") self.actReloadMetaMethods.setIcon(QIcon(get_resource("reload.png"))) self.actReloadMetaMethods.setDisabled(False) self.actReloadMetaMethods.triggered.connect( self.update_meta_method_list) self.toolBar.addAction(self.actLoad) self.toolBar.addAction(self.actReloadMethods) self.toolBar.addWidget(self.spacer1) self.toolBar.addAction(self.actSwitch) self.toolBar.addWidget(self.spacer2) self.toolBar.addAction(self.actReloadMetaMethods) self.toolBar.addAction(self.actPostLoad) # main window self.grid = QGridLayout(self.mainFrame) self.grid.setColumnMinimumWidth(0, 70) self.grid.setColumnStretch(0, 0) self.grid.setColumnStretch(1, 1) self.methodList = QListWidget(self) self.methodList.itemDoubleClicked.connect(self.post_processor_clicked) self.update_post_method_list() self.metaMethodList = QListWidget(self) self.metaMethodList.itemDoubleClicked.connect( self.meta_processor_clicked) self.update_meta_method_list() self.sim_result_list = QListWidget(self) self.sim_results_changed.connect(self.update_result_list) self.results = [] self.delShort = QShortcut(QKeySequence(Qt.Key_Delete), self.sim_result_list) self.delShort.activated.connect(self.remove_result_item) # figures self._figure_dict = {} self.figures_changed.connect(self.update_figure_lists) self.post_figure_list = QListWidget(self) self.post_figure_list.currentItemChanged.connect( self.current_figure_changed) self.meta_figure_list = QListWidget(self) self.meta_figure_list.currentItemChanged.connect( self.current_figure_changed) self.plotView = QWidget() self.lastFigure = None self.post_result_list = QListWidget(self) self.post_results_changed.connect(self.update_post_result_list) self.post_results = [] self.delShortPost = QShortcut(QKeySequence(Qt.Key_Backspace), self.post_result_list) self.delShortPost.activated.connect(self.remove_post_result_item) # log dock self.logBox = QPlainTextEdit(self) self.logBox.setReadOnly(True) # init logger for logging box self.textLogger = PlainTextLogger(logging.INFO) self.textLogger.set_target_cb(self.logBox.appendPlainText) logging.getLogger().addHandler(self.textLogger) self.grid.addWidget(QLabel("Result Files:"), 0, 0) self.grid.addWidget(self.sim_result_list, 1, 0) self.grid.addWidget(QLabel("Postprocessors:"), 2, 0) self.grid.addWidget(self.methodList, 3, 0) self.grid.addWidget(QLabel("Figures:"), 4, 0) self.grid.addWidget(self.post_figure_list, 5, 0) self.grid.addWidget(QLabel("Selected Figure:"), 0, 1) self.grid.addWidget(QLabel("Postprocessor Files:"), 0, 2) self.grid.addWidget(self.post_result_list, 1, 2) self.grid.addWidget(QLabel("Metaprocessors:"), 2, 2) self.grid.addWidget(self.metaMethodList, 3, 2) self.grid.addWidget(QLabel("Figures:"), 4, 2) self.grid.addWidget(self.meta_figure_list, 5, 2) self.grid.addWidget(self.logBox, 6, 0, 1, 3) self.mainFrame.setLayout(self.grid) self.setCentralWidget(self.mainFrame) # status bar self.statusBar = QStatusBar(self) self.setStatusBar(self.statusBar) def load_result_files(self): path = self._settings.value("path/simulation_results") dialog = QFileDialog(self) dialog.setFileMode(QFileDialog.ExistingFiles) dialog.setDirectory(path) dialog.setNameFilter("PyMoskito Result files (*.pmr)") if dialog.exec_(): files = dialog.selectedFiles() for single_file in files: if single_file: self._load_result_file(single_file) def _load_result_file(self, file_name): """ loads a result file """ self._logger.info("loading result file {}".format(file_name)) with open(file_name.encode(), "rb") as f: self.results.append(pickle.load(f)) self.sim_results_changed.emit() def update_result_list(self): self.sim_result_list.clear() for res in self.results: name = res["regime name"] self.sim_result_list.addItem(name) def remove_result_item(self): if self.sim_result_list.currentRow() >= 0: del self.results[self.sim_result_list.currentRow()] self.sim_result_list.takeItem(self.sim_result_list.currentRow()) def load_post_result_files(self): path = self._settings.value("path/processing_results") dialog = QFileDialog(self) dialog.setFileMode(QFileDialog.ExistingFiles) dialog.setDirectory(path) dialog.setNameFilter("Postprocessing Output files (*.pof)") if dialog.exec_(): files = dialog.selectedFiles() for single_file in files: if single_file: self._load_post_result_file(single_file) def _load_post_result_file(self, file_name): """ loads a post-result file (.pof) """ name = os.path.split(file_name)[-1][:-4] self._logger.info("loading result file {}".format(file_name)) with open(file_name.encode(), "rb") as f: results = pickle.load(f) results.update({"name": name}) self.post_results.append(results) self.post_results_changed.emit() def update_post_result_list(self): self.post_result_list.clear() for res in self.post_results: name = res["name"] self.post_result_list.addItem(name) def remove_post_result_item(self): if self.post_result_list.currentRow() >= 0: del self.post_results[self.post_result_list.currentRow()] self.post_result_list.takeItem(self.post_result_list.currentRow()) def update_post_method_list(self): self.methodList.clear() modules = pm.get_registered_processing_modules(PostProcessingModule) for mod in modules: self.methodList.addItem(mod[1]) def update_meta_method_list(self): self.metaMethodList.clear() modules = pm.get_registered_processing_modules(MetaProcessingModule) for mod in modules: self.metaMethodList.addItem(mod[1]) def post_processor_clicked(self, item): self.run_processor(str(item.text()), "post") def meta_processor_clicked(self, item): self.run_processor(str(item.text()), "meta") def run_processor(self, name, processor_type): if processor_type == "post": result_files = self.results base_cls = PostProcessingModule elif processor_type == "meta": result_files = self.post_results base_cls = MetaProcessingModule else: self._logger.error( "unknown processor type {0}".format(processor_type)) raise ValueError( "unknown processor type {0}".format(processor_type)) if not result_files: self._logger.warning( "run_processor() Error: no result file loaded") return processor_cls = pm.get_processing_module_class_by_name(base_cls, name) processor = processor_cls() figs = [] try: self._logger.info("executing processor '{0}'".format(name)) figs = processor.process(result_files) except Exception as err: self._logger.exception("Error in processor") self.figures_changed.emit(figs, processor_type) self._logger.info("finished postprocessing") def update_figure_lists(self, figures, target_type): # remove no longer needed elements for item, fig in [(key, val[0]) for key, val in self._figure_dict.items() if val[1] == target_type]: if fig not in [new_fig["figure"] for new_fig in figures]: if target_type == "post": old_item = self.post_figure_list.takeItem( self.post_figure_list.row(item)) del old_item elif target_type == "meta": old_item = self.meta_figure_list.takeItem( self.meta_figure_list.row(item)) del old_item del self._figure_dict[item] # add new ones to internal storage for fig in figures: if fig["figure"] not in self._figure_dict.values(): new_entry = [(fig["name"], (QListWidgetItem(fig["name"]), fig["figure"], target_type))] self._figure_dict.update(new_entry) # add to display for key, val in self._figure_dict.items(): if val[2] == "post": self.post_figure_list.addItem(val[0]) elif val[2] == "meta": self.meta_figure_list.addItem(val[0]) self.post_figure_list.setCurrentItem(self.post_figure_list.item(0)) self.meta_figure_list.setCurrentItem(self.meta_figure_list.item(0)) def current_figure_changed(self, current_item, last_item=None): if current_item is None: return figures = self._figure_dict if self.lastFigure: self.grid.removeWidget(self.lastFigure) self.lastFigure.setVisible(False) if current_item.text() in figures: figure_widget = figures[current_item.text()][1] self.grid.addWidget(figure_widget, 1, 1, 5, 1) figure_widget.setVisible(True) self.lastFigure = figure_widget def switch_sides(self): self.displayLeft = not self.displayLeft if self.displayLeft: self.actSwitch.setIcon(QIcon(get_resource("left_mode.png"))) self.post_figure_list.setFocus() self.current_figure_changed(self.post_figure_list.currentItem()) else: self.actSwitch.setIcon(QIcon(get_resource("right_mode.png"))) self.meta_figure_list.setFocus() self.current_figure_changed(self.meta_figure_list.currentItem())
def __init__(self, text=None): QPlainTextEdit.__init__(self, text) self.setText = self.setPlainText self.text = self.toPlainText self.buttons = []
def __init__(self, parent, addon_data: AddonData): super().__init__() self.__input_control_list = [] self.title = "PyQt5 Scroll Bar" self.top = 200 self.left = 500 self.width = 400 self.height = 300 self.form_layout = QVBoxLayout() self.addon_data = addon_data self.groupbox = QGroupBox(self.addon_data.menu_name) self.parent = parent self.jupyter_widget = self.parent.jupyter_widget self.tools_layout = QGridLayout() self.btn_run = QPushButton("Run...") self.btn_run.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.btn_run.clicked.connect(self.on_btn_run) self.tools_layout.addWidget(self.btn_run, 1, 1) self.btn_stop = QPushButton("Stop") self.btn_stop.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.btn_stop.clicked.connect(self.on_btn_stop) self.tools_layout.addWidget(self.btn_stop, 1, 2) self.btn_restart_kernel = QPushButton("Restart kernel...") self.btn_restart_kernel.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.btn_restart_kernel.clicked.connect(self.on_btn_restart_kernel) self.tools_layout.addWidget(self.btn_restart_kernel, 2, 1) self.btn_clear_console = QPushButton("Clear console") self.btn_clear_console.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.btn_clear_console.clicked.connect(self.on_btn_clear_console) self.tools_layout.addWidget(self.btn_clear_console, 2, 2) # prevent the grid layout from resizing self.tools_layout.setColumnStretch(3, 1) self.form_layout.addLayout(self.tools_layout) self.lbl_backend = QLabel("Choose potting backend:") self.lbl_backend.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.combo_backend = QComboBox() self.combo_backend.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.combo_backend.addItem('inline') self.combo_backend.addItem('qt5') self.layout_backend = QHBoxLayout() self.layout_backend.addWidget(self.combo_backend) self.layout_backend.addStretch(1) self.form_layout.addWidget(self.lbl_backend) self.form_layout.addLayout(self.layout_backend) self.combo_backend.currentIndexChanged.connect( self.on_combo_backend_currentIndexChanged) # textbox with addon directory path self.lbl_addon_dir = QLabel("Addon folder:") self.lbl_addon_dir.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.form_layout.addWidget(self.lbl_addon_dir) self.addon_path = os.path.dirname(os.path.dirname(__file__)) self.addon_path += self.addon_data.rel_path self.text_addon_dir = QPlainTextEdit(self) self.text_addon_dir.setPlainText(self.addon_path) self.text_addon_dir.setFixedSize(252, 120) self.text_addon_dir.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.text_addon_dir.setReadOnly(True) self.form_layout.addWidget(self.text_addon_dir) # TODO: move the input controls # to a child QFrame # add the input controls to the layout for c in self.addon_data.inuput_controls: c.parameters["parent"] = self c.parameters["layout"] = self.form_layout if c.class_name == ic.FileChoose.class_name(): # in this case 'value' is just the filename # make it the file path c.parameters["value"] = (self.addon_path + os.path.sep + c.parameters["value"]) control = ic.create_input_control(c.class_name, c.parameters) self.__input_control_list.append(control) # input controls added self.form_layout.addStretch(1) self.groupbox.setLayout(self.form_layout) self.scroll = QScrollArea() self.scroll.setWidget(self.groupbox) self.scroll.setWidgetResizable(True) self.main_layout = QVBoxLayout(self) self.main_layout.addWidget(self.scroll)
class InputsWidget(QWidget): jupyter_widget = None parent = None def __init__(self, parent, addon_data: AddonData): super().__init__() self.__input_control_list = [] self.title = "PyQt5 Scroll Bar" self.top = 200 self.left = 500 self.width = 400 self.height = 300 self.form_layout = QVBoxLayout() self.addon_data = addon_data self.groupbox = QGroupBox(self.addon_data.menu_name) self.parent = parent self.jupyter_widget = self.parent.jupyter_widget self.tools_layout = QGridLayout() self.btn_run = QPushButton("Run...") self.btn_run.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.btn_run.clicked.connect(self.on_btn_run) self.tools_layout.addWidget(self.btn_run, 1, 1) self.btn_stop = QPushButton("Stop") self.btn_stop.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.btn_stop.clicked.connect(self.on_btn_stop) self.tools_layout.addWidget(self.btn_stop, 1, 2) self.btn_restart_kernel = QPushButton("Restart kernel...") self.btn_restart_kernel.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.btn_restart_kernel.clicked.connect(self.on_btn_restart_kernel) self.tools_layout.addWidget(self.btn_restart_kernel, 2, 1) self.btn_clear_console = QPushButton("Clear console") self.btn_clear_console.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.btn_clear_console.clicked.connect(self.on_btn_clear_console) self.tools_layout.addWidget(self.btn_clear_console, 2, 2) # prevent the grid layout from resizing self.tools_layout.setColumnStretch(3, 1) self.form_layout.addLayout(self.tools_layout) self.lbl_backend = QLabel("Choose potting backend:") self.lbl_backend.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.combo_backend = QComboBox() self.combo_backend.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.combo_backend.addItem('inline') self.combo_backend.addItem('qt5') self.layout_backend = QHBoxLayout() self.layout_backend.addWidget(self.combo_backend) self.layout_backend.addStretch(1) self.form_layout.addWidget(self.lbl_backend) self.form_layout.addLayout(self.layout_backend) self.combo_backend.currentIndexChanged.connect( self.on_combo_backend_currentIndexChanged) # textbox with addon directory path self.lbl_addon_dir = QLabel("Addon folder:") self.lbl_addon_dir.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.form_layout.addWidget(self.lbl_addon_dir) self.addon_path = os.path.dirname(os.path.dirname(__file__)) self.addon_path += self.addon_data.rel_path self.text_addon_dir = QPlainTextEdit(self) self.text_addon_dir.setPlainText(self.addon_path) self.text_addon_dir.setFixedSize(252, 120) self.text_addon_dir.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.text_addon_dir.setReadOnly(True) self.form_layout.addWidget(self.text_addon_dir) # TODO: move the input controls # to a child QFrame # add the input controls to the layout for c in self.addon_data.inuput_controls: c.parameters["parent"] = self c.parameters["layout"] = self.form_layout if c.class_name == ic.FileChoose.class_name(): # in this case 'value' is just the filename # make it the file path c.parameters["value"] = (self.addon_path + os.path.sep + c.parameters["value"]) control = ic.create_input_control(c.class_name, c.parameters) self.__input_control_list.append(control) # input controls added self.form_layout.addStretch(1) self.groupbox.setLayout(self.form_layout) self.scroll = QScrollArea() self.scroll.setWidget(self.groupbox) self.scroll.setWidgetResizable(True) self.main_layout = QVBoxLayout(self) self.main_layout.addWidget(self.scroll) def on_combo_backend_currentIndexChanged(self, q): # set selectioon index for combo_backend # for all the instances of the InputsWidget # TODO: move the input controls # to a child QFrame instances = self.parent.addon_list cur_ind = self.combo_backend.currentIndex() for instance in instances: if instance.combo_backend.currentIndex() != cur_ind: instance.combo_backend.setCurrentIndex(cur_ind) if not self.jupyter_widget._executing: command = ('%matplotlib ' + str(self.combo_backend.currentText()) + '\n') self.jupyter_widget.execute(source=command, hidden=False) def on_btn_clear_console(self, q): if not self.jupyter_widget._executing: self.jupyter_widget.execute(source='%clear', hidden=False) def on_btn_restart_kernel(self, q): if self.jupyter_widget._executing: return self.jupyter_widget.request_restart_kernel() self.__enable_restart_controls_val = False self.enable_restart_controls() self.__enable_restart_controls_val = True QTimer.singleShot(2000, self.enable_restart_controls) def enable_restart_controls(self): enable = self.__enable_restart_controls_val self.btn_run.setEnabled(enable) self.btn_stop.setEnabled(enable) self.btn_restart_kernel.setEnabled(enable) self.btn_clear_console.setEnabled(enable) def on_btn_run(self, q): # set the self.jupyter_widget variable from parent self.jupyter_widget = self.parent.jupyter_widget # do nothing if jupyter_widget already executing if self.jupyter_widget._executing: return # read the source file try: with open(os.path.join(self.addon_path, 'execute.py'), "r") as py_file: source = py_file.read() except Exception as e: QMessageBox.critical(self.parent, main_window_title, 'Error loading the code: ' + str(e)) return str(e) finally: pass # print the input parameter values as the # python source code params = '' for c in self.__input_control_list: value = c.get_value() if value is None: # incorrect user input return if isinstance(value, str): value = 'r"' + value + '"' # enclosing string in quotes var_name = c.get_var_name() var_name.strip() if (' ') in var_name: msg = "variable " + var_name + ' has spaces' QMessageBox.critical(self.parent, main_window_title, msg) return params = (params + var_name + ' = ' + str(value) + '\n') # backend params += ('%matplotlib ' + str(self.combo_backend.currentText()) + '\n') # prepending the read source code with the # parameter initialization source = params + '\n' + source # write the created source in the file for debugging with open(self.addon_path + '/saved.py', "w") as text_file: text_file.write(source) # and finally run the code in the jupyter_widget self.jupyter_widget.execute(source=source, hidden=False) def on_btn_stop(self, q): if self.jupyter_widget._executing: self.jupyter_widget.request_interrupt_kernel() def show_itself(self): self.parent.current_addon.hide() self.show() self.parent.current_addon = self html_path = os.path.join(self.addon_path, 'html') html_path = os.path.join(html_path, 'help.html') self.parent.browser_widget.open_local_text(html_path)
class Plugin: def __get_plugin_info__(self): return { 'name': 'r2dwarf', 'description': 'r2frida in Dwarf', 'version': '1.0.0', 'author': 'iGio90', 'homepage': 'https://github.com/iGio90/Dwarf', 'license': 'https://www.gnu.org/licenses/gpl-3.0' } def __init__(self, app): self.app = app self.pipe = None self.progress_dialog = None self.current_seek = '' self.with_decompiler = False self.app.session_manager.sessionCreated.connect( self._on_session_created) self.app.onUIElementCreated.connect(self._on_ui_element_created) def _create_pipe(self): self.pipe = R2Pipe() self.pipe.open('frida://attach/usb//%d' % self.app.dwarf.pid) r2_decompilers = self.pipe.cmd('e cmd.pdc=?') r2_decompilers = r2_decompilers.split() if r2_decompilers and 'pdc' in r2_decompilers: self.pipe.cmd('e cmd.pdc=pdc') # TODO: let select decompiler self.with_decompiler = True self.pipe.cmd("e scr.color=2; e scr.html=1; e scr.utf8=true;") r2arch = self.app.dwarf.arch r2bits = 32 if r2arch == 'arm64': r2arch = 'arm' r2bits = 64 elif r2arch == 'x64': r2arch = 'x86' r2bits = 64 elif r2arch == 'ia32': r2arch = 'x86' self.pipe.cmd('e asm.arch=%s; e asm.bits=%d; e asm.os=%s' % (r2arch, r2bits, self.app.dwarf.platform)) with open( os.path.join(os.path.dirname(os.path.abspath(__file__)), 'agent.js'), 'r') as f: agent = f.read() self.app.dwarf.dwarf_api('evaluate', agent) def _on_apply_context(self, context_data): if self.pipe is None: self._create_pipe() is_java = 'is_java' in context_data and context_data['is_java'] if not is_java: if 'context' in context_data: native_context = context_data['context'] pc = native_context['pc']['value'] self.current_seek = pc self.pipe.cmd('s %s' % self.current_seek) def _on_disassemble(self, ptr): if self.pipe is None: self._create_pipe() if self.current_seek != ptr: self.current_seek = ptr self.pipe.cmd('s %s' % self.current_seek) self.progress_dialog = utils.progress_dialog('running r2 analysis...') self.progress_dialog.forceShow() self.r2analysis = R2Analysis(self.pipe) self.r2analysis.onR2AnalysisFinished.connect(self._on_finish_analysis) self.r2analysis.start() def _on_finish_analysis(self, data): self.progress_dialog.cancel() function_info = data[0] if 'callrefs' in function_info: for ref in function_info['callrefs']: self.call_refs_model.appendRow([ QStandardItem(hex(ref['addr'])), QStandardItem(hex(ref['at'])), QStandardItem(ref['type']) ]) if 'codexrefs' in function_info: for ref in function_info['codexrefs']: self.code_xrefs_model.appendRow([ QStandardItem(hex(ref['addr'])), QStandardItem(hex(ref['at'])), QStandardItem(ref['type']) ]) def _on_finish_graph(self, data): self.progress_dialog.cancel() graph_data = data[0] self.r2_graph_view.setText('<pre>' + graph_data + '</pre>') def _on_finish_decompiler(self, data): self.progress_dialog.cancel() decompile_data = data[0] if decompile_data is not None: self.r2_decompiler_view.clear() self.r2_decompiler_view.appendHtml('<pre>' + decompile_data + '</pre>') self.r2_decompiler_view.verticalScrollBar().triggerAction( QScrollBar.SliderToMinimum) def _on_receive_cmd(self, args): message, data = args if 'payload' in message: payload = message['payload'] if payload.startswith('r2 '): cmd = message['payload'][3:] self.on_r2_command(cmd) def _on_session_created(self): self.app.dwarf.onReceiveCmd.connect(self._on_receive_cmd) self.app.dwarf.onApplyContext.connect(self._on_apply_context) self.console = DwarfConsoleWidget(self.app, input_placeholder='r2', completer=False) self.console.onCommandExecute.connect(self.on_r2_command) self.app.main_tabs.addTab(self.console, 'r2') def _on_ui_element_created(self, elem, widget): if elem == 'disassembly': self.decompiler_view = widget self.decompiler_view.onDisassemble.connect(self._on_disassemble) r2_info = QSplitter() r2_info.setOrientation(Qt.Vertical) call_refs = DwarfListView() self.call_refs_model = QStandardItemModel(0, 3) self.call_refs_model.setHeaderData(0, Qt.Horizontal, 'call refs') self.call_refs_model.setHeaderData(1, Qt.Horizontal, '') self.call_refs_model.setHeaderData(2, Qt.Horizontal, '') call_refs.setModel(self.call_refs_model) code_xrefs = DwarfListView() self.code_xrefs_model = QStandardItemModel(0, 3) self.code_xrefs_model.setHeaderData(0, Qt.Horizontal, 'code xrefs') self.code_xrefs_model.setHeaderData(1, Qt.Horizontal, '') self.code_xrefs_model.setHeaderData(2, Qt.Horizontal, '') code_xrefs.setModel(self.code_xrefs_model) r2_info.addWidget(call_refs) r2_info.addWidget(code_xrefs) self.decompiler_view.insertWidget(0, r2_info) self.decompiler_view.setStretchFactor(0, 1) self.decompiler_view.setStretchFactor(1, 5) r2_menu = QMenu('r2') r2_menu.addAction('graph view', self.show_graph_view) if self.with_decompiler: r2dec = r2_menu.addAction('decompile', self.show_decompiler_view) self.decompiler_view.disasm_view.menu_extra_menu.append(r2_menu) def show_graph_view(self): self.r2_graph_view = R2ScrollArea() self.app.main_tabs.addTab(self.r2_graph_view, 'graph view') index = self.app.main_tabs.indexOf(self.r2_graph_view) self.app.main_tabs.setCurrentIndex(index) self.progress_dialog = utils.progress_dialog('building graph view...') self.progress_dialog.forceShow() self.r2graph = R2Graph(self.pipe) self.r2graph.onR2Graph.connect(self._on_finish_graph) self.r2graph.start() def show_decompiler_view(self): if not self.with_decompiler: return self.r2_decompiler_view = QPlainTextEdit() self.r2_decompiler_view.setVerticalScrollBarPolicy( Qt.ScrollBarAsNeeded) self.r2_decompiler_view.setHorizontalScrollBarPolicy( Qt.ScrollBarAsNeeded) self.app.main_tabs.addTab(self.r2_decompiler_view, 'decompiler') index = self.app.main_tabs.indexOf(self.r2_decompiler_view) self.app.main_tabs.setCurrentIndex(index) self.progress_dialog = utils.progress_dialog('decompiling function...') self.progress_dialog.forceShow() self.r2decompiler = R2Decompiler(self.pipe) self.r2decompiler.onR2Decompiler.connect(self._on_finish_decompiler) self.r2decompiler.start() def on_r2_command(self, cmd): if cmd == 'clear' or cmd == 'clean': self.console.clear() else: try: result = self.pipe.cmd(cmd) self.console.log(result, time_prefix=False) except BrokenPipeError: self.console.log('pipe is broken. recreating...', time_prefix=False) self._create_pipe() self.pipe.cmd('s %s' % self.current_seek)
def __init__(self, window: QMainWindow, system_info): super().__init__() v_box = QVBoxLayout() h_buttons = QHBoxLayout() button_style = "background-color: #006699; padding-left:20px; padding-right:20px; padding-top:5px; padding-bottom:5px;" copy_pastable_json = json.dumps(system_info, indent=2) website_link = str( base64.b64decode( "aHR0cHM6Ly90YXJhbGxvLndlZWVvcGVuLml0L2J1bGsvYWRkCg=="), "utf-8") self.clipboard_button = QPushButton("Copy to clipboard") self.clipboard_button.setStyleSheet(button_style) self.clipboard_button.clicked.connect( lambda: QApplication.clipboard().setText(copy_pastable_json)) self.clipboard_button.clicked.connect( lambda: self.spawn_notification("Copied to clipboard")) self.website_button = QPushButton("Go to T.A.R.A.L.L.O.") self.website_button.setStyleSheet(button_style) self.website_button.clicked.connect( lambda: sp.Popen(["xdg-open", website_link])) plain_text = QPlainTextEdit() plain_text.document().setPlainText(copy_pastable_json) plain_text.setStyleSheet("background-color:#333333; color:#bbbbbb") plain_text.setReadOnly(True) plain_text.setMinimumSize(plain_text.width(), plain_text.height()) # prevent from resizing too much back_button = QPushButton("Go back") back_button.clicked.connect( lambda: self.restore_previous_window(window, system_info)) h_buttons.addWidget(self.clipboard_button, alignment=Qt.AlignCenter) h_buttons.addWidget(self.website_button, alignment=Qt.AlignCenter) v_box.addLayout(h_buttons) v_box.addWidget(plain_text) v_box.addWidget(back_button, alignment=Qt.AlignCenter) self.setLayout(v_box)
class CheckingWidget_UI(object): checking_ending = QtCore.pyqtSignal(NeuralCrash) def setupUI(self, widget, neuralconfig): self.neuralconfig = neuralconfig self.layout = QVBoxLayout(widget) status = QFormLayout() self.error = QPlainTextEdit() self.error.setReadOnly(True) self.label_load_model = QLabel() self.label_load_model.setText('Checking') self.label_load_testdata = QLabel() self.label_load_testdata.setText('Checking') self.label_get_tested_values = QLabel() self.label_get_tested_values.setText('Checking') self.label_set_tested_values = QLabel() self.label_set_tested_values.setText('Checking') self.label_test_model = QLabel() self.label_test_model.setText('Checking') self.status_load_model = '' self.status_load_testdata = '' self.status_get_tested_values = '' self.status_set_tested_values = '' self.status_test_model = '' status.addRow('load_model', self.label_load_model) status.addRow('load_testdata', self.label_load_testdata) status.addRow('get_tested_values', self.label_get_tested_values) status.addRow('set_tested_values', self.label_set_tested_values) status.addRow('test_model', self.label_test_model) self.layout.addLayout(status) self.layout.addWidget(self.error) self.layout.setContentsMargins(0, 0, 0, 0) self.check_function_load_model() def errorprint(self, text, checked_functions): self.error.appendPlainText(checked_functions + '\n' + text + '\n\n\t--------\n\n') def update_status(self, label_name, status): if label_name == 'load_model': self.status_load_model = status self.label_load_model.setText(status) elif label_name == 'load_testdata': self.status_load_testdata = status self.label_load_testdata.setText(status) elif label_name == 'get_tested_values': self.status_get_tested_values = status self.label_get_tested_values.setText(status) elif label_name == 'set_tested_values': self.status_set_tested_values = status self.label_set_tested_values.setText(status) elif label_name == 'test_model': self.status_test_model = status self.label_test_model.setText(status) def update_label(self, label): if label.text().endswith('...'): label.setText('Checking.') else: label.setText(label.text() + '.') def update_NeuralCrash(self, new_state): self.neuralconfig = new_state def check_function_load_model(self): self.threadAnim_load_model = AnimationTimer(0.3) self.threadWork_load_model = QtCore.QThread() self.QObject_load_model = Check_function(self.neuralconfig, 'load_model') self.QObject_load_model.moveToThread(self.threadWork_load_model) self.threadWork_load_model.started.connect(self.QObject_load_model.run) self.QObject_load_model.function_checked_signal.connect( self.update_status) self.QObject_load_model.error_signal.connect(self.errorprint) self.QObject_load_model.return_new_state.connect( self.update_NeuralCrash) self.QObject_load_model.done.connect( self.threadAnim_load_model.requestInterruption) self.QObject_load_model.done.connect(self.check_function_load_testdata) self.threadAnim_load_model.time_passes.connect( lambda: self.update_label(self.label_load_model)) self.threadAnim_load_model.start() self.threadWork_load_model.start() def check_function_load_testdata(self): self.threadAnim_load_testdata = AnimationTimer(0.3) self.threadWork_load_testdata = QtCore.QThread() self.QObject_load_testdata = Check_function(self.neuralconfig, 'load_testdata') self.QObject_load_testdata.moveToThread(self.threadWork_load_testdata) self.threadWork_load_testdata.started.connect( self.QObject_load_testdata.run) self.QObject_load_testdata.function_checked_signal.connect( self.update_status) self.QObject_load_testdata.error_signal.connect(self.errorprint) self.QObject_load_testdata.return_new_state.connect( self.update_NeuralCrash) self.QObject_load_testdata.done.connect( self.threadAnim_load_testdata.requestInterruption) self.QObject_load_testdata.done.connect( self.check_function_get_tested_values) self.threadAnim_load_testdata.time_passes.connect( lambda: self.update_label(self.label_load_testdata)) self.threadAnim_load_testdata.start() self.threadWork_load_testdata.start() def check_function_get_tested_values(self): self.threadAnim_get_tested_values = AnimationTimer(0.3) self.threadWork_get_tested_values = QtCore.QThread() self.QObject_get_tested_values = Check_function( self.neuralconfig, 'get_tested_values') self.QObject_get_tested_values.moveToThread( self.threadWork_get_tested_values) self.threadWork_get_tested_values.started.connect( self.QObject_get_tested_values.run) self.QObject_get_tested_values.function_checked_signal.connect( self.update_status) self.QObject_get_tested_values.error_signal.connect(self.errorprint) self.QObject_get_tested_values.return_new_state.connect( self.update_NeuralCrash) self.QObject_get_tested_values.done.connect( self.threadAnim_get_tested_values.requestInterruption) self.QObject_get_tested_values.done.connect( self.check_function_set_tested_values) self.threadAnim_get_tested_values.time_passes.connect( lambda: self.update_label(self.label_get_tested_values)) self.threadAnim_get_tested_values.start() self.threadWork_get_tested_values.start() def check_function_set_tested_values(self): self.threadAnim_set_tested_values = AnimationTimer(0.3) self.threadWork_set_tested_values = QtCore.QThread() self.QObject_set_tested_values = Check_function( self.neuralconfig, 'set_tested_values') self.QObject_set_tested_values.moveToThread( self.threadWork_set_tested_values) self.threadWork_set_tested_values.started.connect( self.QObject_set_tested_values.run) self.QObject_set_tested_values.function_checked_signal.connect( self.update_status) self.QObject_set_tested_values.error_signal.connect(self.errorprint) self.QObject_set_tested_values.done.connect( self.threadAnim_set_tested_values.requestInterruption) self.QObject_set_tested_values.done.connect( self.check_function_test_model) self.threadAnim_set_tested_values.time_passes.connect( lambda: self.update_label(self.label_set_tested_values)) self.threadAnim_set_tested_values.start() self.threadWork_set_tested_values.start() def check_function_test_model(self): self.threadAnim_test_model = AnimationTimer(0.3) self.threadWork_test_model = QtCore.QThread() self.QObject_test_model = Check_function(self.neuralconfig, 'test_model') self.QObject_test_model.moveToThread(self.threadWork_test_model) self.threadWork_test_model.started.connect(self.QObject_test_model.run) self.QObject_test_model.function_checked_signal.connect( self.update_status) self.QObject_test_model.error_signal.connect(self.errorprint) self.QObject_get_tested_values.return_new_state.connect( self.update_NeuralCrash) self.QObject_test_model.done.connect( self.threadAnim_test_model.requestInterruption) self.QObject_test_model.done.connect(self.end_checking) self.threadAnim_test_model.time_passes.connect( lambda: self.update_label(self.label_test_model)) self.threadAnim_test_model.start() self.threadWork_test_model.start() def end_checking(self): status_tuple = ( self.status_load_model, self.status_load_testdata, self.status_get_tested_values, self.status_set_tested_values, self.status_test_model, ) for status in status_tuple: if status != 'OK': return self.checking_ending.emit(self.neuralconfig)
class AppWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.setAttribute(Qt.WA_DeleteOnClose) self.setWindowTitle(progname) self.init_ui() self.network = None self.isDataLoaded = False self.training_data = None self.test_data = None self.predict_y = None self.networkSettings = None def init_ui(self): self.init_menus() self.init_toolbar(QSize(40, 40)) mainWidget = QWidget(self) mainbox = QHBoxLayout(mainWidget) # self.setLayout(mainbox) topFrame = QFrame(mainWidget) topFrame.setFrameShape(QFrame.StyledPanel) btmFrame = QFrame(mainWidget) btmFrame.setFrameShape(QFrame.StyledPanel) splitter = QSplitter(Qt.Vertical) splitter.addWidget(topFrame) splitter.addWidget(btmFrame) # logText 30%, Plot 70% splitter.setStretchFactor(0, 4) splitter.setStretchFactor(1, 1) mainbox.addWidget(splitter) self.init_plot_area(topFrame) vboxLog = QVBoxLayout(btmFrame) self.logTextEdit = QPlainTextEdit("") self.logTextEdit.appendHtml("""<font size='4'>欢迎使用{}</font><p>""".format(progname)) self.logTextEdit.setReadOnly(True) vboxLog.addWidget(self.logTextEdit) mainWidget.setFocus() self.setCentralWidget(mainWidget) self.statusBar().showMessage("Ready") self.setWindowIcon(QIcon('res/load_network.png')) self.show() def init_plot_area(self, parent): hboxPlot = QHBoxLayout(parent) # errplot_labels = {'t': u'供水温度预测误差', 'x': u'时间', 'y': u'误差百分比(%)'} # predplot_labels = {'t': u'供水温度预测值', 'x': u'时间', 'y': u'供水温度(℃)'} errplot_labels = {'t': 'Prediction Errors', 'x': 'Time', 'y': 'Error Percent(%)'} predplot_labels = {'t': 'Predicted Temperature', 'x': 'Time', 'y': 'Temperature(℃)'} self.errPlot = StaticMplotCanvas(parent, labels=errplot_labels) self.predPlot = StaticMplotCanvas(parent, labels=predplot_labels) hboxPlot.addWidget(self.errPlot) hboxPlot.addWidget(self.predPlot) def init_toolbar(self, iconSize): # data file self.loadDataAct = QAction(QIcon('res/load_data.png'), 'Import Training Data', self) self.loadDataAct.setShortcut('Ctrl+L') self.loadDataAct.triggered.connect(self.loadTrainingDataFile) self.saveDataAct = QAction(QIcon('res/save_data.png'), 'Export Predicted Data', self) self.saveDataAct.setShortcut('Ctrl+E') self.saveDataAct.triggered.connect(self.savePredictDataToFile) self.saveDataAct.setEnabled(False) # network self.loadNetworkAct = QAction(QIcon('res/load_network.png'), 'Load Trained Network', self) self.loadNetworkAct.setShortcut('Ctrl+N') self.loadNetworkAct.triggered.connect(self.restoreNeuralNetwork) self.loadNetworkAct.setEnabled(False) self.saveNetworkAct = QAction(QIcon('res/save_network.png'), 'Save Trained Network', self) self.saveNetworkAct.setShortcut('Ctrl+S') self.saveNetworkAct.triggered.connect(self.saveNeuralNetwork) self.saveNetworkAct.setEnabled(False) # run & predict self.runTrainingAct = QAction(QIcon('res/train_network.png'), 'Train Network', self) self.runTrainingAct.setShortcut('Ctrl+R') self.runTrainingAct.triggered.connect(self.runNetworkTraining) self.runTrainingAct.setEnabled(False) self.predictDatakAct = QAction(QIcon('res/predict.png'), 'Predict Data', self) self.predictDatakAct.setShortcut('Ctrl+P') self.predictDatakAct.triggered.connect(self.predictData) self.predictDatakAct.setEnabled(False) # clear self.resetAct = QAction(QIcon('res/clear.png'), 'Clear data and network', self) self.resetAct.setEnabled(False) self.resetAct.triggered.connect(self.clearDataAndNetwork) dataToolbar = self.addToolBar('Data ToolBar') dataToolbar.addAction(self.loadDataAct) dataToolbar.addAction(self.saveDataAct) dataToolbar.setIconSize(iconSize) networkToolbar = self.addToolBar('Network ToolBar') networkToolbar.addAction(self.loadNetworkAct) networkToolbar.addAction(self.runTrainingAct) networkToolbar.addAction(self.predictDatakAct) networkToolbar.addAction(self.saveNetworkAct) networkToolbar.setIconSize(iconSize) resetToolbar = self.addToolBar('Reset ToolBar') resetToolbar.addAction(self.resetAct) resetToolbar.setIconSize(iconSize) def init_menus(self): # File settingAct = QAction(QIcon('res/settings.png'), '设置', self) settingAct.triggered.connect(self.showSettingDialog) exitAct = QAction(QIcon('exit.png'), '退出', self) exitAct.setShortcut('Ctrl+Q') exitAct.triggered.connect(self.fileQuit) menubar = self.menuBar() fileMenu = menubar.addMenu('&File') fileMenu.addAction(settingAct) fileMenu.addSeparator() fileMenu.addAction(exitAct) # Help helpMenu = QMenu('&Help', self) self.menuBar().addMenu(helpMenu) helpMenu.addAction('使用说明', self.usage) helpMenu.addAction('关于', self.about) @pyqtSlot() def loadTrainingDataFile(self): fname, _ = QFileDialog.getOpenFileName(self, 'Open Training Data', '.', 'Data File(*.csv)') if not fname: # self.logStatus("加载数据文件{}失败!".format(fname), 'red', 'E') return dl = DataHandler(fname) self.training_data, self.test_data = dl.load(cb=self.logStatus) self.isDataLoaded = True self.runTrainingAct.setEnabled(True) self.loadNetworkAct.setEnabled(True) self.resetAct.setEnabled(True) self.logStatus("加载数据文件{}成功".format(fname)) self.logStatus('请训练神经网络或者加载已经训练的神经网络模型', '#FF8C00', 'T') @pyqtSlot() def savePredictDataToFile(self): if self.predict_y is None: # self.logStatus('没有未保存的预测数据, 请先进行数据预测!', 'red', 'E') return fname, _ = QFileDialog.getSaveFileName(self, 'Save Predicted Data', '.', 'Data File(*.csv)') if not fname: self.logStatus('保存预测数据文件{}失败!'.format(fname), 'red', 'E') return test_x, _ = DataHandler.split_xy(self.test_data) status = DataHandler.save(np.concatenate((test_x, self.predict_y), axis=0), fname) if status: self.logStatus('保存预测数据文件{}成功'.format(fname)) @pyqtSlot() def restoreNeuralNetwork(self): fname, _ = QFileDialog.getOpenFileName(self, 'Open Network File', '.', 'Network File(*.nf)') if not fname: # self.logStatus('打开神经网络文件{}失败!'.format(fname), 'red', 'E') return # clear previous plots self.clearPlots() training_x, training_y = DataHandler.split_xy(self.training_data) self.network = NeuralNetwork(training_x, training_y) try: self.network.load(fname) except ShapeError as e: self.logStatus('加载神经网络文件{}失败!'.format(fname), 'red', 'E') QMessageBox.warning(self, '警告', '加载神经网络文件失败, 请检查文件格式是否正确!') return self.logStatus('神经网络文件{}加载成功'.format(fname)) self.predictDatakAct.setEnabled(True) self.logStatus('请执行数据预测', '#FF8C00', 'T') @pyqtSlot() def saveNeuralNetwork(self): fname, _ = QFileDialog.getSaveFileName(self, 'Save Network File', '.', 'Network File(*.nf)') if not fname: # self.logStatus('保存神经网络文件{}失败!'.format(fname), 'red', 'E') return self.network.dump(fname) self.logStatus('保存神经网络文件{}成功'.format(fname)) @pyqtSlot() def runNetworkTraining(self): if self.network is not None: ans = QMessageBox.question(self, '警告', '系统中已存在训练好的神经网络,请问您需要重新训练神经网络吗?') if ans == QMessageBox.No: return # clear previous plots self.clearPlots() self.logStatus("正在初始化神经网络结构...", 'blue', 'I') training_x, training_y = DataHandler.split_xy(self.training_data) # retrieve settings epoch0 = 2000 tol0 = 0.1 retry_num = 3 h0size = 4 h1size = 4 if self.networkSettings: epoch0 = self.networkSettings['epoch'] tol0 = self.networkSettings['tol'] retry_num = self.networkSettings['retry'] h0size = self.networkSettings['h0size'] h1size = self.networkSettings['h1size'] self.logStatus("神经网络信息:layer1={}, layer2={}, epoch0={}, retry={}, tol0={}" .format(h0size, h1size, epoch0, retry_num, tol0), 'blue', 'I') net = [(training_x.shape[0], ''), (h0size, 'sigmoid'), (h1size, 'sigmoid'), (1, 'feedthrough')] try: self.network = NeuralNetwork(training_x, training_y, sizes=net) except ShapeError as e: self.logStatus('初始化神经网络结构失败!') QMessageBox.warning(self, '警告', '初始化神经网络结构失败, 请重试!') return # training mu0 = 0.1 beta = 10 retry = 0 self.logStatus("使用LM算法开始训练神经网络...", 'blue', 'I') while retry < retry_num: residual, mu, citer, msg = \ self.network.train(retry=retry, epoch=epoch0, mu0=mu0, beta=beta, tol=tol0, cb=self.logStatus) if residual is None: if retry == (retry_num - 1): self.logStatus("训练失败!".format(msg), 'red', 'E') return else: self.logStatus("训练失败:{}, 重试中...".format(msg), '#FFA07A', 'I') self.network.randomize_wb() # continue elif residual > tol0: if retry == (retry_num - 1): self.logStatus("训练失败!".format(msg), 'red', 'E') return else: self.logStatus("训练失败: 运算未能收敛, 重试中...", '#FFA07A', 'I') self.network.randomize_wb() # continue else: self.logStatus("神经网络训练完成, 迭代次数={1}, 最终残差={0}" .format(residual, citer+retry*epoch0), 'blue', 'I') break retry += 1 self.predictDatakAct.setEnabled(True) self.saveNetworkAct.setEnabled(True) self.logStatus('请执行数据预测', '#FF8C00', 'T') @pyqtSlot() def predictData(self): # don't forget to clear previous plots self.clearPlots() self.logStatus("开始进行数据预测...", 'blue', 'I') test_x, test_y = DataHandler.split_xy(self.test_data, False) self.predict_y = self.network.predict(test_x) self.logStatus("开始计算误差...", 'blue', 'I') self.predPlot.update_plot(x=np.arange(len(self.predict_y[0])), y=self.predict_y[0]) # error plot err_percent = (self.predict_y - test_y) * 100.0 / test_y self.errPlot.error_plot(x=np.arange(len(err_percent[0])), y=err_percent[0]) abs_err = np.abs(err_percent) self.logStatus("数据预测完成, 最大绝对值误差={}%, 平均绝对值误差={}%" .format(abs_err.max(), abs_err.mean()), 'blue', 'I') self.saveDataAct.setEnabled(True) @pyqtSlot() def clearDataAndNetwork(self): ans = QMessageBox.question(self, '警告', '您希望删除所有的数据和已经训练好的神经网络吗?') if ans == QMessageBox.No: return # reset self.network = None self.isDataLoaded = False self.training_data = None self.test_data = None # update UI self.loadNetworkAct.setEnabled(False) self.runTrainingAct.setEnabled(False) self.saveDataAct.setEnabled(False) self.saveNetworkAct.setEnabled(False) self.predictDatakAct.setEnabled(False) self.resetAct.setEnabled(False) self.logTextEdit.clear() # clear plots self.clearPlots() @pyqtSlot(dict) def updateSettings(self, settings): self.networkSettings = settings @pyqtSlot() def showSettingDialog(self): dlg = SettingDialog(self, self.networkSettings) dlg.show() @pyqtSlot() def fileQuit(self): self.close() @pyqtSlot() def about(self): QMessageBox.about(self, "关于", """<b>{}</b><p>版本号: {}""".format(progname, progversion) ) @pyqtSlot() def usage(self): dlg = UsageDialog(self) dlg.show() def closeEvent(self, ce): self.fileQuit() def logStatus(self, text, color='green', tag='S'): self.logTextEdit.appendHtml("<p><font color='{0}'><b>[{1}]:</b> {2}" "</font></p>".format(color, tag, text)) # force UI update. An alternative is to use QThread QApplication.processEvents() def clearPlots(self): self.predPlot.clear() self.errPlot.clear() errplot_labels = {'t': 'Prediction Errors', 'x': 'Time', 'y': 'Error Percent(%)'} predplot_labels = {'t': 'Predicted Temperature', 'x': 'Time', 'y': 'Temperature(℃)'} self.errPlot.initial_figure(errplot_labels) self.predPlot.initial_figure(predplot_labels)
def __init__(self, parent=None): QMainWindow.__init__(self, parent) self._settings = QSettings() self._logger = logging.getLogger(self.__class__.__name__) self.setWindowTitle("Processing") self.setWindowIcon(QIcon(get_resource("processing.png"))) self.mainFrame = QWidget(self) self.resize(1000, 600) # toolbar self.toolBar = QToolBar("file control") self.toolBar.setIconSize(QSize(24, 24)) self.addToolBar(self.toolBar) self.actLoad = QAction(self) self.actLoad.setText("load result file") self.actLoad.setIcon(QIcon(get_resource("load.png"))) self.actLoad.setDisabled(False) self.actLoad.triggered.connect(self.load_result_files) self.actPostLoad = QAction(self) self.actPostLoad.setText("load post-result file") self.actPostLoad.setIcon(QIcon(get_resource("load.png"))) self.actPostLoad.setDisabled(False) self.actPostLoad.triggered.connect(self.load_post_result_files) self.actSwitch = QAction(self) self.actSwitch.setText("switch display mode") self.actSwitch.setIcon(QIcon(get_resource("left_mode.png"))) self.actSwitch.setDisabled(False) self.actSwitch.triggered.connect(self.switch_sides) self.displayLeft = True self.spacer1 = QWidget() self.spacer2 = QWidget() self.spacer1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.actReloadMethods = QAction(self) self.actReloadMethods.setText("reload methods") self.actReloadMethods.setIcon(QIcon(get_resource("reload.png"))) self.actReloadMethods.setDisabled(False) self.actReloadMethods.triggered.connect(self.update_post_method_list) self.actReloadMetaMethods = QAction(self) self.actReloadMetaMethods.setText("reload meta methods") self.actReloadMetaMethods.setIcon(QIcon(get_resource("reload.png"))) self.actReloadMetaMethods.setDisabled(False) self.actReloadMetaMethods.triggered.connect( self.update_meta_method_list) self.toolBar.addAction(self.actLoad) self.toolBar.addAction(self.actReloadMethods) self.toolBar.addWidget(self.spacer1) self.toolBar.addAction(self.actSwitch) self.toolBar.addWidget(self.spacer2) self.toolBar.addAction(self.actReloadMetaMethods) self.toolBar.addAction(self.actPostLoad) # main window self.grid = QGridLayout(self.mainFrame) self.grid.setColumnMinimumWidth(0, 70) self.grid.setColumnStretch(0, 0) self.grid.setColumnStretch(1, 1) self.methodList = QListWidget(self) self.methodList.itemDoubleClicked.connect(self.post_processor_clicked) self.update_post_method_list() self.metaMethodList = QListWidget(self) self.metaMethodList.itemDoubleClicked.connect( self.meta_processor_clicked) self.update_meta_method_list() self.sim_result_list = QListWidget(self) self.sim_results_changed.connect(self.update_result_list) self.results = [] self.delShort = QShortcut(QKeySequence(Qt.Key_Delete), self.sim_result_list) self.delShort.activated.connect(self.remove_result_item) # figures self._figure_dict = {} self.figures_changed.connect(self.update_figure_lists) self.post_figure_list = QListWidget(self) self.post_figure_list.currentItemChanged.connect( self.current_figure_changed) self.meta_figure_list = QListWidget(self) self.meta_figure_list.currentItemChanged.connect( self.current_figure_changed) self.plotView = QWidget() self.lastFigure = None self.post_result_list = QListWidget(self) self.post_results_changed.connect(self.update_post_result_list) self.post_results = [] self.delShortPost = QShortcut(QKeySequence(Qt.Key_Backspace), self.post_result_list) self.delShortPost.activated.connect(self.remove_post_result_item) # log dock self.logBox = QPlainTextEdit(self) self.logBox.setReadOnly(True) # init logger for logging box self.textLogger = PlainTextLogger(logging.INFO) self.textLogger.set_target_cb(self.logBox.appendPlainText) logging.getLogger().addHandler(self.textLogger) self.grid.addWidget(QLabel("Result Files:"), 0, 0) self.grid.addWidget(self.sim_result_list, 1, 0) self.grid.addWidget(QLabel("Postprocessors:"), 2, 0) self.grid.addWidget(self.methodList, 3, 0) self.grid.addWidget(QLabel("Figures:"), 4, 0) self.grid.addWidget(self.post_figure_list, 5, 0) self.grid.addWidget(QLabel("Selected Figure:"), 0, 1) self.grid.addWidget(QLabel("Postprocessor Files:"), 0, 2) self.grid.addWidget(self.post_result_list, 1, 2) self.grid.addWidget(QLabel("Metaprocessors:"), 2, 2) self.grid.addWidget(self.metaMethodList, 3, 2) self.grid.addWidget(QLabel("Figures:"), 4, 2) self.grid.addWidget(self.meta_figure_list, 5, 2) self.grid.addWidget(self.logBox, 6, 0, 1, 3) self.mainFrame.setLayout(self.grid) self.setCentralWidget(self.mainFrame) # status bar self.statusBar = QStatusBar(self) self.setStatusBar(self.statusBar)
def __init__(self, parent: QWidget = None) -> None: super().__init__(parent) self._connected_sensors = {} self.resize(700, 500) # Varibles for PowerReport self.window_power_r = None self.power_config_name = [] self.power_config_id = [] self.power_th = [] self.power_pol = [] self.power_data_acc = False # debug messages self.debug_label = QLabel(self.tr('Debug')) self.debug_textedit = QPlainTextEdit() self.debug_textedit.setReadOnly(True) self.debug_label.setBuddy(self.debug_textedit) self._debug = CustomDebug(self.debug_textedit) # Refresh COM Ports self.refresh_com_ports_btn = QPushButton(self.tr('Refresh')) self.refresh_com_ports_btn.pressed.connect(self.update_com_ports) # Refresh COM Ports self.connect_btn = QPushButton(self.tr('Connect')) self.connect_btn.pressed.connect(self.on_connect_btn_pressed) # Port Combobox self.port_label = QLabel(self.tr('COM Port:')) self.port_combobox = QComboBox() self.port_label.setBuddy(self.port_combobox) self.port_combobox.currentIndexChanged.connect( self.on_port_combobox_change) self.update_com_ports() # Connect and Disconnect Buttons self.connect_btn = QPushButton(self.tr('Connect')) self.disconnect_btn = QPushButton(self.tr('Disconnect')) self.disconnect_btn.setVisible(False) self.connect_btn.pressed.connect(self.on_connect_btn_pressed) self.disconnect_btn.pressed.connect(self.on_disconnect_btn_pressed) # New Configuration Button self.new_config_btn = QPushButton(self.tr('New')) self.new_config_btn.setVisible(False) self.new_config_btn.pressed.connect(self.on_new_config_pressed) # Test connection self.test_btn = QPushButton(self.tr('Test')) self.test_btn.setVisible(False) self.connect_btn.pressed.connect(self.on_test_btn_pressed) # poll messages # Enabled? # self.poll_checkbox = QCheckBox("Poll?", self) # self.poll_checkbox.stateChanged.connect(self.click_poll_sensor) # Seconds self.poll_label = QLabel(self.tr('Poll interval (minutes):')) self.poll_lineedit = QLineEdit() self.poll_label.setBuddy(self.poll_lineedit) self.poll_label.setVisible(False) self.poll_lineedit.setEnabled(True) self.poll_lineedit.setVisible(False) # self.poll_lineedit.returnPressed.connect(self.) # threshold # per metric # Enabled? self.threshold_label_1 = QLabel(self.tr('Metric 1:')) self.threshold_label_2 = QLabel(self.tr('Metric 2:')) self.threshold_label_2.setVisible(False) self.threshold_label_3 = QLabel(self.tr('Metric 3:')) self.threshold_label_3.setVisible(True) self.threshold_label_4 = QLabel(self.tr('Metric 4:')) self.threshold_label_4.setVisible(True) self.threshold_checkbox_1 = QCheckBox("Threshold ?", self) self.threshold_checkbox_1.stateChanged.connect( self.click_threshold_checkbox_1) self.threshold_checkbox_1.setVisible(False) self.threshold_checkbox_2 = QCheckBox("Threshold ?", self) self.threshold_checkbox_2.stateChanged.connect( self.click_threshold_checkbox_2) self.threshold_checkbox_2.setVisible(False) self.threshold_checkbox_3 = QCheckBox("Threshold ?", self) self.threshold_checkbox_3.stateChanged.connect( self.click_threshold_checkbox_3) self.threshold_checkbox_3.setVisible(False) self.threshold_checkbox_4 = QCheckBox("Threshold ?", self) self.threshold_checkbox_4.stateChanged.connect( self.click_threshold_checkbox_4) self.threshold_checkbox_4.setVisible(False) # threshold high self.threshold_high_label_1 = QLabel(self.tr('High:')) self.threshold_high_lineedit_1 = QLineEdit() self.threshold_high_label_1.setBuddy(self.threshold_high_lineedit_1) self.threshold_high_lineedit_1.setEnabled(True) self.threshold_high_label_2 = QLabel(self.tr('High:')) self.threshold_high_lineedit_2 = QLineEdit() self.threshold_high_label_2.setBuddy(self.threshold_high_lineedit_2) self.threshold_high_lineedit_2.setEnabled(True) self.threshold_high_label_3 = QLabel(self.tr('High:')) self.threshold_high_lineedit_3 = QLineEdit() self.threshold_high_label_3.setBuddy(self.threshold_high_lineedit_3) self.threshold_high_lineedit_3.setEnabled(True) self.threshold_high_label_4 = QLabel(self.tr('High:')) self.threshold_high_lineedit_4 = QLineEdit() self.threshold_high_label_4.setBuddy(self.threshold_high_lineedit_4) self.threshold_high_lineedit_4.setEnabled(True) # threshold Low self.threshold_low_label_1 = QLabel(self.tr('Low:')) self.threshold_low_lineedit_1 = QLineEdit() self.threshold_low_label_1.setBuddy(self.threshold_low_lineedit_1) self.threshold_low_lineedit_1.setEnabled(True) self.threshold_low_label_2 = QLabel(self.tr('Low:')) self.threshold_low_lineedit_2 = QLineEdit() self.threshold_low_label_2.setBuddy(self.threshold_low_lineedit_2) self.threshold_low_lineedit_2.setEnabled(True) self.threshold_low_label_3 = QLabel(self.tr('Low:')) self.threshold_low_lineedit_3 = QLineEdit() self.threshold_low_label_3.setBuddy(self.threshold_low_lineedit_3) self.threshold_low_lineedit_3.setEnabled(True) self.threshold_low_label_4 = QLabel(self.tr('Low:')) self.threshold_low_lineedit_4 = QLineEdit() self.threshold_low_label_4.setBuddy(self.threshold_low_lineedit_4) self.threshold_low_lineedit_4.setEnabled(True) # Sensor Combobox self.sensor_label = QLabel(self.tr('Sensor:')) self.sensor_combobox = QComboBox() self.sensor_label.setBuddy(self.sensor_combobox) self.sensor_combobox.currentIndexChanged.connect( self.on_sensor_combobox_change) self.update_com_ports() self.sensor_btn = QPushButton(self.tr('Load')) self.sensor_btn.setVisible(False) self.sensor_btn.pressed.connect(self.on_sensor_btn_pressed) # Save and Disconnect Buttons self.save_btn = QPushButton(self.tr('Save')) # disable visivibility and only show when there is a connection self.save_btn.setVisible(False) self.disconnect_btn = QPushButton(self.tr('Disconnect')) self.disconnect_btn.setVisible(False) self.save_btn.pressed.connect(self.on_save_btn_pressed) self.disconnect_btn.pressed.connect(self.on_disconnect_btn_pressed) # Power Report Button # self.power_report_btn = QPushButton(self.tr('Power Report')) # self.power_report_btn.setVisible(False) # self.power_report_btn.pressed.connect(self.on_power_report_btn_pressed) # Data Accumulation Enabling/Disabling self.accumulation_checkbox = QCheckBox("Data Accumulation ?", self) self.accumulation_checkbox.stateChanged.connect(self.click_accumulation_checkbox) self.accumulation_checkbox.setVisible(False) # Arrange Layout layout = QGridLayout() # COM Port line layout.addWidget(self.port_label, 0, 0) layout.addWidget(self.port_combobox, 0, 1, 1, 3) layout.addWidget(self.connect_btn, 0, 4) layout.addWidget(self.refresh_com_ports_btn, 0, 5) # layout.addWidget(self.port_motherboard, 0, 1, 2) # Sensors line layout.addWidget(self.sensor_label, 1, 0) layout.addWidget(self.sensor_combobox, 1, 1, 1, 3) layout.addWidget(self.sensor_btn, 1, 4) layout.addWidget(self.save_btn, 1, 5) # Polling line # layout.addWidget(self.poll_checkbox, 2, 0) layout.addWidget(self.poll_label, 3, 1) layout.addWidget(self.poll_lineedit, 3, 2) # threshold line layout.addWidget(self.threshold_label_1, 4, 0) layout.addWidget(self.threshold_checkbox_1, 4, 1) layout.addWidget(self.threshold_high_label_1, 4, 2) layout.addWidget(self.threshold_high_lineedit_1, 4, 3) layout.addWidget(self.threshold_low_label_1, 4, 4) layout.addWidget(self.threshold_low_lineedit_1, 4, 5) layout.addWidget(self.threshold_label_2, 5, 0) layout.addWidget(self.threshold_checkbox_2, 5, 1) layout.addWidget(self.threshold_high_label_2, 5, 2) layout.addWidget(self.threshold_high_lineedit_2, 5, 3) layout.addWidget(self.threshold_low_label_2, 5, 4) layout.addWidget(self.threshold_low_lineedit_2, 5, 5) layout.addWidget(self.threshold_label_3, 6, 0) layout.addWidget(self.threshold_checkbox_3, 6, 1) layout.addWidget(self.threshold_high_label_3, 6, 2) layout.addWidget(self.threshold_high_lineedit_3, 6, 3) layout.addWidget(self.threshold_low_label_3, 6, 4) layout.addWidget(self.threshold_low_lineedit_3, 6, 5) layout.addWidget(self.threshold_label_4, 7, 0) layout.addWidget(self.threshold_checkbox_4, 7, 1) layout.addWidget(self.threshold_high_label_4, 7, 2) layout.addWidget(self.threshold_high_lineedit_4, 7, 3) layout.addWidget(self.threshold_low_label_4, 7, 4) layout.addWidget(self.threshold_low_lineedit_4, 7, 5) # Debug layout.addWidget(self.debug_label, 8, 0) layout.addWidget(self.debug_textedit, 9, 0, 1, 6) # Save and disconnect layout layout.addWidget(self.disconnect_btn, 10, 4) layout.addWidget(self.test_btn, 10, 5) # Power Report Button # layout.addWidget(self.power_report_btn, 10, 0) # Accumulation Checkbox layout.addWidget(self.accumulation_checkbox, 2, 1) # New Configuration Button layout.addWidget(self.new_config_btn, 10, 4) self.remove_metric_rows_from_gui() self.setLayout(layout) # self._load_settings() self._debug.write("GUI", "Application started successfully") self._debug.write("GUI", VERSION) self.update_com_ports()
class ApplyAdoptDialog(QDialog): def __init__(self, UserId): super(ApplyAdoptDialog, self).__init__() self.userid = UserId self.initUI() def initUI(self): self.resize(400, 350) self.setWindowTitle("myPet——宠物领养") self.setWindowIcon(QIcon("./images/icon.png")) self.idlabel = QLabel(self) self.idlabel.setText("备案编号:") self.idlabel.setFont(QFont("苏新诗柳楷繁", 15)) self.idedit = QLineEdit() self.idedit.setFixedSize(300, 35) self.idedit.setFont(QFont("苏新诗柳楷繁", 13)) self.h1box = QHBoxLayout() self.h1box.addStretch(1) self.h1box.addWidget(self.idlabel) self.h1box.addStretch(1) self.h1box.addWidget(self.idedit) self.h1box.addStretch(1) self.textlabel = QLabel(self) self.textlabel.setText("申请理由:") self.textlabel.setFont(QFont("苏新诗柳楷繁", 15)) self.textedit = QPlainTextEdit() self.textedit.setFixedSize(300, 150) self.textedit.setFont(QFont("苏新诗柳楷繁", 13)) self.h2box = QHBoxLayout() self.h2box.addStretch(1) self.h2box.addWidget(self.textlabel) self.h2box.addStretch(1) self.h2box.addWidget(self.textedit) self.h2box.addStretch(1) self.submitbutton = QPushButton() self.submitbutton.setText("申请领养") self.submitbutton.setFixedSize(150, 35) self.submitbutton.setFont(QFont("苏新诗柳楷繁", 15)) self.submitbutton.clicked.connect(self.submit) self.h3box = QHBoxLayout() self.h3box.addStretch(1) self.h3box.addWidget(self.submitbutton) self.h3box.addStretch(1) self.vbox = QVBoxLayout() self.vbox.addStretch(1) self.vbox.addLayout(self.h1box) self.vbox.addStretch(1) self.vbox.addLayout(self.h2box) self.vbox.addStretch(1) self.vbox.addLayout(self.h3box) self.vbox.addStretch(1) self.setLayout(self.vbox) def submit(self): self.adoptid = 'a' + str(time.strftime("%g%m%d")) + str( random.randint(0, 9999)).zfill(4) self.petid = self.idedit.text() self.adopttext = self.textedit.toPlainText() now = int(time.time()) timeStruct = time.localtime(now) self.strTime = time.strftime("%Y/%m/%d %H:%M", timeStruct) db = QSqlDatabase.addDatabase("QSQLITE") db.setDatabaseName("./db/myPet.db") db.open() query = QSqlQuery() sql = "select * from user where UserId = '%s' and UserAuthority = '黑名单'" % ( self.userid) query.exec_(sql) if (query.next()): print( QMessageBox.warning(self, "警告", "你是黑名单用户,无法申请宠物领养!", QMessageBox.Yes, QMessageBox.Yes)) return sql = "select * from user where UserId = '%s' and UserAuthority = '灰名单'" % ( self.userid) query.exec_(sql) if (query.next()): print( QMessageBox.warning(self, "警告", "你是灰名单用户,无法申请宠物领养!", QMessageBox.Yes, QMessageBox.Yes)) return if (self.petid == ""): print( QMessageBox.warning(self, "警告", "请输入备案编号!", QMessageBox.Yes, QMessageBox.Yes)) return #先查看拟定领养宠物是否存在 sql = "select * from pet where PetId = '%s'" % (self.petid) query.exec_(sql) if (query.next()): #查看是否为自己领养自己的宠物 sql = "select * from pet where PetId = '%s' and ReleaseUserId = '%s'" % ( self.petid, self.userid) query.exec_(sql) if (query.next()): print( QMessageBox.warning(self, "警告", "请勿申请领养自己发布的宠物", QMessageBox.Yes, QMessageBox.Yes)) return #查看宠物是否是已领养状态 sql = "select * from pet where PetId = '%s' and PetStatus = '已领养'" % ( self.petid) query.exec_(sql) if (query.next()): print( QMessageBox.warning(self, "警告", "宠物已被领养,无法提交申请!", QMessageBox.Yes, QMessageBox.Yes)) return #查看领养编号是否重复 sql = "select * from adoptapply where AdoptApplyId = '%s'" % ( self.adoptid) query.exec_(sql) if (query.next()): print( QMessageBox.warning(self, "警告", "系统出错,请稍后尝试", QMessageBox.Yes, QMessageBox.Yes)) return #查看是否已存在申请用户和申请宠物相同 且申请状态为“审核中”的 sql = "select * from adoptapply where AdoptFromId = '%s' " \ "and AdoptPetId = '%s' and AdoptStatus = '审核中'" %(self.userid,self.petid) query.exec_(sql) if (query.next()): print( QMessageBox.warning(self, "警告", "您对该宠物有申请正在审核中,请勿重复提交", QMessageBox.Yes, QMessageBox.Yes)) return sql = "insert into adoptapply values('%s','%s','%s','审核中','%s','%s')" % ( self.adoptid, self.userid, self.petid, self.adopttext, self.strTime) query.exec_(sql) db.commit() db.close() print( QMessageBox.information(self, "提醒", "你已成功提交宠物领养申请", QMessageBox.Yes, QMessageBox.Yes)) self.idedit.setText("") self.textedit.clear() else: print( QMessageBox.warning(self, "警告", "您输入的宠物备案编号并不存在,请重新输入", QMessageBox.Yes, QMessageBox.Yes)) return
class PlateRecognize(QDialog): def __init__(self): super(PlateRecognize,self).__init__() self.text = "" self.strTime = "" self.plateid = "" self.filePath = "" self.initUI() def initUI(self): self.resize(700,600) self.setWindowTitle("myOCR——车牌识别") self.setWindowIcon(QIcon("./images/Icon.png")) self.plabel = QLabel(self) self.plabel.setFixedSize(400,300) self.obtn = QPushButton(self) self.obtn.setText("打开本地图片") self.obtn.setFont(QFont("苏新诗柳楷繁", 15)) self.obtn.clicked.connect(self.openimage) self.obtn.setFixedSize(180,40) self.sbtn = QPushButton(self) self.sbtn.setText("开 始 识 别") self.sbtn.setFont(QFont("苏新诗柳楷繁", 15)) self.sbtn.clicked.connect(self.recognize) self.sbtn.setFixedSize(180,40) self.v1box = QVBoxLayout() self.v1box.addWidget(self.obtn) self.v1box.addWidget(self.sbtn) self.h1box = QHBoxLayout() self.h1box.addWidget(self.plabel) self.h1box.addLayout(self.v1box) self.tlabel = QLabel(self) self.tlabel.setText("识\n别\n结\n果") self.tlabel.setFont(QFont("苏新诗柳楷繁", 15)) self.tlabel.resize(200, 50) self.tedit = QPlainTextEdit(self) self.tedit.setFont(QFont("宋体",10)) self.tedit.setFixedSize(600,350) self.h2box = QHBoxLayout() self.h2box.addStretch(1) self.h2box.addWidget(self.tlabel) self.h2box.addStretch(1) self.h2box.addWidget(self.tedit) self.h2box.addStretch(1) self.vbox = QVBoxLayout() self.vbox.addLayout(self.h1box) self.vbox.addStretch(1) self.vbox.addLayout(self.h2box) self.setLayout(self.vbox) def openimage(self): self.filePath, imgType = QFileDialog.getOpenFileName(self, "打开本地图片", "", "*.jpg;;*.png;;All Files(*)") self.jpg = QtGui.QPixmap(self.filePath).scaled(self.plabel.width(), self.plabel.height()) self.plabel.setPixmap(self.jpg) def recognize(self): if(self.filePath == ""): print(QMessageBox.warning(self, "警告", "请插入图片", QMessageBox.Yes, QMessageBox.Yes)) return now = int(time.time()) timeStruct = time.localtime(now) self.strTime = time.strftime("%Y/%m/%d %H:%M", timeStruct) self.plateid = 'p' + str(time.strftime("%g%m%d")) + str(random.randint(0, 9999)).zfill(4) db = QSqlDatabase.addDatabase("QSQLITE") db.setDatabaseName('./db/myOCR.db') db.open() query = QSqlQuery() sql = "select * from records where RecordId = '%s'"%(self.plateid) query.exec_(sql) if (query.next()): print(QMessageBox.warning(self, "警告", "系统错误,请重新提交", QMessageBox.Yes, QMessageBox.Yes)) return result = aipOcr.licensePlate(self.get_file_content(self.filePath),options) plate = result['words_result']['number'] self.text = "车牌号码:" + plate sql = "insert into records values('%s','%s','%s','车牌识别','%s','')"%( self.plateid,self.filePath,self.strTime,self.text) query.exec_(sql) db.commit() db.close() print(QMessageBox.information(self, "提醒", "您已成功识别车牌!", QMessageBox.Yes, QMessageBox.Yes)) self.tedit.setPlainText(self.text) def get_file_content(self,filePath): with open(filePath, 'rb') as fp: return fp.read()
class UI(QWidget): def __init__(self): super().__init__() self.width: any = None self.height: any = None self.input_open_button: QPushButton = None self.input_clear_button: QPushButton = None self.input_list: QListWidget = None self.input_input_label: QLabel = None self.method_calculate_button: QPushButton = None self.method_reset_button: QPushButton = None self.method_combobox: QComboBox = None self.method_method_used_label: QLabel = None self.method_intial_interval_textbox: QPlainTextEdit = None self.output_save_button: QPushButton = None self.output_clear_button: QPushButton = None self.output_textbox: QPlainTextEdit = None self.output_output_label: QLabel = None # 3d self.figure1 = plt.figure() self.canvas1 = FigureCanvas(self.figure1) # 2d self.figure2 = plt.figure() self.canvas2 = FigureCanvas(self.figure2) # graph error message box self.graph_error_texbox: QPlainTextEdit = None self.grid_layout: QGridLayout = None self.hbox1: QHBoxLayout = None self.hbox2: QHBoxLayout = None self.hbox: QHBoxLayout = None self.vbox: QVBoxLayout = None self.open_file_location: str = os.path.dirname( os.path.abspath(__file__)) self.save_file_location: str = os.path.dirname( os.path.abspath(__file__)) self.methods = list(Methods.keys()) self.initUI() def initUI(self): self.grid_layout = QGridLayout() self.setLayout(self.grid_layout) self.grid_layout.setHorizontalSpacing(50) # create 5 blocks self.create_input_block() self.create_method_used_block() self.create_output_block() self.create_graph_block() self.setGeometry(170, 100, 1600, 75E0) #self.setMinimumSize(1600, 500) self.setWindowTitle('Project2-Optimization') self.width = self.frameGeometry().width() self.height = self.frameGeometry().height() self.show() def create_input_block(self): self.input_open_button = QPushButton("open") self.input_open_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.input_open_button.clicked.connect(self.open_file_dialog) self.input_clear_button = QPushButton("clear") self.input_clear_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.input_clear_button.clicked.connect(self.input_clear) self.input_input_label = QLabel('Input:') input_h_box = QHBoxLayout() input_h_box.addWidget(self.input_open_button) input_h_box.addSpacing(50) input_h_box.addWidget(self.input_clear_button) self.input_list = QListWidget() input_v_box = QVBoxLayout() input_v_box.addWidget(self.input_input_label) input_v_box.addWidget(self.input_list) input_v_box.addLayout(input_h_box) self.grid_layout.addLayout(input_v_box, 0, 0) def create_method_used_block(self): # Combo Box to be used self.method_combobox = QComboBox(self) self.method_combobox.addItems(self.methods) # Buttons to be used self.method_reset_button = QPushButton("reset") self.method_reset_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.method_reset_button.clicked.connect(self.method_reset) self.method_calculate_button = QPushButton("calculate") self.method_calculate_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.method_calculate_button.clicked.connect(self.method_calculate) # Qlabel to be used self.method_method_used_label = QLabel('Method Used:') self.method_intial_interval_textbox = QPlainTextEdit() method_h2_box = QHBoxLayout() method_h2_box.addWidget(self.method_reset_button) method_h2_box.addWidget(self.method_calculate_button) method_v_box = QVBoxLayout() method_v_box.addWidget(self.method_method_used_label) method_v_box.addWidget(self.method_combobox) method_v_box.addWidget(self.method_intial_interval_textbox) method_v_box.addLayout(method_h2_box) self.grid_layout.addLayout(method_v_box, 0, 1) def create_output_block(self): self.output_textbox = QPlainTextEdit(QWidget().resize(640, 480)) self.output_textbox.setReadOnly(True) self.output_save_button = QPushButton("save") self.output_save_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.output_save_button.clicked.connect(self.save_file_dialog) self.output_clear_button = QPushButton("clear") self.output_clear_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.output_clear_button.clicked.connect(self.output_clear) self.output_output_label = QLabel('Output:') output_h_box = QHBoxLayout() output_h_box.addWidget(self.output_save_button) output_h_box.addWidget(self.output_clear_button) output_v_box = QVBoxLayout() output_v_box.addWidget(self.output_output_label) output_v_box.addWidget(self.output_textbox) output_v_box.addLayout(output_h_box) self.grid_layout.addLayout(output_v_box, 1, 0, 1, 2) def create_graph_block(self): ''' plot some random stuff ''' self.figure1.suptitle('3d') self.figure2.suptitle('2d') self.canvas1.draw() self.canvas2.draw() # self.figure2.legend() self.graph_error_texbox = QPlainTextEdit('Default graph(NULL)') self.graph_error_texbox.setReadOnly(True) self.graph_error_texbox.setMinimumSize(640, 110) self.hbox1 = QHBoxLayout() self.hbox2 = QHBoxLayout() self.hbox = QHBoxLayout() self.vbox = QVBoxLayout() self.hbox1.addWidget(self.canvas1) self.hbox2.addWidget(self.canvas2) self.hbox.addLayout(self.hbox1) self.hbox.addLayout(self.hbox2) self.vbox.addLayout(self.hbox) self.vbox.addWidget(self.graph_error_texbox) self.grid_layout.addLayout(self.vbox, 0, 2, 2, 2) def open_file_dialog(self): filename, _ = QFileDialog.getOpenFileName(self, "Open file", self.open_file_location, "Text Files (*.txt)") temp_pos = filename.rfind('/') if temp_pos: self.open_file_location = filename[:temp_pos + 1] if filename: with open(filename, 'rb') as file: read_data = file.read() udatabtype = read_data.decode("utf-8") asciidatabtype = udatabtype.encode("ascii", "ignore") asciidata = asciidatabtype.decode("ascii") read_data_list = asciidata.splitlines() self.input_list.addItems(read_data_list) def save_file_dialog(self): filename, _ = QFileDialog.getSaveFileName(self, "Save File", self.save_file_location, "Text Files (*.txt)") temp_pos = filename.rfind('/') self.save_file_location = filename[:temp_pos + 1] if filename: with open(filename, 'w') as file: file.write(self.output_textbox.toPlainText()) self.output_clear() def input_clear(self): self.input_list.clear() def output_clear(self): # clear textbox self.output_textbox.clear() # clear graph ''' clear windows ''' plt.figure(1) plt.clf() plt.figure(2) plt.clf() plt.close('all') ''' plot some random stuff ''' self.figure1 = plt.figure() self.figure2 = plt.figure() self.canvas1 = FigureCanvas(self.figure1) self.canvas2 = FigureCanvas(self.figure2) self.figure1.suptitle('3d') self.figure2.suptitle('2d') self.canvas1.draw() self.canvas2.draw() self.grid_layout.removeItem(self.hbox1) self.grid_layout.removeItem(self.hbox2) self.grid_layout.removeItem(self.hbox) self.grid_layout.removeItem(self.vbox) self.graph_error_texbox.setPlainText('Default graph(NULL)') self.hbox1 = QHBoxLayout() self.hbox2 = QHBoxLayout() self.hbox = QHBoxLayout() self.vbox = QVBoxLayout() self.hbox1.addWidget(self.canvas1) self.hbox2.addWidget(self.canvas2) self.hbox.addLayout(self.hbox1) self.hbox.addLayout(self.hbox2) self.vbox.addLayout(self.hbox) self.vbox.addWidget(self.graph_error_texbox) self.grid_layout.addLayout(self.vbox, 0, 2, 2, 2) def method_reset(self): self.method_intial_interval_textbox.setPlainText('') self.method_combobox.setCurrentIndex(0) def method_calculate(self): initial_interval = self.method_intial_interval_textbox.toPlainText() method = self.method_combobox.currentText() equation_item = self.input_list.currentItem() if equation_item is None: self.output_textbox.setPlainText('No equation string detected!\n') return elif method == 'None----': self.output_textbox.setPlainText('Method couldnt be None\n') return elif initial_interval == '': self.output_textbox.setPlainText('No initial point\n') return # global variables equation_str: str = None initial_point: List[float] = None intervals: List[List[float]] = None answer: str = None Xs: List[Arrai] = None vars_form: List[str] = None # exception added try: equation_str = equation_item.text() # get initial point and intervals initial_point, vars_form, intervals = get_ip_intervals( initial_interval) # manager = Manager(equation_str, vars_form, method, initial_point, intervals) manager = Manager(equation_str=equation_str, vars_form=vars_form, method_name=method, initial_point=initial_point, intervals=intervals) answer, Xs = manager.run() # write answer to output self.output_textbox.setPlainText(answer) except Exception as explosion: answer = explosion.args[0] self.output_textbox.setPlainText(answer) try: # draw out graph draw_graph(self, equation_str, vars_form, Xs, intervals) # catch graph drawing exception except: self.graph_error_texbox.setPlainText( 'Error while building graph!\n Current Equation: %s' % equation_str) def resizeEvent(self, a0: QResizeEvent) -> None: HeightIncreasement = self.frameGeometry().height() - self.height temp_size = 30 if abs(HeightIncreasement) - temp_size >= 0: # no pointer could be used in python self.change_font(self.input_input_label, HeightIncreasement / temp_size) self.change_font(self.method_method_used_label, HeightIncreasement / temp_size) self.change_font(self.output_output_label, HeightIncreasement / temp_size) self.change_font(self.input_open_button, HeightIncreasement / temp_size) self.change_font(self.input_clear_button, HeightIncreasement / temp_size) self.change_font(self.method_calculate_button, HeightIncreasement / temp_size) self.change_font(self.method_reset_button, HeightIncreasement / temp_size) self.change_font(self.output_save_button, HeightIncreasement / temp_size) self.change_font(self.output_clear_button, HeightIncreasement / temp_size) self.change_font(self.method_combobox, HeightIncreasement / temp_size) self.width = self.frameGeometry().width() self.height = self.frameGeometry().height() @staticmethod def change_font(label: QLabel, increasement: int): font = label.font() font.setPointSize(font.pointSize() + increasement) if font.pointSize() > 8: label.setFont(font)
def __init__(self): super(MainWindow, self).__init__() self.commandslist = [] self.tracker = 0 os.chdir(os.path.expanduser("~")) # print(os.getcwd()) self.name = (str(getpass.getuser()) + "@" + str(socket.gethostname()) + ":" + str(os.getcwd()) + "$ ") self.setWindowTitle('PyQt5Terminal') self.setWindowIcon(QIcon.fromTheme("terminal-emulator")) self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.MergedChannels) self.process.readyRead.connect(self.dataReady) self.process.readyReadStandardError.connect( self.onReadyReadStandardError) self.process.readyReadStandardOutput.connect( self.onReadyReadStandardOutput) self.process.finished.connect(self.isFinished) self.process.setWorkingDirectory(os.getcwd()) self.createStatusBar() self.commandfield = QPlainTextEdit() self.commandfield.setLineWrapMode(QPlainTextEdit.NoWrap) self.commandfield.setFixedHeight(44) self.commandfield.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.commandfield.setAcceptDrops(True) self.cursor = self.commandfield.textCursor() self.textWindow = QPlainTextEdit(self) self.setStyleSheet(mystylesheet(self)) self.textWindow.setReadOnly(True) layout = QVBoxLayout() layout.addWidget(self.textWindow) layout.addWidget(self.commandfield) self.wid = QWidget() self.wid.setLayout(layout) self.setCentralWidget(self.wid) self.setGeometry(0, 0, 600, 500) self.commandfield.setPlainText(self.name) self.cursorEnd() self.commandfield.setFocus() self.copySelectedTextAction = QAction(QIcon.fromTheme("edit-copy"), "Copy", shortcut="Shift+Ctrl+c", triggered=self.copyText) self.textWindow.addAction(self.copySelectedTextAction) self.pasteTextAction = QAction(QIcon.fromTheme("edit-paste"), "Copy", shortcut="Shift+Ctrl+v", triggered=self.pasteText) self.commandfield.addAction(self.pasteTextAction) # self.cancelAction = QAction("Cancel", shortcut="Ctrl+c", triggered=self.killProcess) self.textWindow.addAction(self.cancelAction) self.commandfield.installEventFilter(self) # self.textWindow.installEventFilter(self) QApplication.setCursorFlashTime(1000) self.cursorEnd() print(self.process.workingDirectory()) self.settings = QSettings("QTerminal", "QTerminal") self.readSettings()
def __init__(self, parent=None): super().__init__(parent, windowTitle="parceqt debugger") f = self._updated_format = QTextCharFormat() c = QColor("palegreen") c.setAlpha(64) f.setBackground(c) f = self._currentline_format = QTextCharFormat() f.setProperty(QTextCharFormat.FullWidthSelection, True) self._actions = Actions(self) self._actions.add_menus(self.menuBar()) widget = QWidget(self) self.setCentralWidget(widget) layout = QVBoxLayout(margin=4, spacing=2) widget.setLayout(layout) top_layout = QHBoxLayout(margin=0, spacing=0) self.guessButton = QToolButton(self, clicked=self.guess_root_lexicon, toolTip="Guess Language", icon=self.style().standardIcon( QStyle.SP_BrowserReload)) self.lexiconChooser = LexiconChooser(self) self.ancestorView = AncestorView(self) top_layout.addWidget(self.guessButton) top_layout.addWidget(self.lexiconChooser) top_layout.addWidget(self.ancestorView) top_layout.addStretch(10) layout.addLayout(top_layout) self.guessButton.setFixedHeight( self.lexiconChooser.sizeHint().height()) splitter = QSplitter(self, orientation=Qt.Horizontal) layout.addWidget(splitter, 100) self.textEdit = QPlainTextEdit(lineWrapMode=QPlainTextEdit.NoWrap, cursorWidth=2) self.treeView = QTreeView() splitter.addWidget(self.textEdit) splitter.addWidget(self.treeView) splitter.setStretchFactor(0, 3) splitter.setStretchFactor(1, 2) self.extraSelectionManager = ExtraSelectionManager(self.textEdit) self.document = d = self.textEdit.document() self.textEdit.setDocument(self.document) self.worker = w = parceqt.worker(d) self.builder = b = w.builder() w.debugging = True self.setStatusBar(QStatusBar()) self.create_model() # signal connections self.textEdit.viewport().installEventFilter(self) self.textEdit.installEventFilter(self) self.lexiconChooser.lexicon_changed.connect( self.slot_root_lexicon_changed) self.ancestorView.node_clicked.connect(self.slot_node_clicked) w.started.connect(self.slot_build_started) w.tree_updated.connect(self.slot_build_updated) self.textEdit.cursorPositionChanged.connect( self.slot_cursor_position_changed) self.treeView.clicked.connect(self.slot_item_clicked) self.textEdit.setFocus() self.set_theme() # somewhat larger font by default font = self.textEdit.font() font.setPointSizeF(11) self.textEdit.setFont(font)
def initUI(self): self.setWindowTitle("Help Guide") self.resize(640, 480) #create output window self.helpListOutput = QPlainTextEdit(self) #self.helpListOutput.setReadOnly(True) self.helpListOutput.setGeometry(20, 40, 600, 360) #add close button self.helpQuitButton = QPushButton(self) self.helpQuitButton.setGeometry(220, 410, 200, 40) self.helpQuitButton.setText("Close") self.helpQuitButton.clicked.connect(self.close) #help topics content self.helpText = """RUN AUTOMATON To run the pushdown automaton, you must do the following: 1. Load the pushdown automaton definition file. ---This can be done by selecting the "File" menu from the top of the window and selecting "Open Automaton" from the menu. ---This will open a file browser to select the desired pushdown automaton definition file. 2. Select an input string to run the pushdown automaton on ---After loading the definition file, you must either manually add a valid input string or select an input string from the "Input String List" that was loaded from a "pda.str" text file containing input strings. 3. Click "Run String" ---After selecting the desired input string to be ran with the given pushdown automaton definition file, click the "Run String" button. ---Once the pushdown automaton has been started, the current state of the pushdown automaton as well as any results returned will be displayed in the output subwindow on the right side of the window. STOP AUTOMATON While the pushdown automaton is running, you have the option of stopping its execution on the input string by clicking the "Quit Running String" button just below the output window. If you have the pushdown automaton halt its execution, you may then select a different input string to be ran instead. If you are interested in loading a different definition file for the pushdown automaton, you may click the "Close Automaton" button below the output subwindow. This will cause the current pushdown automaton definition file to be unloaded, and a different definition file may be loaded using the same process as was done to load the original pushdown automaton definition file. Any error that are encountered will be shown at the bottom of the window in red, as well as giving more information about the error. LOAD AUTOMATON This command allows the user to select a definition file from the file browser. If the definition file is not present, an error message will be presented in the status label on the bottom right corner of the window. An input string list file is not required to be present in order to run load the pushdown automaton. INPUT STRING TEXT BOX This text box allows the user to create input strings manually. After entering a valid input string in this text box, click the ‘Add to List’ button to add the input string to the ‘Input String List’ that is below. If an invalid input string is provided, an error message will be presented on the bottom right corner of the application window, indicating such. INPUT STRING LIST This section shows the available input strings that can be ran with the pushdown automaton. To select an input string, click on the desired input string from the list shown. Once clicked, the selected input string will be highlighted. To run the input string with the currently loaded pushdown automaton, click the ‘Run String’ button at the bottom of the window. An input string must be selected from this list to be run with the pushdown automaton. If there aren’t any input strings in this list, one will have to be added manually using the ‘Input String’ textbox above. OUTPUT WINDOW The results of running the pushdown automaton will be displayed within this box on the right side of the application window. These results include the progress of the pushdown automaton as it is running as well as the final results of running the selected input string with the current pushdown automaton. To the right of the output section is a tall and narrow section which indicated the current and running contents of the stack within the pushdown automaton. MAX TRANSITIONS This option indicated the maximum number of transitions to be allowed while running the pushdown automaton. This option can be changed by clicking on the arrows to the right of the number just to the right of the ‘Max. Transit’ label. This number cannot be less than 1. DISPLAY PATH TEXT This checkbox determines whether you want to show the path of the pushdown automaton. If this box is checked, the path will be displayed at the bottom of the output section. QUIT RUNNING BUTTON This button will force the pushdown automaton to stop running on the selected input string.""" self.helpListOutput.setPlainText(self.helpText) self.show()
class MYGUI(QWidget): def __init__(self): super().__init__() self.exit_flag = False self.try_time = 1527652647.6671877 + 24 * 60 * 60 self.initUI() def initUI(self): self.pdf_label = QLabel("PDF文件夹路径: ") self.pdf_btn = QPushButton("选择") self.pdf_btn.clicked.connect(self.open_pdf) self.pdf_path = QLineEdit("PDF文件夹路径...") self.pdf_path.setEnabled(False) self.excel_label = QLabel("Excel Demo 路径: ") self.excel_btn = QPushButton("选择") self.excel_btn.clicked.connect(self.open_excel) self.excel_path = QLineEdit("Excel Demo路径...") self.excel_path.setEnabled(False) self.output_label = QLabel("输出路径: ") self.output_path = QLineEdit(os.path.abspath("./")) self.output_path.setEnabled(False) self.output_btn = QPushButton("选择") self.output_btn.clicked.connect(self.open_output) self.info = QPlainTextEdit() h1 = QHBoxLayout() h1.addWidget(self.pdf_label) h1.addWidget(self.pdf_path) h1.addWidget(self.pdf_btn) h2 = QHBoxLayout() h2.addWidget(self.excel_label) h2.addWidget(self.excel_path) h2.addWidget(self.excel_btn) h3 = QHBoxLayout() h3.addWidget(self.output_label) h3.addWidget(self.output_path) h3.addWidget(self.output_btn) self.run_btn = QPushButton("运行") self.run_btn.clicked.connect(self.run) self.auth_label = QLabel("密码") self.auth_ed = QLineEdit("test_mode") exit_btn = QPushButton("退出") exit_btn.clicked.connect(self.Exit) h4 = QHBoxLayout() h4.addWidget(self.auth_label) h4.addWidget(self.auth_ed) h4.addStretch(1) h4.addWidget(self.run_btn) h4.addWidget(exit_btn) v = QVBoxLayout() v.addLayout(h1) v.addLayout(h2) v.addLayout(h3) v.addWidget(self.info) v.addLayout(h4) self.setLayout(v) width = int(QDesktopWidget().screenGeometry().width() / 3) height = int(QDesktopWidget().screenGeometry().height() / 3) self.setGeometry(100, 100, width, height) self.setWindowTitle('PDF to Excel') self.show() def Exit(self): self.exit_flag = True qApp.quit() def open_pdf(self): fname = QFileDialog.getExistingDirectory(self, "Open pdf folder", "/home") if fname: self.pdf_path.setText(fname) def open_excel(self): fname = QFileDialog.getOpenFileName(self, "Open demo excel", "/home") if fname[0]: self.excel_path.setText(fname[0]) def open_output(self): fname = QFileDialog.getExistingDirectory(self, "Open output folder", "/home") if fname: self.output_path.setText(fname) def run(self): self.info.setPlainText("") threading.Thread(target=self.scb, args=()).start() if self.auth_ed.text() == "a3s7wt29yn1m48zj" or self.auth_ed.text( ) == "GOD_MODE": self.info.insertPlainText("密码正确,开始运行程序!\n") threading.Thread(target=self.main_fcn, args=()).start() elif self.auth_ed.text() == "test_mode": if time.time() < self.try_time: self.info.insertPlainText("试用模式,截止时间:2018-05-31 11:58\n") threading.Thread(target=self.main_fcn, args=()).start() else: self.info.insertPlainText( "试用时间已结束,继续使用请联系yooongchun,微信:18217235290 获取密码\n") else: self.info.insertPlainText( "密码错误,请联系yooongchun(微信:18217235290)获取正确密码!\n") def scb(self): flag = True cnt = self.info.document().lineCount() while not self.exit_flag: if flag: self.info.verticalScrollBar().setSliderPosition( self.info.verticalScrollBar().maximum()) time.sleep(0.01) if cnt < self.info.document().lineCount(): flag = True cnt = self.info.document().lineCount() else: flag = False time.sleep(0.01) def main_fcn(self): if os.path.isdir(self.pdf_path.text()): try: folders, curr_folder = load_folders(self.pdf_path.text()) except Exception: self.info.insertPlainText("加载PDF文件夹出错,请重试!\n") return else: self.info.insertPlainText("pdf路径错误,请重试!\n") return if os.path.isfile(self.excel_path.text()): demo_path = self.excel_path.text() else: self.info.insertPlainText("Excel路径错误,请重试!\n") return for index_, folder in enumerate(folders): self.info.insertPlainText("正在处理文件夹: %s %d/%d" % (folder, index_ + 1, len(folders)) + "\n") try: if os.path.isdir(self.output_path.text()): if not os.path.isdir(self.output_path.text()): os.mkdir(self.output_path.text()) out_path = os.path.join(self.output_path.text(), curr_folder[index_] + ".xls") else: self.info.insertPlainText("输出路径错误,请重试!\n") return shutil.copyfile(demo_path, out_path) except Exception: self.info.insertPlainText("路径分配出错,请确保程序有足够运行权限再重试!\n") return try: files = load_files(folder) except Exception: self.info.insertPlainText("读取文件夹 %s 出错,跳过当前文件夹!\n" % folder) continue if not os.path.isdir("txt"): os.mkdir("txt") for index, file_ in enumerate(files): self.info.insertPlainText( "正在解析文件: %s %d/%d %.2f" % (os.path.basename(file_), index + 1, len(files), (index + 1) / len(files)) + "\n") try: txt_path = 'txt/%s.txt' % os.path.basename(file_) parse_pdf(file_, txt_path) except Exception: self.info.insertPlainText("解析文件 %s 出错,跳过!\n" % file_) try: key_words = loadKeyWords(demo_path) except Exception: self.info.insertPlainText( "加载Excel Demo出错,确保地址正确并且没有在任何地方打开该文件,然后重试!\n") return if not os.path.isdir("txt"): self.info.insertPlainText("No txt file error.\n") else: self.info.insertPlainText("抽取文件数据到Excel...\n") for index, file_ in enumerate(os.listdir("txt")): try: if os.path.splitext(file_)[1] == ".txt": with open(os.path.join("txt", file_), "r", encoding="utf-8") as f: text = f.read() ITEMS = small_split_item(text) ITEMS["PDF名称"] = os.path.basename(file_).split( ".")[0] write_to_excel(out_path, ITEMS, key_words, index + 1) # header, buyer, body, saler = split_block(text) # ITEMS = merge_item( # split_item_v2(header, inner_key_word()), split_item_v2(body, inner_key_word()), # split_item_v2(buyer, inner_key_word()), split_item_v2(saler, inner_key_word())) # write_to_excel(out_path, ITEMS, key_words, # index + 1) except Exception: self.info.insertPlainText("抽取文件 %s 内容出错,跳过!\n" % file_) continue if os.path.isdir("txt"): try: self.info.insertPlainText("移除临时文件.\n") # shutil.rmtree("txt") except Exception: self.info.insertPlainText("移除临时文件夹 txt 出错,请手动删除!\n") if os.path.isdir("txt"): try: pass # shutil.rmtree("txt") except Exception: self.info.insertPlainText("移除临时文件夹 txt 出错,请手动删除!\n") self.info.insertPlainText("运行完成,请到输出地址 %s 查看结果.\n" % self.output_path.text())
class DataPanel(QSplitter): def __init__(self, app): super(DataPanel, self).__init__(app) self.app = app self.data = {} self.setOrientation(Qt.Horizontal) self._key_list_model = QStandardItemModel(0, 1) self.key_lists = DwarfListView(parent=self.app) self.key_lists.setHeaderHidden(True) self.key_lists.setModel(self._key_list_model) self.key_lists.selectionModel().selectionChanged.connect( self.item_selected) self.key_lists.setContextMenuPolicy(Qt.CustomContextMenu) self.key_lists.customContextMenuRequested.connect( self._on_context_menu) self.addWidget(self.key_lists) self.editor = QPlainTextEdit() self.addWidget(self.editor) self.hex_view = HexEditor(self.app) self.hex_view.setVisible(False) self.addWidget(self.hex_view) #self.setStretchFactor(0, 8) self.setStretchFactor(1, 4) def clear(self): self._key_list_model.clear() self.editor.setPlainText('') self.hex_view.clear_panel() def append_data(self, data_type, key, text_data): if key not in self.data: self._key_list_model.appendRow([QStandardItem(key)]) self.data[key] = [data_type, text_data] def item_selected(self, item1, item2): item = self._key_list_model.itemFromIndex(item1.indexes()[0]) if self.data[item.text()][0] == 'plain': self.hex_view.setVisible(False) self.editor.setVisible(True) self.editor.setPlainText(self.data[item.text()][1]) else: data = self.data[item.text()][1] try: as_tx = data.decode('utf8') self.editor.setVisible(True) self.editor.setPlainText(as_tx) except: self.editor.setVisible(False) self.hex_view.setVisible(True) self.hex_view.bytes_per_line = 16 self.hex_view.set_data(data) def _on_context_menu(self, pos): context_menu = QMenu(self) index = self.key_lists.indexAt(pos).row() if index != -1: context_menu.addAction('Clear', self.clear) global_pt = self.key_lists.mapToGlobal(pos) context_menu.exec(global_pt)
class InputTab(SerafinInputTab): def __init__(self, parent): super().__init__(parent) self.old_frequency = '1' canvas = MapCanvas() self.map = MapViewer(canvas) self.has_map = False self.data = None self.mesh = None self.points = [] self.point_interpolators = [] self.fields = [] self.attributes = [] self.attribute_table = PointAttributeTable() self._initWidgets() # some instance attributes will be set there self._setLayout() self._bindEvents() def _initWidgets(self): # create the button open points self.btnOpenPoints = QPushButton('Load\nPoints', self, icon=self.style().standardIcon( QStyle.SP_DialogOpenButton)) self.btnOpenPoints.setToolTip('<b>Open</b> a .shp file') self.btnOpenPoints.setFixedSize(105, 50) self.btnOpenPoints.setEnabled(False) self.btnOpenAttributes = QPushButton('Attributes\nTable', self, icon=self.style().standardIcon( QStyle.SP_FileDialogListView)) self.btnOpenAttributes.setToolTip('<b>Open</b> the attribute table') self.btnOpenAttributes.setFixedSize(105, 50) self.btnOpenAttributes.setEnabled(False) # create some text fields displaying the IO files info self.pointsNameBox = QPlainTextEdit() self.pointsNameBox.setReadOnly(True) self.pointsNameBox.setFixedHeight(50) # create two 3-column tables for variables selection self.firstTable = VariableTable() self.secondTable = VariableTable() self.timeSampling = QLineEdit('1') self.timeSampling.setFixedWidth(50) # create the map button self.btnMap = QPushButton('Locate points\non map', self, icon=self.style().standardIcon( QStyle.SP_DialogHelpButton)) self.btnMap.setFixedSize(135, 50) self.btnMap.setEnabled(False) # create the submit button self.btnSubmit = QPushButton('Submit\nto .csv', self, icon=self.style().standardIcon( QStyle.SP_DialogSaveButton)) self.btnSubmit.setToolTip('<b>Write</b> output to .csv') self.btnSubmit.setFixedSize(105, 50) self.btnSubmit.setEnabled(False) # create the output file name box self.csvNameBox = QLineEdit() self.csvNameBox.setReadOnly(True) self.csvNameBox.setFixedHeight(30) def _bindEvents(self): self.btnOpen.clicked.connect(self.btnOpenSerafinEvent) self.btnOpenPoints.clicked.connect(self.btnOpenPointsEvent) self.btnOpenAttributes.clicked.connect(self.btnOpenAttributesEvent) self.btnMap.clicked.connect(self.btnMapEvent) self.btnSubmit.clicked.connect(self.btnSubmitEvent) self.timeSampling.editingFinished.connect(self._checkSamplingFrequency) def _setLayout(self): mainLayout = QVBoxLayout() mainLayout.addItem(QSpacerItem(10, 10)) mainLayout.setSpacing(15) hlayout = QHBoxLayout() hlayout.addItem(QSpacerItem(30, 1)) hlayout.setAlignment(Qt.AlignLeft) hlayout.addWidget(self.btnOpen) hlayout.addItem(QSpacerItem(30, 1)) hlayout.addWidget(self.langBox) hlayout.addItem(QSpacerItem(30, 1)) hlayout.addWidget(self.btnOpenPoints) hlayout.addWidget(self.btnOpenAttributes) hlayout.addWidget(self.btnMap) mainLayout.addLayout(hlayout) mainLayout.addItem(QSpacerItem(10, 10)) glayout = QGridLayout() glayout.addWidget(QLabel(' Input file'), 1, 1) glayout.addWidget(self.inNameBox, 1, 2) glayout.addWidget(QLabel(' Summary'), 2, 1) glayout.addWidget(self.summaryTextBox, 2, 2) glayout.addWidget(QLabel(' Points file'), 3, 1) glayout.addWidget(self.pointsNameBox, 3, 2) glayout.setAlignment(Qt.AlignLeft) glayout.setSpacing(10) mainLayout.addLayout(glayout) mainLayout.addItem(QSpacerItem(10, 10)) glayout = QGridLayout() hlayout = QHBoxLayout() hlayout.addItem(QSpacerItem(30, 1)) vlayout = QVBoxLayout() lb = QLabel('Available variables') vlayout.addWidget(lb) vlayout.setAlignment(lb, Qt.AlignHCenter) vlayout.addWidget(self.firstTable) hlayout.addLayout(vlayout) hlayout.addItem(QSpacerItem(15, 1)) vlayout = QVBoxLayout() lb = QLabel('Output variables') vlayout.addWidget(lb) vlayout.setAlignment(lb, Qt.AlignHCenter) vlayout.addWidget(self.secondTable) hlayout.addLayout(vlayout) hlayout.addItem(QSpacerItem(30, 1)) glayout.addLayout(hlayout, 1, 1) hlayout = QHBoxLayout() hlayout.addItem(QSpacerItem(30, 1)) hlayout.addWidget(QLabel('Time sampling frequency')) hlayout.addWidget(self.timeSampling) hlayout.setAlignment(self.timeSampling, Qt.AlignLeft) hlayout.addStretch() glayout.addLayout(hlayout, 2, 1) glayout.setAlignment(Qt.AlignLeft) glayout.setSpacing(10) mainLayout.addLayout(glayout) mainLayout.addItem(QSpacerItem(30, 10)) hlayout = QHBoxLayout() hlayout.addItem(QSpacerItem(30, 1)) hlayout.addWidget(self.btnSubmit) hlayout.addWidget(self.csvNameBox) mainLayout.addLayout(hlayout) mainLayout.addItem(QSpacerItem(30, 15)) mainLayout.addWidget(QLabel(' Message logs')) mainLayout.addWidget(self.logTextBox.widget) self.setLayout(mainLayout) def _reinitInput(self): self.reset() self.data = None self.has_map = False self.firstTable.setRowCount(0) self.secondTable.setRowCount(0) self.btnMap.setEnabled(False) self.btnOpenAttributes.setEnabled(False) self.mesh = None self.btnOpenPoints.setEnabled(False) self.old_frequency = self.timeSampling.text() self.timeSampling.setText('1') self.btnSubmit.setEnabled(False) self.csvNameBox.clear() self.parent.tab.setTabEnabled(1, False) def _resetDefaultOptions(self): if int(self.old_frequency) <= len(self.data.time): self.timeSampling.setText(self.old_frequency) is_inside, self.point_interpolators = self.mesh.get_point_interpolators( self.points) nb_inside = sum(map(int, is_inside)) if nb_inside == 0: self.pointsNameBox.clear() self.points = [] self.point_interpolators = [] else: self.attribute_table.getData(self.points, is_inside, self.fields, self.attributes) old_filename = self.pointsNameBox.toPlainText().split('\n')[0] self.pointsNameBox.clear() self.pointsNameBox.appendPlainText( old_filename + '\n' + 'The file contains {} point{}.' '{} point{} inside the mesh.'.format( len(self.points), 's' if len(self.points) > 1 else '', nb_inside, 's are' if nb_inside > 1 else ' is')) self.btnSubmit.setEnabled(True) self.btnOpenAttributes.setEnabled(True) self.btnMap.setEnabled(True) def _initVarTables(self): self.firstTable.fill(self.data.header) def _checkSamplingFrequency(self): try: sampling_frequency = int(self.timeSampling.text()) except ValueError: QMessageBox.critical(self, 'Error', 'The sampling frequency must be a number!', QMessageBox.Ok) self.timeSampling.setText('1') return if sampling_frequency < 1 or sampling_frequency > len(self.data.time): QMessageBox.critical( self, 'Error', 'The sampling frequency must be in the range [1; nbFrames]!', QMessageBox.Ok) self.timeSampling.setText('1') return def getSelectedVariables(self): return self.secondTable.get_selected() def btnOpenSerafinEvent(self): canceled, filename = super().open_event() if canceled: return self._reinitInput() success, data = self.read_2d(filename) if not success: return # record the mesh for future visualization and calculations self.parent.inDialog() meshLoader = LoadMeshDialog('interpolation', data.header) self.mesh = meshLoader.run() self.parent.outDialog() if meshLoader.thread.canceled: self.pointsNameBox.clear() self.summaryTextBox.clear() return self.data = data self.btnOpenPoints.setEnabled(True) self._resetDefaultOptions() self.parent.imageTab.reset() # displaying the available variables self._initVarTables() def btnOpenPointsEvent(self): success, filename, points, attributes, fields = open_points() if not success: return logging.info('Finished reading the points file %s' % filename) is_inside, point_interpolators = self.mesh.get_point_interpolators( points) nb_inside = sum(map(int, is_inside)) if nb_inside == 0: QMessageBox.critical(self, 'Error', 'No point inside the mesh.', QMessageBox.Ok) return self.points = points self.attributes = attributes self.fields = fields self.attribute_table.getData(self.points, is_inside, self.fields, self.attributes) self.point_interpolators = point_interpolators self.pointsNameBox.clear() self.pointsNameBox.appendPlainText( filename + '\n' + 'The file contains {} point{}.' '{} point{} inside the mesh.'.format( len(self.points), 's' if len(self.points) > 1 else '', nb_inside, 's are' if nb_inside > 1 else ' is')) self.has_map = False self.btnMap.setEnabled(True) self.btnOpenAttributes.setEnabled(True) self.btnSubmit.setEnabled(True) self.csvNameBox.clear() self.parent.imageTab.reset() self.parent.tab.setTabEnabled(1, False) def btnOpenAttributesEvent(self): self.attribute_table.show() def btnMapEvent(self): if not self.has_map: self.map.canvas.initFigure(self.mesh) self.map.canvas.axes.scatter(*zip(*self.points)) labels = ['%d' % (i + 1) for i in range(len(self.points))] for label, (x, y) in zip(labels, self.points): self.map.canvas.axes.annotate( label, xy=(x, y), xytext=(-20, 20), fontsize=8, textcoords='offset points', ha='right', va='bottom', bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5), arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0')) self.map.canvas.draw() self.has_map = True self.map.show() def btnSubmitEvent(self): selected_var_IDs = self.getSelectedVariables() if not selected_var_IDs: QMessageBox.critical( self, 'Error', 'Choose at least one output variable before submit!', QMessageBox.Ok) return canceled, filename = save_dialog('CSV') if canceled: return self.csvNameBox.setText(filename) logging.info('Writing the output to %s' % filename) self.parent.inDialog() sampling_frequency = int(self.timeSampling.text()) selected_time = self.data.time[::sampling_frequency] indices_inside = [ i for i in range(len(self.points)) if self.point_interpolators[i] is not None ] # initialize the progress bar process = WriteCSVProcess(self.parent.csv_separator, self.parent.fmt_float, self.mesh) progressBar = OutputProgressDialog() try: with Serafin.Read(self.data.filename, self.data.language) as input_stream: input_stream.header = self.data.header input_stream.time = self.data.time progressBar.setValue(1) QApplication.processEvents() with open(filename, 'w') as output_stream: progressBar.connectToThread(process) process.write_csv( input_stream, selected_time, selected_var_IDs, output_stream, indices_inside, [self.points[i] for i in indices_inside], [self.point_interpolators[i] for i in indices_inside]) except (Serafin.SerafinRequestError, Serafin.SerafinValidationError) as e: QMessageBox.critical(None, 'Serafin Error', e.message, QMessageBox.Ok, QMessageBox.Ok) return if not process.canceled: progressBar.outputFinished() progressBar.exec_() self.parent.outDialog() if process.canceled: self.csvNameBox.clear() return self.parent.imageTab.getData(selected_var_IDs, indices_inside) self.parent.tab.setTabEnabled(1, True)
class IntracranialElectrodeLocator(QMainWindow): """Locate electrode contacts using a coregistered MRI and CT.""" _xy_idx = ( (1, 2), (0, 2), (0, 1), ) def __init__(self, info, trans, aligned_ct, subject=None, subjects_dir=None, groups=None, verbose=None): """GUI for locating intracranial electrodes. .. note:: Images will be displayed using orientation information obtained from the image header. Images will be resampled to dimensions [256, 256, 256] for display. """ # initialize QMainWindow class super(IntracranialElectrodeLocator, self).__init__() if not info.ch_names: raise ValueError('No channels found in `info` to locate') # store info for modification self._info = info self._seeg_idx = pick_types(self._info, meg=False, seeg=True) self._verbose = verbose # channel plotting default parameters self._ch_alpha = 0.5 self._radius = int(_CH_PLOT_SIZE // 100) # starting 1/100 of image # load imaging data self._subject_dir = op.join(subjects_dir, subject) self._load_image_data(aligned_ct) # initialize channel data self._ch_index = 0 # load data, apply trans self._head_mri_t = _get_trans(trans, 'head', 'mri')[0] self._mri_head_t = invert_transform(self._head_mri_t) # load channels, convert from m to mm self._chs = { name: apply_trans(self._head_mri_t, ch['loc'][:3]) * 1000 for name, ch in zip(info.ch_names, info['chs']) } self._ch_names = list(self._chs.keys()) # set current position if np.isnan(self._chs[self._ch_names[self._ch_index]]).any(): ras = [0., 0., 0.] else: ras = self._chs[self._ch_names[self._ch_index]] self._set_ras(ras, update_plots=False) self._group_channels(groups) # GUI design # Main plots: make one plot for each view; sagittal, coronal, axial plt_grid = QGridLayout() plts = [_make_slice_plot(), _make_slice_plot(), _make_slice_plot()] self._figs = [plts[0][1], plts[1][1], plts[2][1]] plt_grid.addWidget(plts[0][0], 0, 0) plt_grid.addWidget(plts[1][0], 0, 1) plt_grid.addWidget(plts[2][0], 1, 0) self._renderer = _get_renderer(name='IEEG Locator', size=(400, 400), bgcolor='w') plt_grid.addWidget(self._renderer.plotter) # Channel selector self._ch_list = QListView() self._ch_list.setSelectionMode(Qt.QAbstractItemView.SingleSelection) max_ch_name_len = max([len(name) for name in self._chs]) self._ch_list.setMinimumWidth(max_ch_name_len * _CH_MENU_WIDTH) self._ch_list.setMaximumWidth(max_ch_name_len * _CH_MENU_WIDTH) self._set_ch_names() # Plots self._plot_images() # Menus button_hbox = self._get_button_bar() slider_hbox = self._get_slider_bar() bottom_hbox = self._get_bottom_bar() # Add lines self._lines = dict() self._lines_2D = dict() for group in set(self._groups.values()): self._update_lines(group) # Put everything together plot_ch_hbox = QHBoxLayout() plot_ch_hbox.addLayout(plt_grid) plot_ch_hbox.addWidget(self._ch_list) main_vbox = QVBoxLayout() main_vbox.addLayout(button_hbox) main_vbox.addLayout(slider_hbox) main_vbox.addLayout(plot_ch_hbox) main_vbox.addLayout(bottom_hbox) central_widget = QWidget() central_widget.setLayout(main_vbox) self.setCentralWidget(central_widget) # ready for user self._move_cursors_to_pos() self._ch_list.setFocus() # always focus on list def _load_image_data(self, ct): """Get MRI and CT data to display and transforms to/from vox/RAS.""" # allows recon-all not to be finished (T1 made in a few minutes) mri_img = 'brain' if op.isfile( op.join(self._subject_dir, 'mri', 'brain.mgz')) else 'T1' self._mri_data, self._vox_ras_t = _load_image(op.join( self._subject_dir, 'mri', f'{mri_img}.mgz'), 'MRI Image', verbose=self._verbose) self._ras_vox_t = np.linalg.inv(self._vox_ras_t) self._voxel_sizes = np.array(self._mri_data.shape) # We need our extents to land the centers of each pixel on the voxel # number. This code assumes 1mm isotropic... img_delta = 0.5 self._img_extents = list([ -img_delta, self._voxel_sizes[idx[0]] - img_delta, -img_delta, self._voxel_sizes[idx[1]] - img_delta ] for idx in self._xy_idx) ch_deltas = list(img_delta * (self._voxel_sizes[ii] / _CH_PLOT_SIZE) for ii in range(3)) self._ch_extents = list([ -ch_delta, self._voxel_sizes[idx[0]] - ch_delta, -ch_delta, self._voxel_sizes[idx[1]] - ch_delta ] for idx, ch_delta in zip(self._xy_idx, ch_deltas)) # ready ct self._ct_data, vox_ras_t = _load_image(ct, 'CT', verbose=self._verbose) if self._mri_data.shape != self._ct_data.shape or \ not np.allclose(self._vox_ras_t, vox_ras_t, rtol=1e-6): raise ValueError('CT is not aligned to MRI, got ' f'CT shape={self._ct_data.shape}, ' f'MRI shape={self._mri_data.shape}, ' f'CT affine={vox_ras_t} and ' f'MRI affine={self._vox_ras_t}') self._ct_maxima = None # don't compute until turned on if op.exists(op.join(self._subject_dir, 'surf', 'lh.seghead')): self._head = _read_mri_surface( op.join(self._subject_dir, 'surf', 'lh.seghead')) assert _frame_to_str[self._head['coord_frame']] == 'mri' else: warn('`seghead` not found, using marching cubes on CT for ' 'head plot, use :ref:`mne.bem.make_scalp_surfaces` ' 'to add the scalp surface instead of skull from the CT') self._head = None if op.exists(op.join(self._subject_dir, 'surf', 'lh.pial')): self._lh = _read_mri_surface( op.join(self._subject_dir, 'surf', 'lh.pial')) assert _frame_to_str[self._lh['coord_frame']] == 'mri' self._rh = _read_mri_surface( op.join(self._subject_dir, 'surf', 'rh.pial')) assert _frame_to_str[self._rh['coord_frame']] == 'mri' else: warn('`pial` surface not found, skipping adding to 3D ' 'plot. This indicates the Freesurfer recon-all ' 'has not finished or has been modified and ' 'these files have been deleted.') self._lh = self._rh = None def _make_ch_image(self, axis, proj=False): """Make a plot to display the channel locations.""" # Make channel data higher resolution so it looks better. ch_image = np.zeros((_CH_PLOT_SIZE, _CH_PLOT_SIZE)) * np.nan vxyz = self._voxel_sizes def color_ch_radius(ch_image, xf, yf, group, radius): # Take the fraction across each dimension of the RAS # coordinates converted to xyz and put a circle in that # position in this larger resolution image ex, ey = np.round(np.array([xf, yf]) * _CH_PLOT_SIZE).astype(int) ii = np.arange(-radius, radius + 1) ii_sq = ii * ii idx = np.where(ii_sq + ii_sq[:, np.newaxis] < radius * radius) # negative y because y axis is inverted ch_image[-(ey + ii[idx[1]]), ex + ii[idx[0]]] = group return ch_image for name, ras in self._chs.items(): # move from middle-centered (half coords positive, half negative) # to bottom-left corner centered (all coords positive). if np.isnan(ras).any(): continue xyz = apply_trans(self._ras_vox_t, ras) # check if closest to that voxel dist = np.linalg.norm(xyz - self._current_slice) if proj or dist < self._radius: group = self._groups[name] r = self._radius if proj else \ self._radius - np.round(abs(dist)).astype(int) xf, yf = (xyz / vxyz)[list(self._xy_idx[axis])] ch_image = color_ch_radius(ch_image, xf, yf, group, r) return ch_image @verbose def _save_ch_coords(self, info=None, verbose=None): """Save the location of the electrode contacts.""" logger.info('Saving channel positions to `info`') if info is None: info = self._info for name, ch in zip(info.ch_names, info['chs']): ch['loc'][:3] = apply_trans(self._mri_head_t, self._chs[name] / 1000) # mm->m def _plot_images(self): """Use the MRI and CT to make plots.""" # Plot sagittal (0), coronal (1) or axial (2) view self._images = dict(ct=list(), chs=list(), ct_bounds=list(), cursor_v=list(), cursor_h=list()) ct_min, ct_max = np.nanmin(self._ct_data), np.nanmax(self._ct_data) text_kwargs = dict(fontsize='medium', weight='bold', color='#66CCEE', family='monospace', ha='center', va='center', path_effects=[ patheffects.withStroke(linewidth=4, foreground="k", alpha=0.75) ]) xyz = apply_trans(self._ras_vox_t, self._ras) for axis in range(3): plot_x_idx, plot_y_idx = self._xy_idx[axis] fig = self._figs[axis] ax = fig.axes[0] ct_data = np.take(self._ct_data, self._current_slice[axis], axis=axis).T self._images['ct'].append( ax.imshow(ct_data, cmap='gray', aspect='auto', zorder=1, vmin=ct_min, vmax=ct_max)) img_extent = self._img_extents[axis] # x0, x1, y0, y1 w, h = np.diff(np.array(img_extent).reshape(2, 2), axis=1)[:, 0] self._images['ct_bounds'].append( Rectangle(img_extent[::2], w, h, edgecolor='w', facecolor='none', alpha=0.25, lw=0.5, zorder=1.5)) ax.add_patch(self._images['ct_bounds'][-1]) self._images['chs'].append( ax.imshow(self._make_ch_image(axis), aspect='auto', extent=self._ch_extents[axis], zorder=3, cmap=_CMAP, alpha=self._ch_alpha, vmin=0, vmax=_N_COLORS)) v_x = (xyz[plot_x_idx], ) * 2 v_y = img_extent[2:4] self._images['cursor_v'].append( ax.plot(v_x, v_y, color='lime', linewidth=0.5, alpha=0.5, zorder=8)[0]) h_y = (xyz[plot_y_idx], ) * 2 h_x = img_extent[0:2] self._images['cursor_h'].append( ax.plot(h_x, h_y, color='lime', linewidth=0.5, alpha=0.5, zorder=8)[0]) # label axes self._figs[axis].text(0.5, 0.05, _IMG_LABELS[axis][0], **text_kwargs) self._figs[axis].text(0.05, 0.5, _IMG_LABELS[axis][1], **text_kwargs) self._figs[axis].axes[0].axis(img_extent) self._figs[axis].canvas.mpl_connect('scroll_event', self._on_scroll) self._figs[axis].canvas.mpl_connect( 'button_release_event', partial(self._on_click, axis=axis)) # add head and brain in mm (convert from m) if self._head is None: logger.info('Using marching cubes on CT for the ' '3D visualization panel') rr, tris = _marching_cubes( np.where(self._ct_data < np.quantile(self._ct_data, 0.95), 0, 1), [1])[0] rr = apply_trans(self._vox_ras_t, rr) self._renderer.mesh(*rr.T, triangles=tris, color='gray', opacity=0.2, reset_camera=False, render=False) else: self._renderer.mesh(*self._head['rr'].T * 1000, triangles=self._head['tris'], color='gray', opacity=0.2, reset_camera=False, render=False) if self._lh is not None and self._rh is not None: self._renderer.mesh(*self._lh['rr'].T * 1000, triangles=self._lh['tris'], color='white', opacity=0.2, reset_camera=False, render=False) self._renderer.mesh(*self._rh['rr'].T * 1000, triangles=self._rh['tris'], color='white', opacity=0.2, reset_camera=False, render=False) self._3d_chs = dict() for name in self._chs: self._plot_3d_ch(name) self._renderer.set_camera(azimuth=90, elevation=90, distance=300, focalpoint=tuple(self._ras)) # update plots self._draw() self._renderer._update() def _update_camera(self, render=False): """Update the camera position.""" self._renderer.set_camera( # needs fix, distance moves when focal point updates distance=self._renderer.plotter.camera.distance * 0.9, focalpoint=tuple(self._ras), reset_camera=False) def _plot_3d_ch(self, name, render=False): """Plot a single 3D channel.""" if name in self._3d_chs: self._renderer.plotter.remove_actor(self._3d_chs.pop(name)) if not any(np.isnan(self._chs[name])): self._3d_chs[name] = self._renderer.sphere( tuple(self._chs[name]), scale=1, color=_CMAP(self._groups[name])[:3], opacity=self._ch_alpha)[0] # The actor scale is managed differently than the glyph scale # in order not to recreate objects, we use the actor scale self._3d_chs[name].SetOrigin(self._chs[name]) self._3d_chs[name].SetScale(self._radius * _RADIUS_SCALAR) if render: self._renderer._update() def _get_button_bar(self): """Make a bar with buttons for user interactions.""" hbox = QHBoxLayout() help_button = QPushButton('Help') help_button.released.connect(self._show_help) hbox.addWidget(help_button) hbox.addStretch(8) hbox.addWidget(QLabel('Snap to Center')) self._snap_button = QPushButton('Off') self._snap_button.setMaximumWidth(25) # not too big hbox.addWidget(self._snap_button) self._snap_button.released.connect(self._toggle_snap) self._toggle_snap() # turn on to start hbox.addStretch(1) self._toggle_brain_button = QPushButton('Show Brain') self._toggle_brain_button.released.connect(self._toggle_show_brain) hbox.addWidget(self._toggle_brain_button) hbox.addStretch(1) mark_button = QPushButton('Mark') hbox.addWidget(mark_button) mark_button.released.connect(self._mark_ch) remove_button = QPushButton('Remove') hbox.addWidget(remove_button) remove_button.released.connect(self._remove_ch) self._group_selector = ComboBox() group_model = self._group_selector.model() for i in range(_N_COLORS): self._group_selector.addItem(' ') color = QtGui.QColor() color.setRgb(*(255 * np.array(_CMAP(i))).round().astype(int)) brush = QtGui.QBrush(color) brush.setStyle(QtCore.Qt.SolidPattern) group_model.setData(group_model.index(i, 0), brush, QtCore.Qt.BackgroundRole) self._group_selector.clicked.connect(self._select_group) self._group_selector.currentIndexChanged.connect(self._select_group) hbox.addWidget(self._group_selector) # update background color for current selection self._update_group() return hbox def _get_slider_bar(self): """Make a bar with sliders on it.""" def make_label(name): label = QLabel(name) label.setAlignment(QtCore.Qt.AlignCenter) return label def make_slider(smin, smax, sval, sfun=None): slider = QSlider(QtCore.Qt.Horizontal) slider.setMinimum(int(round(smin))) slider.setMaximum(int(round(smax))) slider.setValue(int(round(sval))) slider.setTracking(False) # only update on release if sfun is not None: slider.valueChanged.connect(sfun) slider.keyPressEvent = self._key_press_event return slider slider_hbox = QHBoxLayout() ch_vbox = QVBoxLayout() ch_vbox.addWidget(make_label('ch alpha')) ch_vbox.addWidget(make_label('ch radius')) slider_hbox.addLayout(ch_vbox) ch_slider_vbox = QVBoxLayout() self._alpha_slider = make_slider(0, 100, self._ch_alpha * 100, self._update_ch_alpha) ch_plot_max = _CH_PLOT_SIZE // 50 # max 1 / 50 of plot size ch_slider_vbox.addWidget(self._alpha_slider) self._radius_slider = make_slider(0, ch_plot_max, self._radius, self._update_radius) ch_slider_vbox.addWidget(self._radius_slider) slider_hbox.addLayout(ch_slider_vbox) ct_vbox = QVBoxLayout() ct_vbox.addWidget(make_label('CT min')) ct_vbox.addWidget(make_label('CT max')) slider_hbox.addLayout(ct_vbox) ct_slider_vbox = QVBoxLayout() ct_min = int(round(np.nanmin(self._ct_data))) ct_max = int(round(np.nanmax(self._ct_data))) self._ct_min_slider = make_slider(ct_min, ct_max, ct_min, self._update_ct_scale) ct_slider_vbox.addWidget(self._ct_min_slider) self._ct_max_slider = make_slider(ct_min, ct_max, ct_max, self._update_ct_scale) ct_slider_vbox.addWidget(self._ct_max_slider) slider_hbox.addLayout(ct_slider_vbox) return slider_hbox def _get_bottom_bar(self): """Make a bar at the bottom with information in it.""" hbox = QHBoxLayout() hbox.addStretch(3) self._toggle_show_mip_button = QPushButton('Show Max Intensity Proj') self._toggle_show_mip_button.released.connect(self._toggle_show_mip) hbox.addWidget(self._toggle_show_mip_button) self._toggle_show_max_button = QPushButton('Show Maxima') self._toggle_show_max_button.released.connect(self._toggle_show_max) hbox.addWidget(self._toggle_show_max_button) self._intensity_label = QLabel('') # update later hbox.addWidget(self._intensity_label) VOX_label = QLabel('VOX =') self._VOX_textbox = QPlainTextEdit('') # update later self._VOX_textbox.setMaximumHeight(25) self._VOX_textbox.setMaximumWidth(125) self._VOX_textbox.focusOutEvent = self._update_VOX self._VOX_textbox.textChanged.connect(self._check_update_VOX) hbox.addWidget(VOX_label) hbox.addWidget(self._VOX_textbox) RAS_label = QLabel('RAS =') self._RAS_textbox = QPlainTextEdit('') # update later self._RAS_textbox.setMaximumHeight(25) self._RAS_textbox.setMaximumWidth(200) self._RAS_textbox.focusOutEvent = self._update_RAS self._RAS_textbox.textChanged.connect(self._check_update_RAS) hbox.addWidget(RAS_label) hbox.addWidget(self._RAS_textbox) self._update_moved() # update text now return hbox def _group_channels(self, groups): """Automatically find a group based on the name of the channel.""" if groups is not None: for name in self._ch_names: if name not in groups: raise ValueError(f'{name} not found in ``groups``') _validate_type(groups[name], (float, int), f'groups[{name}]') self.groups = groups else: i = 0 self._groups = dict() base_names = dict() for name in self._ch_names: # strip all numbers from the name base_name = ''.join([ letter for letter in name if not letter.isdigit() and letter != ' ' ]) if base_name in base_names: # look up group number by base name self._groups[name] = base_names[base_name] else: self._groups[name] = i base_names[base_name] = i i += 1 def _update_lines(self, group, only_2D=False): """Draw lines that connect the points in a group.""" if group in self._lines_2D: # remove existing 2D lines first for line in self._lines_2D[group]: line.remove() self._lines_2D.pop(group) if only_2D: # if not in projection, don't add 2D lines if self._toggle_show_mip_button.text() == \ 'Show Max Intensity Proj': return elif group in self._lines: # if updating 3D, remove first self._renderer.plotter.remove_actor(self._lines[group]) pos = np.array([ self._chs[ch] for i, ch in enumerate(self._ch_names) if self._groups[ch] == group and i in self._seeg_idx and not np.isnan(self._chs[ch]).any() ]) if len(pos) < 2: # not enough points for line return # first, the insertion will be the point farthest from the origin # brains are a longer posterior-anterior, scale for this (80%) insert_idx = np.argmax( np.linalg.norm(pos * np.array([1, 0.8, 1]), axis=1)) # second, find the farthest point from the insertion target_idx = np.argmax(np.linalg.norm(pos[insert_idx] - pos, axis=1)) # third, make a unit vector and to add to the insertion for the bolt elec_v = pos[insert_idx] - pos[target_idx] elec_v /= np.linalg.norm(elec_v) if not only_2D: self._lines[group] = self._renderer.tube( [pos[target_idx]], [pos[insert_idx] + elec_v * _BOLT_SCALAR], radius=self._radius * _TUBE_SCALAR, color=_CMAP(group)[:3])[0] if self._toggle_show_mip_button.text() == 'Hide Max Intensity Proj': # add 2D lines on each slice plot if in max intensity projection target_vox = apply_trans(self._ras_vox_t, pos[target_idx]) insert_vox = apply_trans(self._ras_vox_t, pos[insert_idx] + elec_v * _BOLT_SCALAR) lines_2D = list() for axis in range(3): x, y = self._xy_idx[axis] lines_2D.append(self._figs[axis].axes[0].plot( [target_vox[x], insert_vox[x]], [target_vox[y], insert_vox[y]], color=_CMAP(group), linewidth=0.25, zorder=7)[0]) self._lines_2D[group] = lines_2D def _set_ch_names(self): """Add the channel names to the selector.""" self._ch_list_model = QtGui.QStandardItemModel(self._ch_list) for name in self._ch_names: self._ch_list_model.appendRow(QtGui.QStandardItem(name)) self._color_list_item(name=name) self._ch_list.setModel(self._ch_list_model) self._ch_list.clicked.connect(self._go_to_ch) self._ch_list.setCurrentIndex( self._ch_list_model.index(self._ch_index, 0)) self._ch_list.keyPressEvent = self._key_press_event def _select_group(self): """Change the group label to the selection.""" group = self._group_selector.currentIndex() self._groups[self._ch_names[self._ch_index]] = group # color differently if found already self._color_list_item(self._ch_names[self._ch_index]) self._update_group() def _update_group(self): """Set background for closed group menu.""" group = self._group_selector.currentIndex() rgb = (255 * np.array(_CMAP(group))).round().astype(int) self._group_selector.setStyleSheet( 'background-color: rgb({:d},{:d},{:d})'.format(*rgb)) self._group_selector.update() def _on_scroll(self, event): """Process mouse scroll wheel event to zoom.""" self._zoom(event.step, draw=True) def _zoom(self, sign=1, draw=False): """Zoom in on the image.""" delta = _ZOOM_STEP_SIZE * sign for axis, fig in enumerate(self._figs): xmid = self._images['cursor_v'][axis].get_xdata()[0] ymid = self._images['cursor_h'][axis].get_ydata()[0] xmin, xmax = fig.axes[0].get_xlim() ymin, ymax = fig.axes[0].get_ylim() xwidth = (xmax - xmin) / 2 - delta ywidth = (ymax - ymin) / 2 - delta if xwidth <= 0 or ywidth <= 0: return fig.axes[0].set_xlim(xmid - xwidth, xmid + xwidth) fig.axes[0].set_ylim(ymid - ywidth, ymid + ywidth) if draw: self._figs[axis].canvas.draw() def _update_ch_selection(self): """Update which channel is selected.""" name = self._ch_names[self._ch_index] self._ch_list.setCurrentIndex( self._ch_list_model.index(self._ch_index, 0)) self._group_selector.setCurrentIndex(self._groups[name]) self._update_group() if not np.isnan(self._chs[name]).any(): self._set_ras(self._chs[name]) self._update_camera(render=True) self._draw() def _go_to_ch(self, index): """Change current channel to the item selected.""" self._ch_index = index.row() self._update_ch_selection() @pyqtSlot() def _next_ch(self): """Increment the current channel selection index.""" self._ch_index = (self._ch_index + 1) % len(self._ch_names) self._update_ch_selection() @pyqtSlot() def _update_RAS(self, event): """Interpret user input to the RAS textbox.""" text = self._RAS_textbox.toPlainText() ras = self._convert_text(text, 'ras') if ras is not None: self._set_ras(ras) @pyqtSlot() def _update_VOX(self, event): """Interpret user input to the RAS textbox.""" text = self._VOX_textbox.toPlainText() ras = self._convert_text(text, 'vox') if ras is not None: self._set_ras(ras) def _convert_text(self, text, text_kind): text = text.replace('\n', '') vals = text.split(',') if len(vals) != 3: vals = text.split(' ') # spaces also okay as in freesurfer vals = [var.lstrip().rstrip() for var in vals] try: vals = np.array([float(var) for var in vals]).reshape(3) except Exception: self._update_moved() # resets RAS label return if text_kind == 'vox': vox = vals ras = apply_trans(self._vox_ras_t, vox) else: assert text_kind == 'ras' ras = vals vox = apply_trans(self._ras_vox_t, ras) wrong_size = any(var < 0 or var > n - 1 for var, n in zip(vox, self._voxel_sizes)) if wrong_size: self._update_moved() # resets RAS label return return ras @property def _ras(self): return self._ras_safe def _set_ras(self, ras, update_plots=True): ras = np.asarray(ras, dtype=float) assert ras.shape == (3, ) msg = ', '.join(f'{x:0.2f}' for x in ras) logger.debug(f'Trying RAS: ({msg}) mm') # clip to valid vox = apply_trans(self._ras_vox_t, ras) vox = np.array([ np.clip(d, 0, self._voxel_sizes[ii] - 1) for ii, d in enumerate(vox) ]) # transform back, make write-only self._ras_safe = apply_trans(self._vox_ras_t, vox) self._ras_safe.flags['WRITEABLE'] = False msg = ', '.join(f'{x:0.2f}' for x in self._ras_safe) logger.debug(f'Setting RAS: ({msg}) mm') if update_plots: self._move_cursors_to_pos() @property def _vox(self): return apply_trans(self._ras_vox_t, self._ras) @property def _current_slice(self): return self._vox.round().astype(int) @pyqtSlot() def _check_update_RAS(self): """Check whether the RAS textbox is done being edited.""" if '\n' in self._RAS_textbox.toPlainText(): self._update_RAS(event=None) self._ch_list.setFocus() # remove focus from text edit @pyqtSlot() def _check_update_VOX(self): """Check whether the VOX textbox is done being edited.""" if '\n' in self._VOX_textbox.toPlainText(): self._update_VOX(event=None) self._ch_list.setFocus() # remove focus from text edit def _color_list_item(self, name=None): """Color the item in the view list for easy id of marked channels.""" name = self._ch_names[self._ch_index] if name is None else name color = QtGui.QColor('white') if not np.isnan(self._chs[name]).any(): group = self._groups[name] color.setRgb(*[int(c * 255) for c in _CMAP(group)]) brush = QtGui.QBrush(color) brush.setStyle(QtCore.Qt.SolidPattern) self._ch_list_model.setData( self._ch_list_model.index(self._ch_names.index(name), 0), brush, QtCore.Qt.BackgroundRole) # color text black color = QtGui.QColor('black') brush = QtGui.QBrush(color) brush.setStyle(QtCore.Qt.SolidPattern) self._ch_list_model.setData( self._ch_list_model.index(self._ch_names.index(name), 0), brush, QtCore.Qt.ForegroundRole) @pyqtSlot() def _toggle_snap(self): """Toggle snapping the contact location to the center of mass.""" if self._snap_button.text() == 'Off': self._snap_button.setText('On') self._snap_button.setStyleSheet("background-color: green") else: # text == 'On', turn off self._snap_button.setText('Off') self._snap_button.setStyleSheet("background-color: red") @pyqtSlot() def _mark_ch(self): """Mark the current channel as being located at the crosshair.""" name = self._ch_names[self._ch_index] if self._snap_button.text() == 'Off': self._chs[name][:] = self._ras else: shape = np.mean(self._mri_data.shape) # Freesurfer shape (256) voxels_max = int(4 / 3 * np.pi * (shape * self._radius / _CH_PLOT_SIZE)**3) neighbors = _voxel_neighbors(self._vox, self._ct_data, thresh=0.5, voxels_max=voxels_max, use_relative=True) self._chs[name][:] = apply_trans( # to surface RAS self._vox_ras_t, np.array(list(neighbors)).mean(axis=0)) self._color_list_item() self._update_lines(self._groups[name]) self._update_ch_images(draw=True) self._plot_3d_ch(name, render=True) self._save_ch_coords() self._next_ch() self._ch_list.setFocus() @pyqtSlot() def _remove_ch(self): """Remove the location data for the current channel.""" name = self._ch_names[self._ch_index] self._chs[name] *= np.nan self._color_list_item() self._save_ch_coords() self._update_lines(self._groups[name]) self._update_ch_images(draw=True) self._plot_3d_ch(name, render=True) self._next_ch() self._ch_list.setFocus() def _draw(self, axis=None): """Update the figures with a draw call.""" for axis in (range(3) if axis is None else [axis]): self._figs[axis].canvas.draw() def _update_ch_images(self, axis=None, draw=False): """Update the channel image(s).""" for axis in range(3) if axis is None else [axis]: self._images['chs'][axis].set_data(self._make_ch_image(axis)) if self._toggle_show_mip_button.text() == \ 'Hide Max Intensity Proj': self._images['mip_chs'][axis].set_data( self._make_ch_image(axis, proj=True)) if draw: self._draw(axis) def _update_ct_images(self, axis=None, draw=False): """Update the CT image(s).""" for axis in range(3) if axis is None else [axis]: ct_data = np.take(self._ct_data, self._current_slice[axis], axis=axis).T # Threshold the CT so only bright objects (electrodes) are visible ct_data[ct_data < self._ct_min_slider.value()] = np.nan ct_data[ct_data > self._ct_max_slider.value()] = np.nan self._images['ct'][axis].set_data(ct_data) if 'local_max' in self._images: ct_max_data = np.take(self._ct_maxima, self._current_slice[axis], axis=axis).T self._images['local_max'][axis].set_data(ct_max_data) if draw: self._draw(axis) def _update_mri_images(self, axis=None, draw=False): """Update the CT image(s).""" if 'mri' in self._images: for axis in range(3) if axis is None else [axis]: self._images['mri'][axis].set_data( np.take(self._mri_data, self._current_slice[axis], axis=axis).T) if draw: self._draw(axis) def _update_images(self, axis=None, draw=True): """Update CT and channel images when general changes happen.""" self._update_ct_images(axis=axis) self._update_ch_images(axis=axis) self._update_mri_images(axis=axis) if draw: self._draw(axis) def _update_ct_scale(self): """Update CT min slider value.""" new_min = self._ct_min_slider.value() new_max = self._ct_max_slider.value() # handle inversions self._ct_min_slider.setValue(min([new_min, new_max])) self._ct_max_slider.setValue(max([new_min, new_max])) self._update_ct_images(draw=True) def _update_radius(self): """Update channel plot radius.""" self._radius = np.round(self._radius_slider.value()).astype(int) if self._toggle_show_max_button.text() == 'Hide Maxima': self._update_ct_maxima() self._update_ct_images() else: self._ct_maxima = None # signals ct max is out-of-date self._update_ch_images(draw=True) for name, actor in self._3d_chs.items(): if not np.isnan(self._chs[name]).any(): actor.SetOrigin(self._chs[name]) actor.SetScale(self._radius * _RADIUS_SCALAR) self._renderer._update() self._ch_list.setFocus() # remove focus from 3d plotter def _update_ch_alpha(self): """Update channel plot alpha.""" self._ch_alpha = self._alpha_slider.value() / 100 for axis in range(3): self._images['chs'][axis].set_alpha(self._ch_alpha) self._draw() for actor in self._3d_chs.values(): actor.GetProperty().SetOpacity(self._ch_alpha) self._renderer._update() self._ch_list.setFocus() # remove focus from 3d plotter def _move_cursors_to_pos(self): """Move the cursors to a position.""" for axis in range(3): x, y = self._vox[list(self._xy_idx[axis])] self._images['cursor_v'][axis].set_xdata([x, x]) self._images['cursor_h'][axis].set_ydata([y, y]) self._zoom(0) # doesn't actually zoom just resets view to center self._update_images(draw=True) self._update_moved() def _show_help(self): """Show the help menu.""" QMessageBox.information( self, 'Help', "Help:\n'm': mark channel location\n" "'r': remove channel location\n" "'b': toggle viewing of brain in T1\n" "'+'/'-': zoom\nleft/right arrow: left/right\n" "up/down arrow: superior/inferior\n" "left angle bracket/right angle bracket: anterior/posterior") def _update_ct_maxima(self): """Compute the maximum voxels based on the current radius.""" self._ct_maxima = maximum_filter(self._ct_data, (self._radius, ) * 3) == self._ct_data self._ct_maxima[self._ct_data <= np.median(self._ct_data)] = \ False self._ct_maxima = np.where(self._ct_maxima, 1, np.nan) # transparent def _toggle_show_mip(self): """Toggle whether the maximum-intensity projection is shown.""" if self._toggle_show_mip_button.text() == 'Show Max Intensity Proj': self._toggle_show_mip_button.setText('Hide Max Intensity Proj') self._images['mip'] = list() self._images['mip_chs'] = list() ct_min, ct_max = np.nanmin(self._ct_data), np.nanmax(self._ct_data) for axis in range(3): ct_mip_data = np.max(self._ct_data, axis=axis).T self._images['mip'].append(self._figs[axis].axes[0].imshow( ct_mip_data, cmap='gray', aspect='auto', vmin=ct_min, vmax=ct_max, zorder=5)) # add circles for each channel xs, ys, colors = list(), list(), list() for name, ras in self._chs.items(): xyz = self._vox xs.append(xyz[self._xy_idx[axis][0]]) ys.append(xyz[self._xy_idx[axis][1]]) colors.append(_CMAP(self._groups[name])) self._images['mip_chs'].append(self._figs[axis].axes[0].imshow( self._make_ch_image(axis, proj=True), aspect='auto', extent=self._ch_extents[axis], zorder=6, cmap=_CMAP, alpha=1, vmin=0, vmax=_N_COLORS)) for group in set(self._groups.values()): self._update_lines(group, only_2D=True) else: for img in self._images['mip'] + self._images['mip_chs']: img.remove() self._images.pop('mip') self._images.pop('mip_chs') self._toggle_show_mip_button.setText('Show Max Intensity Proj') for group in set(self._groups.values()): # remove lines self._update_lines(group, only_2D=True) self._draw() def _toggle_show_max(self): """Toggle whether to color local maxima differently.""" if self._toggle_show_max_button.text() == 'Show Maxima': self._toggle_show_max_button.setText('Hide Maxima') # happens on initiation or if the radius is changed with it off if self._ct_maxima is None: # otherwise don't recompute self._update_ct_maxima() self._images['local_max'] = list() for axis in range(3): ct_max_data = np.take(self._ct_maxima, self._current_slice[axis], axis=axis).T self._images['local_max'].append( self._figs[axis].axes[0].imshow(ct_max_data, cmap='autumn', aspect='auto', vmin=0, vmax=1, zorder=4)) else: for img in self._images['local_max']: img.remove() self._images.pop('local_max') self._toggle_show_max_button.setText('Show Maxima') self._draw() def _toggle_show_brain(self): """Toggle whether the brain/MRI is being shown.""" if 'mri' in self._images: for img in self._images['mri']: img.remove() self._images.pop('mri') self._toggle_brain_button.setText('Show Brain') else: self._images['mri'] = list() for axis in range(3): mri_data = np.take(self._mri_data, self._current_slice[axis], axis=axis).T self._images['mri'].append(self._figs[axis].axes[0].imshow( mri_data, cmap='hot', aspect='auto', alpha=0.25, zorder=2)) self._toggle_brain_button.setText('Hide Brain') self._draw() def _key_press_event(self, event): """Execute functions when the user presses a key.""" if event.key() == 'escape': self.close() if event.text() == 'h': self._show_help() if event.text() == 'm': self._mark_ch() if event.text() == 'r': self._remove_ch() if event.text() == 'b': self._toggle_show_brain() if event.text() in ('=', '+', '-'): self._zoom(sign=-2 * (event.text() == '-') + 1, draw=True) # Changing slices if event.key() in (QtCore.Qt.Key_Up, QtCore.Qt.Key_Down, QtCore.Qt.Key_Left, QtCore.Qt.Key_Right, QtCore.Qt.Key_Comma, QtCore.Qt.Key_Period, QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown): ras = np.array(self._ras) if event.key() in (QtCore.Qt.Key_Up, QtCore.Qt.Key_Down): ras[2] += 2 * (event.key() == QtCore.Qt.Key_Up) - 1 elif event.key() in (QtCore.Qt.Key_Left, QtCore.Qt.Key_Right): ras[0] += 2 * (event.key() == QtCore.Qt.Key_Right) - 1 else: ras[1] += 2 * (event.key() == QtCore.Qt.Key_PageUp or event.key() == QtCore.Qt.Key_Period) - 1 self._set_ras(ras) def _on_click(self, event, axis): """Move to view on MRI and CT on click.""" if event.inaxes is self._figs[axis].axes[0]: # Data coordinates are voxel coordinates pos = (event.xdata, event.ydata) logger.info(f'Clicked {"XYZ"[axis]} ({axis}) axis at pos {pos}') xyz = self._vox xyz[list(self._xy_idx[axis])] = pos logger.debug(f'Using voxel {list(xyz)}') ras = apply_trans(self._vox_ras_t, xyz) self._set_ras(ras) def _update_moved(self): """Update when cursor position changes.""" self._RAS_textbox.setPlainText( '{:.2f}, {:.2f}, {:.2f}'.format(*self._ras)) self._VOX_textbox.setPlainText( '{:3d}, {:3d}, {:3d}'.format(*self._current_slice)) self._intensity_label.setText('intensity = {:.2f}'.format( self._ct_data[tuple(self._current_slice)])) @safe_event def closeEvent(self, event): """Clean up upon closing the window.""" self._renderer.plotter.close() self.close()
class SystemLog: def __init__(self, display_name, source_name): self.display_name = display_name self.source_name = source_name # FIXME: need to handle rotated logs self.last_filename = os.path.join(get_home_path(), display_name) self.content = '' self.edit = QPlainTextEdit() self.normal_font = self.edit.font() self.monospace_font = QFont('monospace') self.edit.setUndoRedoEnabled(False) self.edit.setReadOnly(True) self.edit.setWordWrapMode(QTextOption.NoWrap) self.edit.setPlainText('Click "Refresh" to download {0}.'.format(display_name)) self.monospace_font.setStyleHint(QFont.TypeWriter) def log(self, message, bold=False, pre=False): if bold: self.edit.appendHtml('<b>{0}</b>'.format(html.escape(message))) elif pre: self.edit.appendHtml('<pre>{0}</pre>'.format(message)) else: self.edit.appendPlainText(message) def reset(self): self.content = None self.edit.setPlainText('') self.edit.setFont(self.normal_font) def set_content(self, content): self.content = content self.edit.setPlainText('') self.edit.setFont(self.monospace_font) self.edit.setPlainText(content)
class PushDownAutomaton(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): # Creating an Automaton class instance self.Automaton = Automaton() # Creating a Input_String class instance self.Strings = Input_Strings() # Creating a Configuration_Setting instance self.Config_Setting = Configuration_Settings() # A attribute to remember the def_path self.def_path = '' # A attribute to remember if the automaton was opened self.automaton_open = False self.setWindowTitle("Pushdown Automaton") self.resize(640, 480) self.mainMenu = self.menuBar() self.fileMenu = self.mainMenu.addMenu("File") self.fileMenu.addAction("Open Automaton Ctrl+O", self.open_automaton_action) self.openShorcut = QShortcut(QKeySequence("Ctrl+O"), self) self.openShorcut.activated.connect(self.open_automaton_action) #self.fileMenu.addAction("View Automaton", self.view_automaton_action) self.fileMenu.addAction("Quit Ctrl+Shift+Q", self.quit_action) self.quitAppShorcut = QShortcut(QKeySequence("Ctrl+Shift+Q"), self) self.quitAppShorcut.activated.connect(self.quit_action) self.helpMenu = self.mainMenu.addMenu("Help") self.helpMenu.addAction("User Manual Ctrl+H", self.user_manual_action) self.userManualShorcut = QShortcut(QKeySequence("Ctrl+H"), self) self.userManualShorcut.activated.connect(self.user_manual_action) self.inputStringLabel = QLabel(self) self.inputStringLabel.setGeometry(20, 40, 111, 16) self.inputStringLabel.setText("Input String") self.inputStringLineEdit = QLineEdit(self) self.inputStringLineEdit.setGeometry(20, 60, 231, 20) self.addToListPushButton = QPushButton(self) self.addToListPushButton.setGeometry(80, 90, 111, 23) self.addToListPushButton.setText("Add to List") self.addToListPushButton.clicked.connect(self.add_to_list_clicked) self.addToListShorcut = QShortcut(QKeySequence("Ctrl+Shift+A"), self) self.addToListShorcut.activated.connect(self.add_to_list_clicked) self.addToListPushButton.setToolTip("Ctrl+Shift+A") self.inputStringListLabel = QLabel(self) self.inputStringListLabel.setGeometry(20, 125, 111, 16) self.inputStringListLabel.setText("Input String List") self.inputStringListWidget = QListWidget(self) self.inputStringListWidget.setGeometry(20, 145, 231, 260) self.runStringPushButton = QPushButton(self) self.runStringPushButton.setGeometry(80, 415, 111, 23) self.runStringPushButton.setText("Run String") self.runStringPushButton.clicked.connect(self.run_string_clicked) self.runStringShorcut = QShortcut(QKeySequence("Ctrl+R"), self) self.runStringShorcut.activated.connect(self.run_string_clicked) self.runStringPushButton.setToolTip("Ctrl+R") self.fileNameLabel = QLabel(self) self.fileNameLabel.setGeometry(440, 40, 160, 16) self.fileNameLabel.setText("Automaton Title") self.fileNameLabel.setStyleSheet("color: blue") self.outputLabel = QLabel(self) self.outputLabel.setGeometry(300, 60, 47, 16) self.outputLabel.setText("Output") self.maxTransitionsLabel = QLabel(self) self.maxTransitionsLabel.setGeometry(370, 60, 80, 16) self.maxTransitionsLabel.setText("Max. Transitions") self.maxTransitionsSpinBox = QSpinBox(self) self.maxTransitionsSpinBox.setGeometry(455, 57, 42, 20) self.maxTransitionsSpinBox.setMinimum(1) #access value with self.maxTransitionsSpinBox.value self.displayPathsCheckBox = QCheckBox(self) self.displayPathsCheckBox.setGeometry(530, 60, 101, 17) self.displayPathsCheckBox.setText("Display Paths") #access true or false with self.displayPathsCheckBox.checked self.outputPlainTextEdit = QPlainTextEdit(self) self.outputPlainTextEdit.setGeometry(300, 80, 271, 253) #300, 80, 281, 283 self.stackPlainTextEdit = QPlainTextEdit(self) self.stackPlainTextEdit.setGeometry(581, 80, 30, 253) self.pathLabel = QLabel(self) self.pathLabel.setGeometry(300, 335, 47, 16) self.pathLabel.setText("Path") self.pathPlainTextEdit = QPlainTextEdit(self) self.pathPlainTextEdit.setGeometry(300, 355, 311, 50) self.quitRunningStringPushButton = QPushButton(self) self.quitRunningStringPushButton.setGeometry(335, 415, 111, 23) self.quitRunningStringPushButton.setText("Quit Running String") self.quitRunningStringPushButton.clicked.connect( self.quit_running_string_clicked) self.quitRunningStringShorcut = QShortcut(QKeySequence("Ctrl+Q"), self) self.quitRunningStringShorcut.activated.connect( self.quit_running_string_clicked) self.quitRunningStringPushButton.setToolTip("Ctrl+Q") self.closeAutomatonPushButton = QPushButton(self) self.closeAutomatonPushButton.setGeometry(465, 415, 111, 23) self.closeAutomatonPushButton.setText("Close Automaton") self.closeAutomatonPushButton.clicked.connect( self.close_automaton_clicked) self.closeAutomatonShorcut = QShortcut(QKeySequence("Ctrl+Alt+C"), self) self.closeAutomatonShorcut.activated.connect( self.close_automaton_clicked) self.closeAutomatonPushButton.setToolTip("Ctrl+Alt+C") # Style for status label text self.styleError = 'font: 15pt Arial; color: maroon' self.styleNormal = 'font:15pt Arial; color: green' self.statusBar = self.statusBar() self.statusLabel = QLabel( "application status messages will go here (when something completes, etc.)" ) self.statusLabel.setStyleSheet(self.styleNormal) self.statusBar.addPermanentWidget(self.statusLabel) self.show() def parseConfigFile(self, file_path): # Load the config settings self.Config_Setting.load(file_path) # Set the value parsed from the config file to the spinbox self.maxTransitionsSpinBox.setValue( int(self.Config_Setting.max_trans[0])) return def parseInputStringFile(self, file_path): # If the input string widget is empty add the input strings to the widget if self.inputStringListWidget.count() == 0: # Loading the string into the Strings attribute input_strings self.Strings.load(file_path) for string in self.Strings.input_strings: # If the string is valid if self.Strings.validate(self.Automaton.Input_Alpha.alphabet, string) == True: # Add the string to the widget self.inputStringListWidget.addItem(string) return # A method to update the input string widget def update_input_string_widget(self): self.inputStringListWidget.clear() for string in self.Strings.input_strings: self.inputStringListWidget.addItem(string) def quit_action(self): sys.exit(0) def open_automaton_action(self): #self.outputPlainTextEdit.setPlainText("Open Automaton Clicked") # Save the location of the def file self.def_path, _ = QFileDialog.getOpenFileName( self, "Select Definition File", "", ".def files (*.def)") #self.def_path = 'pda.def' #self.invalid_def_path = 'invalid_pda.def' # Check if the defintion file is valid Valid_def = Validate_Def_File(self.def_path) if Valid_def.def_valid == True: # Load the Automaton self.Automaton.load(self.def_path) # Store the the automaton is opened self.automaton_open = True # Set def path to the status bar self.statusLabel.setText(self.def_path) # Now parse config file self.parseConfigFile(self.def_path) # Now parse the input strings self.parseInputStringFile(self.def_path) # Set normal label styling self.statusLabel.setStyleSheet(self.styleNormal) # Change automaton title label self.fileNameLabel.setText(self.def_path.split("/")[-1]) else: error_list = [] error_list = Valid_def.is_invalid_def() for item in error_list: self.outputPlainTextEdit.appendPlainText(item) # Set status label status = self.def_path + " is invalid!" self.statusLabel.setText(status) # Set error label styling self.statusLabel.setStyleSheet(self.styleError) return #def view_automaton_action(self): # self.outputPlainTextEdit.setPlainText("View Automaton Clicked") # file = open(self.def_path, 'r') # for line in file: # self.outputPlainTextEdit.appendPlainText(line) # return def user_manual_action(self): userMan = HelpMenu() userMan.__init__() def add_to_list_clicked(self): # If the user just clicks add string if (self.inputStringLineEdit.text() == ''): return if self.Strings.is_duplicate(self.inputStringLineEdit.text()) == True: status = self.inputStringLineEdit.text() + ' is a duplicate string' self.statusLabel.setText(status) self.statusLabel.setStyleSheet(self.styleError) self.inputStringLineEdit.clear() return if self.Strings.validate(self.Automaton.Input_Alpha.alphabet, self.inputStringLineEdit.text()) == True: self.Strings.add_input_string(self.Automaton.Input_Alpha.alphabet, self.inputStringLineEdit.text()) self.update_input_string_widget() # Make new string the selected string self.inputStringListWidget.setCurrentRow( (self.inputStringListWidget.count() - 1)) self.inputStringLineEdit.clear() self.statusLabel.setStyleSheet(self.styleNormal) self.statusLabel.setText('') else: status = self.inputStringLineEdit.text() + ' is not a valid string' self.statusLabel.setText(status) self.statusLabel.setStyleSheet(self.styleError) self.update_input_string_widget() self.inputStringLineEdit.clear() return def run_string_clicked(self): selected_string = '' if len(self.inputStringListWidget.selectedItems()) > 0: selected_string = self.inputStringListWidget.selectedItems( )[0].text() else: self.statusLabel.setStyleSheet(self.styleError) self.statusLabel.setText('No input string selected') #self.outputPlainTextEdit.setPlainText("Run String Button Clicked") self.Automaton.run_string(selected_string) outputTransitions = self.Automaton.transitions_list outputStack = self.Automaton.stack outputPath = str(outputTransitions[0]) #self.outputPlainTextEdit.setPlainText(outputTransitions) for element in outputTransitions: self.outputPlainTextEdit.setPlainText(str(element)) #self.stackPlainTextEdit.setPlainText(outputStack) #add \n's self.stackPlainTextEdit.setPlainText("") for char in outputStack: self.stackPlainTextEdit.appendPlainText(char) if (self.displayPathsCheckBox.isChecked()): self.pathPlainTextEdit.appendPlainText(outputPath + " -> ") #add ->'s def quit_running_string_clicked(self): self.outputPlainTextEdit.setPlainText( "Quit Running String Button Clicked") return def close_automaton_clicked(self): self.outputPlainTextEdit.clear() self.inputStringListWidget.clear() self.statusLabel.clear() self.outputPlainTextEdit.setPlainText("Close Automaton Button Clicked") return
class Dialog(QWidget): def __init__(self, upgrades, security_upgrades, packages, reboot_required, upg_path): QWidget.__init__(self) self.upgrades = upgrades self.security_upgrades = security_upgrades self.upg_path = upg_path self.packages = packages self.initUI() self.upgradeBtn.clicked.connect(self.call_upgrade) self.closeBtn.clicked.connect(self.call_reject) def initUI(self): self.label = QLabel() self.label.setAlignment(Qt.AlignHCenter) self.upgradeBtn = QPushButton("Upgrade") self.closeBtn = QPushButton("Close") self.plainTextEdit = QPlainTextEdit() text = "" self.plainTextEdit.setVisible(False) self.plainTextEdit.setReadOnly(True) self.plainTextEdit.setEnabled(False) palette = self.plainTextEdit.palette() palette.setColor(QPalette.Base, Qt.black) palette.setColor(QPalette.Text, Qt.gray) self.plainTextEdit.setPalette(palette) hbox = QHBoxLayout() hbox.addStretch(1) hbox.addWidget(self.upgradeBtn) hbox.addWidget(self.closeBtn) hbox.addStretch(1) vbox = QVBoxLayout() vbox.addWidget(self.label) vbox.addWidget(self.plainTextEdit) vbox.addLayout(hbox) if self.upg_path == None: self.upgradeBtn.setVisible(False) self.setLayout(vbox) self.setGeometry(300, 300, 500, 150) self.setWindowTitle("Update Notifier") self.center() if self.upgrades > 0: text = "There are(is) %s upgrade(s) available and %s security update(s) available" % ( self.upgrades, self.security_upgrades) self.plainTextEdit.setVisible(True) for pkg in self.packages: self.plainTextEdit.appendPlainText(str(pkg)) if reboot_required: if text == "": text = "Reboot is needed" self.upgradeBtn.setVisible(False) else: text = text + "\nReboot is needed" self.label.setText(text) self.plainTextEdit.setEnabled(True) def center(self): frameGm = self.frameGeometry() screen = QApplication.desktop().screenNumber( QApplication.desktop().cursor().pos()) centerPoint = QApplication.desktop().screenGeometry(screen).center() frameGm.moveCenter(centerPoint) self.move(frameGm.topLeft()) def call_reject(self): app.quit() def call_upgrade(self): self.label.setText("Upgrading....") #TODO maybe open another thread so notifier won't freeze cmd = ['lxqt-sudo', self.upg_path] #process = subprocess.Popen(self.upg_path) #process = subprocess.Popen(cmd) # process = subprocess.Popen(cmd, shell=True) process = subprocess.Popen(cmd) process.wait() app.quit()
class Window1(QWidget): global trysin def __init__(self): super().__init__() self.title = "SaPa" self.top = 250 self.left = 250 self.width = 600 self.height = 600 self.InitWindow() self.trysin = 0 def InitWindow(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) # Create textbox self.textboxA = QLineEdit(self) self.textboxA.move(5, 320) self.textboxA.resize(185, 40) # Create textbox self.textboxU = QLineEdit(self) self.textboxU.move(205, 320) self.textboxU.resize(185, 40) # Create textbox self.textboxP = QLineEdit(self) self.textboxP.move(405, 320) self.textboxP.resize(185, 40) #Create a Button self.buttonC = QPushButton('Εισαγωγή', self) self.buttonC.move(405, 400) #Create a Button self.buttonD = QPushButton('Διαγραφή', self) self.buttonD.move(5, 400) # Connect button to function click self.buttonC.clicked.connect(self.buttonClickC) self.buttonD.clicked.connect(self.buttonClickD) #Create iosapa Obj iosapa = IoSapa() #Create Plain TextEdit self.pt = QPlainTextEdit(self) i = 0 z = 0 x = 0 filename = glob.glob("data/*.txt") for i in filename: with open(str(filename[x]), "r+") as fo: for line in fo: print(line) self.pt.appendPlainText(line) self.pt.appendPlainText("----------------------------") x += 1 # for x in iosapa.readF(): # print(x) # self.pt.appendPlainText(str(x)) self.pt.move(5, 5) self.pt.resize(590, 300) #Create Lable # label = QLabel(self) #label.setFrameStyle(QFrame.Panel) #label.setText(iosapa.readF()) #label.setGeometry(5,5,450,500) #label.setAlignment(QtCore.Qt.AlignLeft) #self.show() def buttonClickC(self): iosapa = IoSapa() iosapa.writeF(str(self.textboxA.text()), str(self.textboxU.text()), str(self.textboxP.text())) #window = Window1() #window.InitWindow() def buttonClickD(self): iosapa = IoSapa() iosapa.removeF(str(self.textboxA.text()))