class TestUnitFrame(QFrame): def __init__(self, win_idx: int): super().__init__() self.setFrameStyle(QFrame.StyledPanel) self.setAutoFillBackground(True) self.script = QThread() self.script.start() self.script.quit() self.win_idx = win_idx #COM Label self.com_label = QLabel('COM') #状态Label self.status_label = QLabel('状态') #异常信息 self.error_label = QLabel('') self.error_label.setStyleSheet('.QLabel {color:#A57A80;}') leftLayout = QVBoxLayout() leftLayout.setSpacing(5) leftLayout.addWidget(self.com_label) leftLayout.addWidget(self.status_label) leftLayout.addWidget(self.error_label) leftLayout.addStretch(1) ####显示关键信息 self.productmodel_label = QLabel('') self.softversoin_label = QLabel('') self.chipid_label = QLabel('') #测试按钮 self.start_button = QPushButton('测试', clicked=self.onUnitTest) self.start_button.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) rightLayout = QVBoxLayout() rightLayout.addWidget(self.productmodel_label) rightLayout.addWidget(self.softversoin_label) rightLayout.addWidget(self.chipid_label) rightLayout.addStretch(1) rightLayout.addWidget(self.start_button) rightLayout.setAlignment(self.start_button, Qt.AlignRight) #总布局 mainlayout = QHBoxLayout() mainlayout.addLayout(leftLayout) mainlayout.addLayout(rightLayout) mainlayout.setStretchFactor(leftLayout, 4) mainlayout.setStretchFactor(rightLayout, 1) self.setLayout(mainlayout) self.devInitState() def devInitState(self): dev = Config.RC[self.win_idx]['dev'] if dev.status == DevStatus.exception: self.com_label.setText('{}[error]'.format(dev.name)) self.status_label.setText('串口异常') self.status_label.setStyleSheet('color: red;') elif dev.status == DevStatus.opened: self.com_label.setText('{name}[{baudrate}]'.format(**dev.settings)) self.status_label.setStyleSheet('') self.status_label.setText('连接成功') def onUnitTest(self, checked): dev = Config.RC[self.win_idx]['dev'] self.error_label.setText('') if self.script.isFinished( ) and dev.status == DevStatus.opened and Config.PRODUCT_XML: pub.sendMessage(Config.TOPIC_STARTTEST, win=self) elif Config.PRODUCT_XML is None: self.status_label.setStyleSheet('color: red;') self.status_label.setText('未选择产品型号') elif dev.status in [DevStatus.closed, DevStatus.exception]: self.status_label.setStyleSheet('color: red;') self.status_label.setText('串口未设置') def contextMenuEvent(self, event): menu = QMenu() item = menu.addAction('单元设置') menu.addAction('停止测试', self.onStop) menu.addAction('串口设置', lambda: self.onSetting(event)) menu.addAction('断开串口', self.onDisconnect) menu.addAction('重连串口', self.onReconnect) item.setEnabled(False) menu.move(event.globalPos()) menu.exec() def onStop(self): if self.script.isRunning(): self.script.stop() def onSetting(self, event): dlg = SerialSettingDialog(self) dlg.move(event.globalPos()) dev = Config.RC[self.win_idx]['dev'] if dlg.exec(): settings = dlg.getValue() dev.apply_settings(**settings) if dev.status == DevStatus.opened: dev.close() dev.connect() if dev.status == DevStatus.exception: self.com_label.setText('{}[error]'.format(settings['name'])) self.status_label.setText('串口异常') self.status_label.setStyleSheet('color: red;') else: self.com_label.setText('{name}[{baudrate}]'.format(**settings)) self.status_label.setStyleSheet('') self.status_label.setText('连接成功') if Config.FIXED_WIN_NUM == 2 and not Config.SCREEN_MODE: tab = Config.RC['tab'] tab.setCurrentIndex(self.win_idx) tab.setTabText(self.win_idx, settings['name']) def onDisconnect(self): dev = Config.RC[self.win_idx]['dev'] if dev.status == DevStatus.opened: dev.close() self.status_label.setStyleSheet('') self.status_label.setText('断开成功') def onReconnect(self): dev = Config.RC[self.win_idx]['dev'] if dev.status == DevStatus.closed: dev.connect() if dev.status == DevStatus.opened: self.status_label.setStyleSheet('') self.status_label.setText('重连成功') else: self.status_label.setStyleSheet('color: red;') self.status_label.setText('重连失败')
class ReTestButton(QWidget): def __init__(self, win_idx: int, top_item: ResultTreeWidgetItem): super().__init__() self.top_item = top_item self.win_idx = win_idx self.retest_bn = QPushButton(clicked=self.handle_click) self.retest_bn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.step = QThread() self.step.start() self.step.quit() layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addStretch(1) layout.addWidget(self.retest_bn) self.setLayout(layout) def handle_click(self, checked): if self.step.isFinished(): self.step = step.Step(self.win_idx, self.top_item.tag) self.step.sig_item_result.connect(self.handle_item_result) self.step.sig_child_item.connect(self.handle_child_item) self.step.sig_finish.connect(self.handle_finish) self.retest_bn.setIcon(self.style().standardIcon( QStyle.SP_MediaStop)) self.top_item.takeChildren() self.top_item.setIcon(0, QIcon()) self.top_item.setText(0, self.top_item.tag) self.step.start() for idx in range(self.top_item.columnCount()): self.top_item.setBackground(idx, Config.COLOR_GRAY) elif self.step.isRunning(): self.step.stop() def handle_finish(self, sec): origin_text = self.top_item.text(0) self.top_item.setText(0, '{} 测试时长:{:.2f}s'.format(origin_text, sec)) self.retest_bn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) def handle_child_item(self, child_item: mix.ChildItem): child_widget = QTreeWidgetItem(self.top_item) child_widget.setText(0, child_item.tag) child_widget.setText(1, child_item.msg) if child_item.result: bcolor = Config.COLOR_GREEN icon = QIcon(Config.PASS_IMG) else: bcolor = Config.COLOR_RED icon = QIcon(Config.FAIL_IMG) child_widget.setIcon(0, icon) # for i in range(child_widget.columnCount()): # child_widget.setBackground(i, bcolor) self.top_item.setExpanded(True) def handle_item_result(self, item_result: mix.ItemResult): if item_result.result: bcolor = Config.COLOR_GREEN icon = QIcon(Config.PASS_IMG) else: bcolor = Config.COLOR_RED icon = QIcon(Config.FAIL_IMG) self.top_item.setIcon(0, icon) self.top_item.setText( 0, '{}[{}]'.format(item_result.tag, item_result.total)) for i in range(self.top_item.columnCount()): self.top_item.setBackground(i, bcolor)
class CoreUI(QWidget): ''' Core Ui class ''' status_message = pyqtSignal(str) assets_path = "interface/rembot/assets/" def __init__(self, parent): super().__init__(parent) # Log class self.log = Log(self) self.log.log_data[str].connect(self.to_log) # Setup process self.bot_thread = QThread() self.linebot = LineBot() self.linebot.moveToThread(self.bot_thread) self.linebot.message[str].connect( self.linebot.log.info_log) # linebot stderr log self.linebot.log.log_data[str].connect( self.to_log) # display ability logger in ui self.linebot.end_FLAG.connect(self.bot_thread.quit) self.bot_thread.started.connect(self.linebot.run) self.bot_thread.finished.connect(self.bot_process_done) self.init_ui() def init_ui(self): ''' Rembot UI ''' self.setObjectName("CoreUI") # UI Contaier self.ui_container = QVBoxLayout(self) self.ui_container.setObjectName("ui_container") ## Header ### Box self.header_box = QHBoxLayout() self.header_box.setObjectName("header_box") self.header_box.setContentsMargins(10, 10, 10, 10) ### title font = QFont() font.setFamily("OCR A Extended") font.setPointSize(40) font.setBold(True) font.setItalic(False) font.setWeight(75) self.header_title = QLabel() self.header_title.setFont(font) self.header_title.setCursor(QCursor(Qt.ArrowCursor)) self.header_title.setLayoutDirection(Qt.LeftToRight) self.header_title.setStyleSheet("color: rgb(108, 204, 227);") self.header_title.setScaledContents(False) self.header_title.setAlignment(Qt.AlignLeading | Qt.AlignLeft | Qt.AlignVCenter) self.header_title.setContentsMargins(0, 0, 0, 0) self.header_title.setObjectName("header_title") self.header_box.addWidget(self.header_title) # add title to header ### version font = QFont() font.setFamily("Tahoma") font.setPointSize(10) font.setBold(True) font.setWeight(75) self.version_number = QLabel() self.version_number.setFont(font) self.version_number.setStyleSheet("color: rgb(85, 85, 85);") self.version_number.setAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter) self.version_number.setObjectName("version_number") self.header_box.addWidget( self.version_number) # add version number to header # Add to UI Container self.ui_container.addLayout( self.header_box) # add header box to layout # Content self.content_box = QHBoxLayout() self.content_box.setSizeConstraint(QLayout.SetDefaultConstraint) self.content_box.setContentsMargins(10, 10, 10, 10) self.content_box.setObjectName("content_box") ## Left Box self.left_box = QVBoxLayout() self.left_box.setSizeConstraint(QLayout.SetFixedSize) self.left_box.setContentsMargins(10, 10, 10, 10) self.left_box.setObjectName("left_box") ### File box self.file_box = QHBoxLayout() self.file_box.setContentsMargins(10, 10, 10, 10) self.file_box.setObjectName("file_box") #### File label font = QFont() font.setPointSize(10) self.file_label = QLabel() self.file_label.setFont(font) size_policy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) size_policy.setHorizontalStretch(0) size_policy.setVerticalStretch(0) size_policy.setHeightForWidth( self.file_label.sizePolicy().hasHeightForWidth()) self.file_label.setSizePolicy(size_policy) self.file_label.setObjectName("file_label") ### Add label to File box self.file_box.addWidget(self.file_label) #### File Input font = QFont() font.setPointSize(20) self.file_input = QLineEdit() self.file_input.setFont(font) self.file_input.setMinimumSize(QSize(0, 0)) self.file_input.setAcceptDrops(True) self.file_input.setLayoutDirection(Qt.LeftToRight) self.file_input.setText("") self.file_input.setFrame(True) self.file_input.setAlignment(Qt.AlignLeading | Qt.AlignLeft | Qt.AlignVCenter) self.file_input.setObjectName("file_input") #### Add File input to File box self.file_box.addWidget(self.file_input) ### Add File box to Left Box self.left_box.addLayout(self.file_box) #### Add Button box self.button_box = QGridLayout() self.button_box.setContentsMargins(10, 10, 10, 10) self.button_box.setObjectName("button_box") ##### Start Button self.start_button = QPushButton() self.start_button.setObjectName("start_button") ##### Stop Button self.stop_button = QPushButton() self.stop_button.setEnabled(False) self.stop_button.setObjectName("stop_button") ##### Test Button self.abort_button = QPushButton() self.abort_button.setEnabled(False) self.abort_button.setObjectName("abort_button") ##### Quit Button self.quit_button = QPushButton() self.quit_button.setObjectName("quit_button") #### Add Buttons to Button Box self.button_box.addWidget(self.start_button, 0, 0, 1, 1) self.button_box.addWidget(self.stop_button, 0, 1, 1, 1) self.button_box.addWidget(self.abort_button, 1, 0, 1, 1) self.button_box.addWidget(self.quit_button, 1, 1, 1, 1) ### Add Button box to Left box self.left_box.addLayout(self.button_box) #### Log Box and Layout self.log_box = QGroupBox() self.log_box.setFlat(True) self.log_box.setObjectName("log_box") self.log_layout = QVBoxLayout(self.log_box) self.log_layout.setContentsMargins(0, 10, 0, 0) self.log_layout.setObjectName("log_layout") ##### Log output self.log_output = QTextEdit(self.log_box) self.log_output.setMinimumSize(QSize(720, 600)) self.log_output.setReadOnly(True) self.log_output.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.log_output.setObjectName("log_output") #### Add Log Output to Log box | Log layout self.log_layout.addWidget(self.log_output) ### Add Log box to Left box self.left_box.addWidget(self.log_box) #### Left spacer self.spacer_item = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.MinimumExpanding) ### Add spacer to Log box self.left_box.addItem(self.spacer_item) ## Add Left box to Content box self.content_box.addLayout(self.left_box) ### Right Box self.right_box = QVBoxLayout() self.right_box.setSizeConstraint(QLayout.SetMinAndMaxSize) self.right_box.setContentsMargins(10, 10, 10, 10) self.right_box.setObjectName("right_box") #### Origninal image box self.original_img_box = QGroupBox() self.original_img_box.setFlat(True) self.original_img_box.setObjectName("original_img_box") self.original_img_layout = QVBoxLayout(self.original_img_box) self.original_img_layout.setContentsMargins(0, 0, 0, 0) self.original_img_layout.setObjectName("original_img_layout") ##### Original image self.original_img = QLabel(self.original_img_box) self.original_img.setMinimumSize(QSize(720, 400)) self.original_img.setText("") self.default_img = self.assets_path + "default.jpg" self.original_img.setPixmap(QPixmap(self.default_img)) # self.original_img.setScaledContents(True) self.original_img.setObjectName("original_img") #### Add Original image to Original image Layout self.original_img_layout.addWidget(self.original_img) ### Add Original image box to Right box self.right_box.addWidget(self.original_img_box) #### Output image box self.output_img_box = QGroupBox() self.output_img_box.setFlat(True) self.output_img_box.setObjectName("output_img_box") self.output_img_layout = QHBoxLayout(self.output_img_box) self.output_img_layout.setContentsMargins(0, 0, 0, 0) self.output_img_layout.setObjectName("output_img_layout") ##### Output image self.output_img = QLabel(self.output_img_box) # self.output_img.setMinimumSize(QSize(720, 400)) self.output_img.setText("") self.output_img.setPixmap(QPixmap(self.default_img)) self.output_img.setObjectName("output_img") #### Add Output img to output image layout self.output_img_layout.addWidget(self.output_img) ### Add Output image box to Right box self.right_box.addWidget(self.output_img_box) ## Add Right box to Content box self.content_box.addLayout(self.right_box) # Add Content box to UI Container self.ui_container.addLayout( self.content_box) # add content box to layout # Labelling self._translate = QCoreApplication.translate self.retranslate_ui() QMetaObject.connectSlotsByName(self) # Attach signals self.attach_events() def retranslate_ui(self): ''' UI Text ''' self.header_title.setText(self._translate("CoreUI", "REMBOT")) self.version_number.setText(self._translate("CoreUI", "")) self.file_label.setText(self._translate("CoreUI", "File name")) self.file_input.setPlaceholderText( self._translate("CoreUI", "image.ext")) self.start_button.setText(self._translate("CoreUI", "START")) self.stop_button.setText(self._translate("CoreUI", "STOP")) self.abort_button.setText(self._translate("CoreUI", "ABORT")) self.quit_button.setText(self._translate("CoreUI", "QUIT")) self.log_box.setTitle(self._translate("CoreUI", "Log")) self.original_img_box.setTitle( self._translate("CoreUI", "Original Image")) self.output_img_box.setTitle(self._translate("CoreUI", "Output Image")) # Default images self.default_img = self.assets_path + "default.jpg" self.original_img.setPixmap(QPixmap(self.default_img)) self.output_img.setPixmap(QPixmap(self.default_img)) def attach_events(self): ''' Attach signals to events ''' self.start_button.clicked.connect(self.start) self.stop_button.clicked.connect(self.stop) def update_status(self, msg): ''' Update the program statusbar string and log ''' self.status_message.emit(msg) def to_log(self, msg): ''' Output message in ui window ''' self.log_output.append(msg) # Abilities def start(self): ''' Start program ''' self.line_bot() def stop(self): ''' Stop Any running process ''' self.linebot.process_done(1) self.bot_thread.stop() self.bot_thread.wait() def bot_process_done(self): ''' Reset ui when a process is done ''' self.stop_button.setEnabled(False) # disable Stop self.abort_button.setEnabled(False) # disable abort self.start_button.setEnabled(True) # enable start # Reset images self.original_img.setPixmap(QPixmap(self.default_img)) self.original_img.setPixmap(QPixmap(self.default_img)) self.log.info_log("Process done!") # log self.update_status("Ready") def line_bot(self): ''' Start linebot program ''' # Get file from assets_path using user input file_path = self.assets_path + self.file_input.text( ) # specify filepath if os.path.exists(file_path) and file_path[-1] != '/': self.log.info_log("Loading File") # log self.original_img.setPixmap( QPixmap(file_path)) # update display image reply = QMessageBox.question(self, 'Run linebot program ?', "Contine to process ?", \ QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: self.stop_button.setEnabled(False) # enable stop button self.start_button.setEnabled(False) # disable start button # Run process self.linebot.imgpath = file_path self.bot_thread.start() self.update_status("Running ...") else: self.log.info_log("Aborting.") # log else: self.log.warning_log("File does not exist") # log