def __init__( self, onOpenLogButtonPressed: Callable[[], None], onAgentVarsButtonPressed: Callable[[], None], parent: Optional[QWidget] = None, *args: Tuple[Any, Any], **kwargs: Tuple[Any, Any], ) -> None: """ The "Open Log" and "Agent Variables" buttons view used for opening those windows. """ super(SolverWindowsButtonsView, self).__init__(parent=parent, *args, **kwargs) self.setContentsMargins(0, 0, 0, 0) layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) # define the buttons openLogButton = QPushButton("Open Log") agentVarsButton = QPushButton("Agent Variables") # connect them to their respective methods openLogButton.pressed.connect(onOpenLogButtonPressed) # type: ignore agentVarsButton.pressed.connect(onAgentVarsButtonPressed) # type: ignore layout.addWidget(openLogButton) layout.addWidget(agentVarsButton) layout.setAlignment(openLogButton, Qt.Alignment.AlignHCenter) layout.setAlignment(agentVarsButton, Qt.Alignment.AlignHCenter) self.setLayout(layout)
def __init__(self, parent, top): super(QWidget, self).__init__(parent) self.top = top hlayout = QHBoxLayout() self.layout = QGridLayout() hlayout.addLayout(self.layout) hlayout.setAlignment(hlayout, Qt.Alignment.AlignTop) self.setLayout(hlayout) self.row = 0 self.__addLabel__("Federate Name") self.federateName = QLineEdit('REMOTE_WORKSTATION') self.__addInput__(self.federateName) self.__addLabel__("Message Directory Cache") self.messageDirectoryCache = QLineEdit(self) self.__addInputAndSelect__(self.messageDirectoryCache, self.top) self.__addLabel__("Map Data Cache") self.mapDataCache = QLineEdit(self) self.__addInputAndSelect__(self.mapDataCache, self.top) self.__addLabel__("Raster Map Cache") self.rasterMapCache = QLineEdit(self) self.__addInputAndSelect__(self.rasterMapCache, self.top) self.__addLabel__("Remote Control Location") self.remoteControlLocation = QLineEdit(self) self.__addInputAndSelect__(self.remoteControlLocation, self.top)
def __init__(self, parent, top): super(QWidget, self).__init__(parent) self.top = top hlayout = QHBoxLayout() self.layout = QGridLayout() hlayout.addLayout(self.layout) hlayout.setAlignment(hlayout, Qt.Alignment.AlignTop) self.setLayout(hlayout) self.row = 0 self.__addLabel__("Gateway Services") self.__addLabel__("Gateway Host Name/IP Address") self.gatewayHostName = QLineEdit(self) self.__addInput__(self.gatewayHostName) self.__addLabel__("Exercise Data Server Host Name/IP Address") self.productionEDS = QLineEdit(self) self.prodEnable = QRadioButton("Production") self.prodEnable.setChecked(True) self.prodEnable.toggled.connect(self.radioProdClicked) self.prodEnable.setStyleSheet("QRadioButton{ width: 100; }") self.__addInputAndRadio__(self.productionEDS, self.prodEnable) self.testEDS = QLineEdit(self) self.testEnable = QRadioButton("Test") self.testEnable.toggled.connect(self.radioTestClicked) self.testEnable.setStyleSheet("QRadioButton{ width: 100; }") self.__addInputAndRadio__(self.testEDS, self.testEnable) self.__addLabel__("Messaging Port") self.messagePort = QLineEdit("61616") self.__addInput__(self.messagePort)
def createRow(self, exercise, index): item = QHBoxLayout() label = QLabel(exercise.name) item.addWidget(label) item.setAlignment(label, Qt.Alignment.AlignCenter) button = QPushButton(exercise.assigned_key[0]) # button.installEventFilter(self) button.setStyleSheet(""" QPushButton { border: 1px solid grey; background-color: white; } """) button.clicked.connect(partial(self.openDialog, button)) self.buttons.append(button) item.addWidget(button) self.mainLayout.addLayout(item, index, 0) print(index, exercise.name, exercise.assigned_key)
class DocumentBaseViewerWidget(MainWindowContent): def __init__(self, main_window): super(DocumentBaseViewerWidget, self).__init__(main_window, "Document Base") # controls self.controls = QWidget() self.controls_layout = QHBoxLayout(self.controls) self.controls_layout.setContentsMargins(0, 0, 0, 0) self.controls_layout.setSpacing(10) self.controls_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) self.layout.addWidget(self.controls) self.create_document_base_button = QPushButton( "Create a new Document Base") self.create_document_base_button.setFont(BUTTON_FONT) self.create_document_base_button.clicked.connect( self.main_window.show_document_base_creator_widget_task) self.controls_layout.addWidget(self.create_document_base_button) self.load_and_run_default_preprocessing_phase_button = QPushButton( "Preprocess the Document Base") self.load_and_run_default_preprocessing_phase_button.setFont( BUTTON_FONT) self.load_and_run_default_preprocessing_phase_button.clicked.connect( self.main_window.load_and_run_default_preprocessing_phase_task) self.controls_layout.addWidget( self.load_and_run_default_preprocessing_phase_button) self.load_and_run_default_matching_phase_button = QPushButton( "Match the Nuggets to the Attributes") self.load_and_run_default_matching_phase_button.setFont(BUTTON_FONT) self.load_and_run_default_matching_phase_button.clicked.connect( self.main_window.load_and_run_default_matching_phase_task) self.controls_layout.addWidget( self.load_and_run_default_matching_phase_button) self.save_table_button = QPushButton("Export the Table to CSV") self.save_table_button.setFont(BUTTON_FONT) self.save_table_button.clicked.connect( self.main_window.save_table_to_csv_task) self.controls_layout.addWidget(self.save_table_button) # documents self.documents = MainWindowContentSection(self, "Documents:") self.layout.addWidget(self.documents) self.num_documents = QLabel("number of documents: -") self.num_documents.setFont(LABEL_FONT) self.documents.layout.addWidget(self.num_documents) self.num_nuggets = QLabel("number of nuggets: -") self.num_nuggets.setFont(LABEL_FONT) self.documents.layout.addWidget(self.num_nuggets) # attributes self.attributes = MainWindowContentSection(self, "Attributes:") self.layout.addWidget(self.attributes) self.add_attribute_button = QPushButton("Add Attribute") self.add_attribute_button.setFont(BUTTON_FONT) self.add_attribute_button.clicked.connect( self.main_window.add_attribute_task) self.attributes_list = CustomScrollableList(self, AttributeWidget, self.add_attribute_button) self.attributes.layout.addWidget(self.attributes_list) def update_document_base(self, document_base): # update documents self.num_documents.setText( f"number of documents: {len(document_base.documents)}") self.num_nuggets.setText( f"number of nuggets: {len(document_base.nuggets)}") # update attributes self.attributes_list.update_item_list(document_base.attributes, document_base) def enable_input(self): self.create_document_base_button.setEnabled(True) if self.main_window.document_base is not None: self.load_and_run_default_preprocessing_phase_button.setEnabled( True) self.load_and_run_default_matching_phase_button.setEnabled(True) self.save_table_button.setEnabled(True) self.add_attribute_button.setEnabled(True) self.attributes_list.enable_input() def disable_input(self): self.create_document_base_button.setDisabled(True) self.load_and_run_default_preprocessing_phase_button.setDisabled(True) self.load_and_run_default_matching_phase_button.setDisabled(True) self.save_table_button.setDisabled(True) self.add_attribute_button.setDisabled(True) self.attributes_list.disable_input()
class DocumentBaseCreatorWidget(MainWindowContent): def __init__(self, main_window) -> None: super(DocumentBaseCreatorWidget, self).__init__(main_window, "Create Document Base") self.documents = MainWindowContentSection(self, "Documents:") self.layout.addWidget(self.documents) self.documents_explanation = QLabel( "Enter the path of the directory that contains the documents as .txt files." ) self.documents_explanation.setFont(LABEL_FONT) self.documents.layout.addWidget(self.documents_explanation) self.path_widget = QFrame() self.path_layout = QHBoxLayout(self.path_widget) self.path_layout.setContentsMargins(20, 0, 20, 0) self.path_layout.setSpacing(10) self.path_widget.setStyleSheet("background-color: white") self.path_widget.setFixedHeight(40) self.documents.layout.addWidget(self.path_widget) self.path = QLineEdit() self.path.setFont(CODE_FONT_BOLD) self.path.setStyleSheet("border: none") self.path_layout.addWidget(self.path) self.edit_path_button = QPushButton() self.edit_path_button.setIcon(QIcon("aset_ui/resources/folder.svg")) self.edit_path_button.setFlat(True) self.edit_path_button.clicked.connect(self._edit_path_button_clicked) self.path_layout.addWidget(self.edit_path_button) self.attributes = MainWindowContentSection(self, "Attributes:") self.layout.addWidget(self.attributes) self.labels_explanation = QLabel("Enter the attribute names.") self.labels_explanation.setFont(LABEL_FONT) self.attributes.layout.addWidget(self.labels_explanation) self.create_attribute_button = QPushButton("New Attribute") self.create_attribute_button.setFont(BUTTON_FONT) self.create_attribute_button.clicked.connect( self._create_attribute_button_clicked) self.attribute_names = [] self.attributes_list = CustomScrollableList( self, AttributeCreatorWidget, self.create_attribute_button) self.attributes.layout.addWidget(self.attributes_list) self.buttons_widget = QWidget() self.buttons_layout = QHBoxLayout(self.buttons_widget) self.buttons_layout.setContentsMargins(0, 0, 0, 0) self.buttons_layout.setSpacing(10) self.buttons_layout.setAlignment(Qt.AlignmentFlag.AlignRight) self.attributes.layout.addWidget(self.buttons_widget) self.cancel_button = QPushButton("Cancel") self.cancel_button.setFont(BUTTON_FONT) self.cancel_button.clicked.connect(self._cancel_button_clicked) self.buttons_layout.addWidget(self.cancel_button) self.create_document_base_button = QPushButton("Create Document Base") self.create_document_base_button.setFont(BUTTON_FONT) self.create_document_base_button.clicked.connect( self._create_document_base_button_clicked) self.buttons_layout.addWidget(self.create_document_base_button) def enable_input(self): self.edit_path_button.setEnabled(True) self.create_attribute_button.setEnabled(True) self.cancel_button.setEnabled(True) self.create_document_base_button.setEnabled(True) self.attributes_list.enable_input() def disable_input(self): self.edit_path_button.setDisabled(True) self.create_attribute_button.setDisabled(True) self.cancel_button.setDisabled(True) self.create_document_base_button.setDisabled(True) self.attributes_list.disable_input() def initialize_for_new_document_base(self): self.path.setText("") self.attribute_names = [] self.attributes_list.update_item_list([]) def delete_attribute(self, attribute_name): self.attribute_names = [] for attribute_widget in self.attributes_list.item_widgets[:self. attributes_list . num_visible_item_widgets]: self.attribute_names.append(attribute_widget.name.text()) self.attribute_names.remove(attribute_name) self.attributes_list.update_item_list(self.attribute_names) self.attributes_list.last_item_widget().name.setFocus() def _edit_path_button_clicked(self): path = str( QFileDialog.getExistingDirectory( self, "Choose a directory of text files.")) if path != "": path = f"{path}/*.txt" self.path.setText(path) def _create_attribute_button_clicked(self): self.attribute_names = [] for attribute_widget in self.attributes_list.item_widgets[:self. attributes_list . num_visible_item_widgets]: self.attribute_names.append(attribute_widget.name.text()) self.attribute_names.append("") self.attributes_list.update_item_list(self.attribute_names) self.attributes_list.last_item_widget().name.setFocus() def _cancel_button_clicked(self): self.main_window.show_start_menu_widget() self.main_window.enable_global_input() def _create_document_base_button_clicked(self): self.attribute_names = [] for attribute_widget in self.attributes_list.item_widgets[:self. attributes_list . num_visible_item_widgets]: self.attribute_names.append(attribute_widget.name.text()) self.main_window.create_document_base_task(self.path.text(), self.attribute_names)
def __init__(self, parent): super(QWidget, self).__init__(parent) hlayout = QHBoxLayout() self.layout = QGridLayout() hlayout.addLayout(self.layout) hlayout.setAlignment(hlayout, Qt.Alignment.AlignTop) self.setLayout(hlayout) self.row = 0 self.__addLine__( "Python Version:", "{}.{}.{} {}".format(sys.version_info.major, sys.version_info.minor, sys.version_info.micro, sys.version_info.releaselevel)) self.__addLine__("Qt Version:", PYQT_VERSION_STR) if path.isfile('/etc/system-release'): with open('/etc/system-release', 'r') as reader: dist = reader.readline() self.__addLine__("Distribution:", dist.strip()) elif path.isfile('/etc/lsb-release'): with open('/etc/lsb-release') as reader: lsb = reader.readlines() line = str(lsb[-1]) dist = line.strip().split("=")[-1].strip('"') self.__addLine__("Distribution:", dist) self.__addLine__("Operating System:", platform.uname().system) self.__addLine__("Kernel Release:", platform.uname().release) self.__addLine__( "Total Physical Memory:", "{:.1f} GiB".format(psutil.virtual_memory().total / (1024**3))) self.__addLine__( "Root Disk Space as Total/Used/Free:", "{:.1f} GiB/{:.1f} GiB/{:.1f} GiB".format( psutil.disk_usage('/').total / (1024**3), psutil.disk_usage('/').used / (1024**3), psutil.disk_usage('/').free / (1024**3))) self.__addLine__( "Swap Space as Total/Used/Free:", "{:.1f} GiB/{:.2f} GiB/{:.1f} GiB".format( psutil.swap_memory().total / (1024**3), psutil.swap_memory().used / (1024**3), psutil.swap_memory().free / (1024**3))) if hasattr(psutil, 'cpu-thermal') and callable( getattr(psutil, 'cpu-thermal')): self.__addLine__( "CPU Temperature:", "{:.1f}\xb0 C".format( psutil.sensors_temperatures()['cpu-thermal'][0].current)) elif hasattr(psutil, 'thermal-fan-est') and callable( getattr(psutil, 'thermal-fan-est')): self.__addLine__( "CPU Temperature:", "{:.1f}\xb0 C".format(psutil.sensors_temperatures() ['thermal-fan-est'][0].current))
class MainWindow(QMainWindow): ################################ # signals (aset ui --> aset api) ################################ create_document_base = pyqtSignal(str, list) add_attribute = pyqtSignal(str, ASETDocumentBase) remove_attribute = pyqtSignal(str, ASETDocumentBase) forget_matches_for_attribute = pyqtSignal(str, ASETDocumentBase) load_document_base_from_bson = pyqtSignal(str) save_document_base_to_bson = pyqtSignal(str, ASETDocumentBase) save_table_to_csv = pyqtSignal(str, ASETDocumentBase) forget_matches = pyqtSignal(ASETDocumentBase) load_preprocessing_phase_from_config = pyqtSignal(str) save_preprocessing_phase_to_config = pyqtSignal(str, PreprocessingPhase) load_matching_phase_from_config = pyqtSignal(str) save_matching_phase_to_config = pyqtSignal(str, BaseMatchingPhase) run_preprocessing_phase = pyqtSignal(ASETDocumentBase, PreprocessingPhase, Statistics) run_matching_phase = pyqtSignal(ASETDocumentBase, BaseMatchingPhase, Statistics) save_statistics_to_json = pyqtSignal(str, Statistics) load_and_run_default_preprocessing_phase = pyqtSignal(ASETDocumentBase, Statistics) load_and_run_default_matching_phase = pyqtSignal(ASETDocumentBase, Statistics) ############################## # slots (aset api --> aset ui) ############################## @pyqtSlot(str, float) def status(self, message, progress): logger.debug("Called slot 'status'.") self.status_widget_message.setText(message) if progress == -1: self.status_widget_progress.setRange(0, 0) else: self.status_widget_progress.setRange(0, 100) self.status_widget_progress.setValue(int(progress * 100)) @pyqtSlot(str) def finished(self, message): logger.debug("Called slot 'finished'.") self.status_widget_message.setText(message) self.status_widget_progress.setRange(0, 100) self.status_widget_progress.setValue(100) self.show_document_base_viewer_widget() self.enable_global_input() @pyqtSlot(str) def error(self, message): logger.debug("Called slot 'error'.") self.status_widget_message.setText(message) self.status_widget_progress.setRange(0, 100) self.status_widget_progress.setValue(0) self.show_document_base_viewer_widget() self.enable_global_input() @pyqtSlot(ASETDocumentBase) def document_base_to_ui(self, document_base): logger.debug("Called slot 'document_base_to_ui'.") self.document_base = document_base self.document_base_viewer_widget.update_document_base(self.document_base) self._was_enabled.append(self.save_document_base_to_bson_action) self._was_enabled.append(self.save_table_to_csv_action) self._was_enabled.append(self.add_attribute_action) self._was_enabled.append(self.remove_attribute_action) self._was_enabled.append(self.forget_matches_for_attribute_action) self._was_enabled.append(self.forget_matches_action) self._was_enabled.append(self.load_and_run_default_preprocessing_phase_action) self._was_enabled.append(self.load_and_run_default_matching_phase_action) if self.preprocessing_phase is not None: self._was_enabled.append(self.run_preprocessing_phase_action) if self.matching_phase is not None: self._was_enabled.append(self.run_matching_phase_action) @pyqtSlot(PreprocessingPhase) def preprocessing_phase_to_ui(self, preprocessing_phase): logger.debug("Called slot 'preprocessing_phase_to_ui'.") self.preprocessing_phase = preprocessing_phase self._was_enabled.append(self.save_preprocessing_phase_to_config_action) if self.document_base is not None: self._was_enabled.append(self.run_preprocessing_phase_action) @pyqtSlot(BaseMatchingPhase) def matching_phase_to_ui(self, matching_phase): logger.debug("Called slot 'matching_phase_to_ui'.") self.matching_phase = matching_phase self._was_enabled.append(self.save_matching_phase_to_config_action) if self.document_base is not None: self._was_enabled.append(self.run_preprocessing_phase_action) @pyqtSlot(Statistics) def statistics_to_ui(self, statistics): logger.debug("Called slot 'statistics_to_ui'.") self.statistics = statistics @pyqtSlot(dict) def feedback_request_to_ui(self, feedback_request): logger.debug("Called slot 'feedback_request_to_ui'.") self.interactive_matching_widget.handle_feedback_request(feedback_request) # noinspection PyUnresolvedReferences def _connect_slots_and_signals(self): self.create_document_base.connect(self.api.create_document_base) self.add_attribute.connect(self.api.add_attribute) self.remove_attribute.connect(self.api.remove_attribute) self.forget_matches_for_attribute.connect(self.api.forget_matches_for_attribute) self.load_document_base_from_bson.connect(self.api.load_document_base_from_bson) self.save_document_base_to_bson.connect(self.api.save_document_base_to_bson) self.save_table_to_csv.connect(self.api.save_table_to_csv) self.forget_matches.connect(self.api.forget_matches) self.load_preprocessing_phase_from_config.connect(self.api.load_preprocessing_phase_from_config) self.save_preprocessing_phase_to_config.connect(self.api.save_preprocessing_phase_to_config) self.load_matching_phase_from_config.connect(self.api.load_matching_phase_from_config) self.save_matching_phase_to_config.connect(self.api.save_matching_phase_to_config) self.run_preprocessing_phase.connect(self.api.run_preprocessing_phase) self.run_matching_phase.connect(self.api.run_matching_phase) self.save_statistics_to_json.connect(self.api.save_statistics_to_json) self.load_and_run_default_preprocessing_phase.connect(self.api.load_and_run_default_preprocessing_phase) self.load_and_run_default_matching_phase.connect(self.api.load_and_run_default_matching_phase) self.api.status.connect(self.status) self.api.finished.connect(self.finished) self.api.error.connect(self.error) self.api.document_base_to_ui.connect(self.document_base_to_ui) self.api.preprocessing_phase_to_ui.connect(self.preprocessing_phase_to_ui) self.api.matching_phase_to_ui.connect(self.matching_phase_to_ui) self.api.statistics_to_ui.connect(self.statistics_to_ui) self.api.feedback_request_to_ui.connect(self.feedback_request_to_ui) ####### # tasks ####### def load_document_base_from_bson_task(self): logger.info("Execute task 'load_document_base_from_bson_task'.") path, ok = QFileDialog.getOpenFileName(self, "Choose a document collection .bson file!") if ok: self.disable_global_input() # noinspection PyUnresolvedReferences self.load_document_base_from_bson.emit(str(path)) def save_document_base_to_bson_task(self): logger.info("Execute task 'save_document_base_to_bson_task'.") if self.document_base is not None: path, ok = QFileDialog.getSaveFileName(self, "Choose where to save the document collection .bson file!") if ok: self.disable_global_input() # noinspection PyUnresolvedReferences self.save_document_base_to_bson.emit(str(path), self.document_base) def add_attribute_task(self): logger.info("Execute task 'add_attribute_task'.") if self.document_base is not None: name, ok = QInputDialog.getText(self, "Create Attribute", "Attribute name:") if ok: self.disable_global_input() # noinspection PyUnresolvedReferences self.add_attribute.emit(str(name), self.document_base) def remove_attribute_task(self): logger.info("Execute task 'remove_attribute_task'.") if self.document_base is not None: name, ok = QInputDialog.getText(self, "Remove Attribute", "Attribute name:") if ok: self.disable_global_input() # noinspection PyUnresolvedReferences self.remove_attribute.emit(str(name), self.document_base) def remove_attribute_with_given_name_task(self, attribute_name): logger.info("Execute task 'remove_attribute_with_given_name_task'.") if self.document_base is not None: self.disable_global_input() # noinspection PyUnresolvedReferences self.remove_attribute.emit(str(attribute_name), self.document_base) def forget_matches_for_attribute_task(self): logger.info("Execute task 'forget_matches_for_attribute_task'.") if self.document_base is not None: name, ok = QInputDialog.getText(self, "Forget Matches for Attribute", "Attribute name:") if ok: self.disable_global_input() # noinspection PyUnresolvedReferences self.forget_matches_for_attribute.emit(str(name), self.document_base) def forget_matches_for_attribute_with_given_name_task(self, attribute_name): logger.info("Execute task 'forget_matches_for_attribute_with_given_name_task'.") if self.document_base is not None: self.disable_global_input() # noinspection PyUnresolvedReferences self.forget_matches_for_attribute.emit(attribute_name, self.document_base) def forget_matches_task(self): logger.info("Execute task 'forget_matches_task'.") if self.document_base is not None: self.disable_global_input() # noinspection PyUnresolvedReferences self.forget_matches.emit(self.document_base) def enable_collect_statistics_task(self): logger.info("Execute task 'task_enable_collect_statistics'.") self.collect_statistics = True self.enable_collect_statistics_action.setEnabled(False) self.disable_collect_statistics_action.setEnabled(True) def disable_collect_statistics_task(self): logger.info("Execute task 'disable_collect_statistics_task'.") self.collect_statistics = False self.disable_collect_statistics_action.setEnabled(False) self.enable_collect_statistics_action.setEnabled(True) def save_statistics_to_json_task(self): logger.info("Execute task 'save_statistics_to_json_task'.") if self.statistics is not None: path = str(QFileDialog.getSaveFileName(self, "Choose where to save the statistics .json file!")[0]) if path != "": self.disable_global_input() # noinspection PyUnresolvedReferences self.save_statistics_to_json.emit(path, self.statistics) def show_document_base_creator_widget_task(self): logger.info("Execute task 'show_document_base_creator_widget_task'.") self.disable_global_input() self.document_base_creator_widget.enable_input() self.document_base_creator_widget.initialize_for_new_document_base() self.show_document_base_creator_widget() self.document_base_creator_widget.path.setFocus() def create_document_base_task(self, path, attribute_names): logger.info("Execute task 'create_document_base_task'.") self.disable_global_input() # noinspection PyUnresolvedReferences self.create_document_base.emit(path, attribute_names) def save_table_to_csv_task(self): logger.info("Execute task 'save_table_to_csv_task'.") if self.document_base is not None: path = str(QFileDialog.getSaveFileName(self, "Choose where to save the table .csv file!")[0]) if path != "": self.disable_global_input() # noinspection PyUnresolvedReferences self.save_table_to_csv.emit(path, self.document_base) def load_preprocessing_phase_from_config_task(self): logger.info("Execute task 'load_preprocessing_phase_from_config_task'.") path = str(QFileDialog.getOpenFileName(self, "Choose a configuration .json file!")[0]) if path != "": self.disable_global_input() # noinspection PyUnresolvedReferences self.load_preprocessing_phase_from_config.emit(path) def save_preprocessing_phase_to_config_task(self): logger.info("Execute task 'save_preprocessing_phase_to_config_task'.") if self.preprocessing_phase is not None: path = str(QFileDialog.getSaveFileName(self, "Choose where to save the configuration .json file!")[0]) if path != "": self.disable_global_input() # noinspection PyUnresolvedReferences self.save_preprocessing_phase_to_config.emit(path, self.preprocessing_phase) def load_matching_phase_from_config_task(self): logger.info("Execute task 'load_matching_phase_from_config_task'.") path = str(QFileDialog.getOpenFileName(self, "Choose a configuration .json file!")[0]) if path != "": self.disable_global_input() # noinspection PyUnresolvedReferences self.load_matching_phase_from_config.emit(path) def save_matching_phase_to_config_task(self): logger.info("Execute task 'save_matching_phase_to_config_task'.") if self.matching_phase is not None: path = str(QFileDialog.getSaveFileName(self, "Choose where to save the configuration .json file!")[0]) if path != "": self.disable_global_input() # noinspection PyUnresolvedReferences self.save_matching_phase_to_config.emit(path, self.matching_phase) def run_preprocessing_phase_task(self): logger.info("Execute task 'run_preprocessing_phase_task'.") if self.document_base is not None and self.preprocessing_phase is not None: self.statistics = Statistics(self.collect_statistics) self.save_statistics_to_json_action.setEnabled(self.collect_statistics) self.disable_global_input() # noinspection PyUnresolvedReferences self.run_preprocessing_phase.emit(self.document_base, self.preprocessing_phase, self.statistics) def run_matching_phase_task(self): logger.info("Execute task 'run_matching_phase_task'.") if self.document_base is not None and self.matching_phase is not None: self.statistics = Statistics(self.collect_statistics) self.save_statistics_to_json_action.setEnabled(self.collect_statistics) self.disable_global_input() self.interactive_matching_widget.enable_input() self.show_interactive_matching_widget() # noinspection PyUnresolvedReferences self.run_matching_phase.emit(self.document_base, self.matching_phase, self.statistics) def give_feedback_task(self, feedback): logger.info("Execute task 'give_feedback_task'.") self.api.feedback = feedback self.feedback_cond.wakeAll() def load_and_run_default_preprocessing_phase_task(self): logger.info("Execute task 'load_and_run_default_preprocessing_phase_task'.") if self.document_base is not None: self.statistics = Statistics(self.collect_statistics) self.save_statistics_to_json_action.setEnabled(self.collect_statistics) self.disable_global_input() # noinspection PyUnresolvedReferences self.load_and_run_default_preprocessing_phase.emit(self.document_base, self.statistics) def load_and_run_default_matching_phase_task(self): logger.info("Execute task 'load_and_run_default_matching_phase_task'.") if self.document_base is not None: self.statistics = Statistics(self.collect_statistics) self.save_statistics_to_json_action.setEnabled(self.collect_statistics) self.disable_global_input() self.interactive_matching_widget.enable_input() self.show_interactive_matching_widget() # noinspection PyUnresolvedReferences self.load_and_run_default_matching_phase.emit(self.document_base, self.statistics) ################## # controller logic ################## def enable_global_input(self): for action in self._was_enabled: action.setEnabled(True) self.document_base_creator_widget.enable_input() self.document_base_viewer_widget.enable_input() self.interactive_matching_widget.enable_input() self._was_enabled = [] def disable_global_input(self): for action in self._all_actions: if action.isEnabled(): self._was_enabled.append(action) action.setEnabled(False) self.document_base_creator_widget.disable_input() self.document_base_viewer_widget.disable_input() self.interactive_matching_widget.disable_input() def show_document_base_viewer_widget(self): if self.document_base_viewer_widget.isHidden(): self.central_widget_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) self.start_menu_widget.hide() self.interactive_matching_widget.hide() self.document_base_creator_widget.hide() self.central_widget_layout.removeWidget(self.start_menu_widget) self.central_widget_layout.removeWidget(self.interactive_matching_widget) self.central_widget_layout.removeWidget(self.document_base_creator_widget) self.central_widget_layout.addWidget(self.document_base_viewer_widget) self.document_base_viewer_widget.show() self.central_widget_layout.update() def show_interactive_matching_widget(self): if self.interactive_matching_widget.isHidden(): self.central_widget_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) self.start_menu_widget.hide() self.document_base_viewer_widget.hide() self.document_base_creator_widget.hide() self.central_widget_layout.removeWidget(self.start_menu_widget) self.central_widget_layout.removeWidget(self.document_base_viewer_widget) self.central_widget_layout.removeWidget(self.document_base_creator_widget) self.central_widget_layout.addWidget(self.interactive_matching_widget) self.interactive_matching_widget.show() self.central_widget_layout.update() def show_document_base_creator_widget(self): if self.document_base_creator_widget.isHidden(): self.central_widget_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) self.start_menu_widget.hide() self.document_base_viewer_widget.hide() self.interactive_matching_widget.hide() self.central_widget_layout.removeWidget(self.start_menu_widget) self.central_widget_layout.removeWidget(self.document_base_viewer_widget) self.central_widget_layout.removeWidget(self.interactive_matching_widget) self.central_widget_layout.addWidget(self.document_base_creator_widget) self.document_base_creator_widget.show() self.central_widget_layout.update() def show_start_menu_widget(self): if self.start_menu_widget.isHidden(): self.central_widget_layout.setAlignment(Qt.AlignmentFlag.AlignCenter) self.document_base_viewer_widget.hide() self.document_base_creator_widget.hide() self.interactive_matching_widget.hide() self.central_widget_layout.removeWidget(self.document_base_viewer_widget) self.central_widget_layout.removeWidget(self.document_base_creator_widget) self.central_widget_layout.removeWidget(self.interactive_matching_widget) self.central_widget_layout.addWidget(self.start_menu_widget) self.start_menu_widget.show() self.central_widget_layout.update() def __init__(self) -> None: super(MainWindow, self).__init__() self.setWindowTitle("ASET") self.document_base = None self.preprocessing_phase = None self.matching_phase = None self.statistics = Statistics(True) self.collect_statistics = True # set up the api_thread and api and connect slots and signals self.feedback_mutex = QMutex() self.feedback_cond = QWaitCondition() self.api = ASETAPI(self.feedback_mutex, self.feedback_cond) self.api_thread = QThread() self.api.moveToThread(self.api_thread) self._connect_slots_and_signals() self.api_thread.start() # set up the status bar self.status_bar = self.statusBar() self.status_bar.setFont(STATUS_BAR_FONT) self.status_widget = QWidget(self.status_bar) self.status_widget_layout = QHBoxLayout(self.status_widget) self.status_widget_layout.setContentsMargins(0, 0, 0, 0) self.status_widget_message = QLabel() self.status_widget_message.setFont(STATUS_BAR_FONT) self.status_widget_message.setMinimumWidth(10) self.status_widget_layout.addWidget(self.status_widget_message) self.status_widget_progress = QProgressBar() self.status_widget_progress.setMinimumWidth(10) self.status_widget_progress.setMaximumWidth(200) self.status_widget_progress.setTextVisible(False) self.status_widget_progress.setMaximumHeight(20) self.status_widget_layout.addWidget(self.status_widget_progress) self.status_bar.addPermanentWidget(self.status_widget) # set up the actions self._all_actions = [] self._was_enabled = [] self.exit_action = QAction("&Exit", self) self.exit_action.setIcon(QIcon("aset_ui/resources/leave.svg")) self.exit_action.setStatusTip("Exit the application.") self.exit_action.triggered.connect(QApplication.instance().quit) self._all_actions.append(self.exit_action) self.show_document_base_creator_widget_action = QAction("&Create new document base", self) self.show_document_base_creator_widget_action.setIcon(QIcon("aset_ui/resources/two_documents.svg")) self.show_document_base_creator_widget_action.setStatusTip( "Create a new document base from a collection of .txt files and a list of attribute names." ) self.show_document_base_creator_widget_action.triggered.connect(self.show_document_base_creator_widget_task) self._all_actions.append(self.show_document_base_creator_widget_action) self.add_attribute_action = QAction("&Add attribute", self) self.add_attribute_action.setIcon(QIcon("aset_ui/resources/plus.svg")) self.add_attribute_action.setStatusTip("Add a new attribute to the document base.") self.add_attribute_action.triggered.connect(self.add_attribute_task) self.add_attribute_action.setEnabled(False) self._all_actions.append(self.add_attribute_action) self.remove_attribute_action = QAction("&Remove attribute", self) self.remove_attribute_action.setIcon(QIcon("aset_ui/resources/trash.svg")) self.remove_attribute_action.setStatusTip("Remove an attribute from the document base.") self.remove_attribute_action.triggered.connect(self.remove_attribute_task) self.remove_attribute_action.setEnabled(False) self._all_actions.append(self.remove_attribute_action) self.forget_matches_for_attribute_action = QAction("&Forget matches for attribute", self) self.forget_matches_for_attribute_action.setIcon(QIcon("aset_ui/resources/redo.svg")) self.forget_matches_for_attribute_action.setStatusTip("Forget the matches for a single attribute.") self.forget_matches_for_attribute_action.triggered.connect(self.forget_matches_for_attribute_task) self.forget_matches_for_attribute_action.setEnabled(False) self._all_actions.append(self.forget_matches_for_attribute_action) self.load_document_base_from_bson_action = QAction("&Load document base", self) self.load_document_base_from_bson_action.setIcon(QIcon("aset_ui/resources/folder.svg")) self.load_document_base_from_bson_action.setStatusTip("Load an existing document base from a .bson file.") self.load_document_base_from_bson_action.triggered.connect(self.load_document_base_from_bson_task) self._all_actions.append(self.load_document_base_from_bson_action) self.save_document_base_to_bson_action = QAction("&Save document base", self) self.save_document_base_to_bson_action.setIcon(QIcon("aset_ui/resources/save.svg")) self.save_document_base_to_bson_action.setStatusTip("Save the document base in a .bson file.") self.save_document_base_to_bson_action.triggered.connect(self.save_document_base_to_bson_task) self.save_document_base_to_bson_action.setEnabled(False) self._all_actions.append(self.save_document_base_to_bson_action) self.save_table_to_csv_action = QAction("&Export table to CSV", self) self.save_table_to_csv_action.setIcon(QIcon("aset_ui/resources/table.svg")) self.save_table_to_csv_action.setStatusTip("Save the table to a .csv file.") self.save_table_to_csv_action.triggered.connect(self.save_table_to_csv_task) self.save_table_to_csv_action.setEnabled(False) self._all_actions.append(self.save_table_to_csv_action) self.forget_matches_action = QAction("&Forget all matches", self) self.forget_matches_action.setIcon(QIcon("aset_ui/resources/redo.svg")) self.forget_matches_action.setStatusTip("Forget the matches for all attributes.") self.forget_matches_action.triggered.connect(self.forget_matches_task) self.forget_matches_action.setEnabled(False) self._all_actions.append(self.forget_matches_action) self.load_and_run_default_preprocessing_phase_action = QAction( "&Load and run default preprocessing phase", self ) self.load_and_run_default_preprocessing_phase_action.setStatusTip( "Load the default preprocessing phase and run it on the document collection." ) self.load_and_run_default_preprocessing_phase_action.setIcon(QIcon("aset_ui/resources/run_run.svg")) self.load_and_run_default_preprocessing_phase_action.setDisabled(True) self.load_and_run_default_preprocessing_phase_action.triggered.connect( self.load_and_run_default_preprocessing_phase_task ) self._all_actions.append(self.load_and_run_default_preprocessing_phase_action) self.load_preprocessing_phase_from_config_action = QAction("&Load preprocessing phase", self) self.load_preprocessing_phase_from_config_action.setStatusTip( "Load a preprocessing phase from a .json configuration file." ) self.load_preprocessing_phase_from_config_action.triggered.connect( self.load_preprocessing_phase_from_config_task ) self._all_actions.append(self.load_preprocessing_phase_from_config_action) self.save_preprocessing_phase_to_config_action = QAction("&Save preprocessing phase", self) self.save_preprocessing_phase_to_config_action.setStatusTip( "Save the preprocessing phase in a .json configuration file." ) self.save_preprocessing_phase_to_config_action.triggered.connect(self.save_preprocessing_phase_to_config_task) self.save_preprocessing_phase_to_config_action.setEnabled(False) self._all_actions.append(self.save_preprocessing_phase_to_config_action) self.run_preprocessing_phase_action = QAction("Run preprocessing phase", self) self.run_preprocessing_phase_action.setIcon(QIcon("aset_ui/resources/run.svg")) self.run_preprocessing_phase_action.setStatusTip("Run the preprocessing phase on the document collection.") self.run_preprocessing_phase_action.triggered.connect(self.run_preprocessing_phase_task) self.run_preprocessing_phase_action.setEnabled(False) self._all_actions.append(self.run_preprocessing_phase_action) self.load_and_run_default_matching_phase_action = QAction( "&Load and run default matching phase", self ) self.load_and_run_default_matching_phase_action.setStatusTip( "Load the default matching phase and run it on the document collection." ) self.load_and_run_default_matching_phase_action.setIcon(QIcon("aset_ui/resources/run_run.svg")) self.load_and_run_default_matching_phase_action.setDisabled(True) self.load_and_run_default_matching_phase_action.triggered.connect( self.load_and_run_default_preprocessing_phase_task ) self._all_actions.append(self.load_and_run_default_matching_phase_action) self.load_matching_phase_from_config_action = QAction("&Load matching phase", self) self.load_matching_phase_from_config_action.setStatusTip( "Load a matching phase from a .json configuration file." ) self.load_matching_phase_from_config_action.triggered.connect(self.load_matching_phase_from_config_task) self._all_actions.append(self.load_matching_phase_from_config_action) self.save_matching_phase_to_config_action = QAction("&Save matching phase", self) self.save_matching_phase_to_config_action.setStatusTip("Save the matching phase in a .json configuration file.") self.save_matching_phase_to_config_action.triggered.connect(self.save_matching_phase_to_config_task) self.save_matching_phase_to_config_action.setEnabled(False) self._all_actions.append(self.save_matching_phase_to_config_action) self.run_matching_phase_action = QAction("Run matching phase", self) self.run_matching_phase_action.setIcon(QIcon("aset_ui/resources/run.svg")) self.run_matching_phase_action.setStatusTip("Run the matching phase on the document collection.") self.run_matching_phase_action.triggered.connect(self.run_matching_phase_task) self.run_matching_phase_action.setEnabled(False) self._all_actions.append(self.run_matching_phase_action) self.enable_collect_statistics_action = QAction("&Enable statistics", self) self.enable_collect_statistics_action.setIcon(QIcon("aset_ui/resources/statistics.svg")) self.enable_collect_statistics_action.setStatusTip("Enable collecting statistics.") self.enable_collect_statistics_action.triggered.connect(self.enable_collect_statistics_task) self.enable_collect_statistics_action.setEnabled(False) self._all_actions.append(self.enable_collect_statistics_action) self.disable_collect_statistics_action = QAction("&Disable statistics", self) self.disable_collect_statistics_action.setIcon(QIcon("aset_ui/resources/statistics_incorrect.svg")) self.disable_collect_statistics_action.setStatusTip("Disable collecting statistics.") self.disable_collect_statistics_action.triggered.connect(self.disable_collect_statistics_task) self._all_actions.append(self.disable_collect_statistics_action) self.save_statistics_to_json_action = QAction("&Save statistics", self) self.save_statistics_to_json_action.setIcon(QIcon("aset_ui/resources/statistics_save.svg")) self.save_statistics_to_json_action.setStatusTip("Save the statistics to a .json file.") self.save_statistics_to_json_action.triggered.connect(self.save_statistics_to_json_task) self.save_statistics_to_json_action.setEnabled(False) self._all_actions.append(self.save_statistics_to_json_action) # set up the menu bar self.menubar = self.menuBar() self.menubar.setFont(MENU_FONT) self.file_menu = self.menubar.addMenu("&File") self.file_menu.setFont(MENU_FONT) self.file_menu.addAction(self.exit_action) self.document_base_menu = self.menubar.addMenu("&Document Base") self.document_base_menu.setFont(MENU_FONT) self.document_base_menu.addAction(self.show_document_base_creator_widget_action) self.document_base_menu.addSeparator() self.document_base_menu.addAction(self.load_document_base_from_bson_action) self.document_base_menu.addAction(self.save_document_base_to_bson_action) self.document_base_menu.addSeparator() self.document_base_menu.addAction(self.save_table_to_csv_action) self.document_base_menu.addSeparator() self.document_base_menu.addAction(self.add_attribute_action) self.document_base_menu.addAction(self.remove_attribute_action) self.document_base_menu.addSeparator() self.document_base_menu.addAction(self.forget_matches_for_attribute_action) self.document_base_menu.addAction(self.forget_matches_action) self.preprocessing_menu = self.menubar.addMenu("&Preprocessing") self.preprocessing_menu.setFont(MENU_FONT) self.preprocessing_menu.addAction(self.load_and_run_default_preprocessing_phase_action) self.preprocessing_menu.addSeparator() self.preprocessing_menu.addAction(self.load_preprocessing_phase_from_config_action) self.preprocessing_menu.addAction(self.save_preprocessing_phase_to_config_action) self.preprocessing_menu.addSeparator() self.preprocessing_menu.addAction(self.run_preprocessing_phase_action) self.matching_menu = self.menubar.addMenu("&Matching") self.matching_menu.setFont(MENU_FONT) self.matching_menu.addAction(self.load_and_run_default_matching_phase_action) self.matching_menu.addSeparator() self.matching_menu.addAction(self.load_matching_phase_from_config_action) self.matching_menu.addAction(self.save_matching_phase_to_config_action) self.matching_menu.addSeparator() self.matching_menu.addAction(self.run_matching_phase_action) self.statistics_menu = self.menubar.addMenu("&Statistics") self.statistics_menu.setFont(MENU_FONT) self.statistics_menu.addAction(self.enable_collect_statistics_action) self.statistics_menu.addAction(self.disable_collect_statistics_action) self.statistics_menu.addSeparator() self.statistics_menu.addAction(self.save_statistics_to_json_action) # start menu self.start_menu_widget = QWidget() self.start_menu_layout = QVBoxLayout(self.start_menu_widget) self.start_menu_layout.setContentsMargins(0, 0, 0, 0) self.start_menu_layout.setSpacing(30) self.start_menu_layout.setAlignment(Qt.AlignmentFlag.AlignTop) self.start_menu_widget.setMaximumWidth(400) self.start_menu_header = QLabel("Welcome to ASET!") self.start_menu_header.setFont(HEADER_FONT) self.start_menu_layout.addWidget(self.start_menu_header) self.start_menu_create_new_document_base_widget = QWidget() self.start_menu_create_new_document_base_layout = QVBoxLayout(self.start_menu_create_new_document_base_widget) self.start_menu_create_new_document_base_layout.setContentsMargins(0, 0, 0, 0) self.start_menu_create_new_document_base_layout.setSpacing(10) self.start_menu_layout.addWidget(self.start_menu_create_new_document_base_widget) self.start_menu_create_new_document_base_subheader = QLabel("Create a new document base.") self.start_menu_create_new_document_base_subheader.setFont(SUBHEADER_FONT) self.start_menu_create_new_document_base_layout.addWidget(self.start_menu_create_new_document_base_subheader) self.start_menu_create_new_document_base_wrapper_widget = QWidget() self.start_menu_create_new_document_base_wrapper_layout = QHBoxLayout( self.start_menu_create_new_document_base_wrapper_widget) self.start_menu_create_new_document_base_wrapper_layout.setContentsMargins(0, 0, 0, 0) self.start_menu_create_new_document_base_wrapper_layout.setSpacing(20) self.start_menu_create_new_document_base_wrapper_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) self.start_menu_create_new_document_base_layout.addWidget( self.start_menu_create_new_document_base_wrapper_widget) self.start_menu_create_document_base_button = QPushButton() self.start_menu_create_document_base_button.setFixedHeight(45) self.start_menu_create_document_base_button.setFixedWidth(45) self.start_menu_create_document_base_button.setIcon(QIcon("aset_ui/resources/two_documents.svg")) self.start_menu_create_document_base_button.clicked.connect(self.show_document_base_creator_widget_task) self.start_menu_create_new_document_base_wrapper_layout.addWidget(self.start_menu_create_document_base_button) self.start_menu_create_document_base_label = QLabel( "Create a new document base from a directory\nof .txt files and a list of attribute names.") self.start_menu_create_document_base_label.setFont(LABEL_FONT) self.start_menu_create_new_document_base_wrapper_layout.addWidget(self.start_menu_create_document_base_label) self.start_menu_load_document_base_widget = QWidget() self.start_menu_load_document_base_layout = QVBoxLayout(self.start_menu_load_document_base_widget) self.start_menu_load_document_base_layout.setContentsMargins(0, 0, 0, 0) self.start_menu_load_document_base_layout.setSpacing(10) self.start_menu_layout.addWidget(self.start_menu_load_document_base_widget) self.start_menu_load_document_base_subheader = QLabel("Load an existing document base.") self.start_menu_load_document_base_subheader.setFont(SUBHEADER_FONT) self.start_menu_load_document_base_layout.addWidget(self.start_menu_load_document_base_subheader) self.start_menu_load_document_base_wrapper_widget = QWidget() self.start_menu_load_document_base_wrapper_layout = QHBoxLayout( self.start_menu_load_document_base_wrapper_widget) self.start_menu_load_document_base_wrapper_layout.setContentsMargins(0, 0, 0, 0) self.start_menu_load_document_base_wrapper_layout.setSpacing(20) self.start_menu_load_document_base_wrapper_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) self.start_menu_load_document_base_layout.addWidget(self.start_menu_load_document_base_wrapper_widget) self.start_menu_load_document_base_button = QPushButton() self.start_menu_load_document_base_button.setFixedHeight(45) self.start_menu_load_document_base_button.setFixedWidth(45) self.start_menu_load_document_base_button.setIcon(QIcon("aset_ui/resources/folder.svg")) self.start_menu_load_document_base_button.clicked.connect(self.load_document_base_from_bson_task) self.start_menu_load_document_base_wrapper_layout.addWidget(self.start_menu_load_document_base_button) self.start_menu_load_document_base_label = QLabel("Load an existing document base\nfrom a .bson file.") self.start_menu_load_document_base_label.setFont(LABEL_FONT) self.start_menu_load_document_base_wrapper_layout.addWidget(self.start_menu_load_document_base_label) # main UI self.central_widget = QWidget(self) self.central_widget_layout = QHBoxLayout(self.central_widget) self.central_widget_layout.setAlignment(Qt.AlignmentFlag.AlignCenter) self.setCentralWidget(self.central_widget) self.document_base_creator_widget = DocumentBaseCreatorWidget(self) self.document_base_viewer_widget = DocumentBaseViewerWidget(self) self.interactive_matching_widget = InteractiveMatchingWidget(self) self.document_base_creator_widget.hide() self.document_base_viewer_widget.hide() self.interactive_matching_widget.hide() self.central_widget_layout.addWidget(self.start_menu_widget) self.central_widget_layout.update() self.resize(1400, 800) self.show() logger.info("Initialized MainWindow.")
def __init__(self, main_window: QWidget): super().__init__() self.search_callback = None # 主题空间 子组件都放这个Widget里 self.centralWidget = QtWidgets.QWidget(main_window) self.centralWidget.setObjectName("centralWidget") # 搜索框 self.souInput = QtWidgets.QLineEdit(self.centralWidget) self.souInput.setGeometry(QtCore.QRect(40, 30, 800, 30)) font = QtGui.QFont() font.setPointSize(22) font.setKerning(True) font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferDefault) self.souInput.setFont(font) self.souInput.setObjectName("souInput") self.souInput.setText("龙珠") self.modBox = CheckableComboBox(self.centralWidget) self.modBox.setGeometry(QtCore.QRect(850, 30, 120, 30)) for k in constant.mod_dist.keys(): if k in constant.mod_list: self.modBox.addItem(QtCore.Qt.CheckState.Checked, k) else: self.modBox.addItem(QtCore.Qt.CheckState.Unchecked, k) # QTabWidget tab页签 self.tabWidget = QtWidgets.QTabWidget(self.centralWidget) self.tabWidget.setGeometry(QtCore.QRect(40, 70, 944, 668)) self.tabWidget.setTabsClosable(True) self.tabWidget.setObjectName("tabWidget") # 下载页面 self.down_tab = QtWidgets.QWidget() self.down_tab.setStatusTip("") self.down_tab.setAutoFillBackground(False) self.down_tab.setObjectName("down_tab") self.tabWidget.addTab(self.down_tab, "下载列表") # 书架页面 self.bookshelf_tab = QtWidgets.QWidget() self.bookshelf_tab.setObjectName("bookshelf_tab") self.tabWidget.addTab(self.bookshelf_tab, "书架") # 搜索结果页面 self.search_tab = QtWidgets.QWidget() self.search_tab.setObjectName("search_tab") self.tabWidget.addTab(self.search_tab, "搜索结果") # None 空按钮,tab签右侧按钮,设置到前面 tbr = self.tabWidget.tabBar().tabButton(0, QTabBar.ButtonPosition.RightSide) self.tabWidget.tabBar().setTabButton(0, QTabBar.ButtonPosition.LeftSide, tbr) self.tabWidget.tabBar().setTabButton(1, QTabBar.ButtonPosition.LeftSide, tbr) self.tabWidget.tabBar().setTabButton(2, QTabBar.ButtonPosition.LeftSide, tbr) # 启用关闭页签的功能 self.tabWidget.tabCloseRequested.connect(self.tab_close) # 默认打开到书架 self.tabWidget.setCurrentIndex(1) # 主体的centralWidget 放到主窗口中 main_window.setCentralWidget(self.centralWidget) # 书架页 self.bookshelfVBoxLayout = QVBoxLayout() self.bookshelfGroupBox = QGroupBox() self.bookshelfScroll = QScrollArea() self.bookshelfLayout = QVBoxLayout(self.bookshelf_tab) self.bookshelfVBoxLayout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop) self.bookshelfGroupBox.setLayout(self.bookshelfVBoxLayout) self.bookshelfScroll.setWidget(self.bookshelfGroupBox) self.bookshelfScroll.setWidgetResizable(True) self.bookshelfLayout.addWidget(self.bookshelfScroll) # 搜索页 self.searchVBoxLayout = QVBoxLayout() self.searchGroupBox = QGroupBox() self.searchScroll = QScrollArea() self.searchLayout = QVBoxLayout(self.search_tab) self.searchVBoxLayout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop) self.searchGroupBox.setLayout(self.searchVBoxLayout) self.searchScroll.setWidget(self.searchGroupBox) self.searchScroll.setWidgetResizable(True) self.searchLayout.addWidget(self.searchScroll) # 下载页 self.downVBoxLayout = QVBoxLayout() self.downGroupBox = QGroupBox() self.downScroll = QScrollArea() self.downLayout = QVBoxLayout(self.down_tab) self.downVBoxLayout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop) self.downGroupBox.setLayout(self.downVBoxLayout) self.downScroll.setWidget(self.downGroupBox) self.downScroll.setWidgetResizable(True) self.downLayout.addWidget(self.downScroll) down_button_layout = QHBoxLayout() self.downLayout.addLayout(down_button_layout) down_button_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight) all_start = QPushButton() all_start.setText("全部开始") all_stop = QPushButton() all_stop.setText("全部停止") clear_done = QPushButton() clear_done.setText("清理已完成") down_button_layout.addWidget(all_start) down_button_layout.addWidget(all_stop) down_button_layout.addWidget(clear_done) self.souInput.returnPressed.connect(self.input_return_pressed) # 回车搜索 self.load_comic_list_signa.connect(self.search_load_comic_list) # 更新ui的插槽 self.bookshelf_load_comic_list() self.download_callback()
class CalibrateWizard(QWizard): def __init__(self, parent): super().__init__(parent) self.parent = parent self.setWizardStyle(QWizard.WizardStyle.ModernStyle) # CREATE PAGE 1, LINE EDIT, TITLES buttons_layout = [QWizard.WizardButton.NextButton] self.page1 = QWizardPage() self.page1.setTitle('Select the exercises you wish to do later') self.page1.setSubTitle( 'Below are listed all the available and selected exercises by you.' ) self.listSelection = TwoListSelection() # listSelection.addAvailableItems(["item-{}".format(i) for i in range(5)]) hLayout1 = QHBoxLayout(self.page1) hLayout1.addWidget(self.listSelection) # CREATE PAGE 2, LABEL, TITLES self.page2 = QWizardPage() self.page2.setFinalPage(True) self.setButtonLayout(buttons_layout) self.page2.setTitle('Calibrate every exercise') self.page2.setSubTitle( 'Do every exercise once, record after pressing button.') self.contentLayout = QVBoxLayout(self.page2) self.hLayout2 = QHBoxLayout() # Create progress bar, buttons self.actionsLayout = QHBoxLayout() self.finishButton = QPushButton('Ready') self.finishButton.setStyleSheet(CustomQStyles.buttonStyle) self.finishButton.setFixedSize(120, 35) self.progress = QProgressBar() self.progress.setRange(0, 1) self.actionsLayout.addWidget(self.progress) self.actionsLayout.setAlignment(self.progress, Qt.Alignment.AlignBottom) self.actionsLayout.addWidget(self.finishButton) self.actionsLayout.setAlignment(self.finishButton, Qt.Alignment.AlignBottom) self.contentLayout.addLayout(self.hLayout2) self.contentLayout.addLayout(self.actionsLayout) self.actionsLayout.setContentsMargins(15, 35, 15, 0) itemsTextList = [ str(self.listSelection.mInput.item(i).text()) for i in range(self.listSelection.mInput.count()) ] print("items:", itemsTextList) self.button(QWizard.WizardButton.NextButton).clicked.connect( self.onWizardNextButton) self.finishButton.clicked.connect(self.onWizardFinishButton) self.addPage(self.page1) self.addPage(self.page2) # Recording data self.buttons = [] self.images = [] self.labels = [] self.exerciseLayouts = [] self.recordReady = [] self.recordThread = RecordThread(self.parent.classifyExercises) # Training recorded data self.trained = False self.trainThread = TrainThread(self.parent.classifyExercises) self.trainThread.taskFinished.connect(self.onTrainFinished) # Send list to next page def onWizardNextButton(self): self.setPage(1, self.page1) self.trained = False itemsTextList = [ str(self.listSelection.mInput.item(i).text()) for i in range(self.listSelection.mInput.count()) ] # Update list if self.parent.classifyExercises is not None: self.parent.classifyExercises.UpdateExerciseList(itemsTextList) # Set elements on UI self.setMinimumWidth(len(itemsTextList) * 200) self.deleteItemsOfLayout(self.hLayout2) self.images.clear() self.labels.clear() self.buttons.clear() self.recordReady.clear() for x, i in zip(itemsTextList, range(len(itemsTextList))): self.exerciseLayouts.append(QVBoxLayout()) self.buttons.append(QPushButton('Record')) self.recordReady.append(False) image = QLabel() image.setPixmap( QPixmap(os.getcwd() + "/resources/images/" + itemsTextList[i] + ".png")) self.labels.append(QLabel(itemsTextList[i])) self.images.append(image) self.buttons[i].setFixedSize(100, 35) self.buttons[i].clicked.connect( functools.partial(self.onRecordExerciseButtonClicked, x, i)) self.buttons[i].setStyleSheet(CustomQStyles.outlineButtonStyle) self.exerciseLayouts[i].addWidget(self.labels[i]) self.exerciseLayouts[i].addWidget(self.images[i]) self.exerciseLayouts[i].addWidget(self.buttons[i]) self.exerciseLayouts[i].setAlignment(self.labels[i], Qt.Alignment.AlignCenter) self.exerciseLayouts[i].setAlignment(self.images[i], Qt.Alignment.AlignCenter) self.exerciseLayouts[i].setAlignment(self.buttons[i], Qt.Alignment.AlignCenter) self.hLayout2.addLayout(self.exerciseLayouts[i]) def onRecordExerciseButtonClicked(self, exercise, ind): print("Recording - ", exercise) if self.parent.classifyExercises is not None: self.recordThread.exercise = exercise self.recordThread.taskFinished.connect( functools.partial(self.recordFinished, exercise, ind), Qt.ConnectionType.SingleShotConnection) self.recordThread.start() self.recordReady[ind] = False self.buttons[ind].setStyleSheet(CustomQStyles.recordButtonStyle) self.images[ind].setPixmap( QPixmap(os.getcwd() + "/resources/images/" + exercise + ".png")) def recordFinished(self, exercise, index): imagePath = os.getcwd() + "/resources/images/" + exercise + ".png" if self.recordThread.result == 0: imagePath = os.getcwd( ) + "/resources/images/" + exercise + "-fail.png" elif self.recordThread.result == 1: imagePath = os.getcwd( ) + "/resources/images/" + exercise + "-success.png" self.recordReady[index] = True else: print("None.") self.images[index].setPixmap(QPixmap(imagePath)) self.buttons[index].setStyleSheet(CustomQStyles.outlineButtonStyle) print(self.recordReady) def onWizardFinishButton(self): if all(x == True for x in self.recordReady): print("All recorded!") if not self.trained: if self.parent.classifyExercises is not None: self.progress.setRange(0, 0) # indefinite progress bar self.parent.classifyExercises.SaveProcessedData() self.parent.classifyExercises.SavePatientData() self.parent.ui.loadPatientList() self.trainThread.start() else: self.close() else: print("Not all recorded!") def onTrainFinished(self): self.progress.setRange(0, 1) self.progress.setValue(1) self.trained = True CustomMessage.showDialog("Message", "Training model finished!", QMessageBox.StandardButtons.Ok) self.finishButton.setText('Finish') def deleteItemsOfLayout(self, layout): if layout is not None: while layout.count(): item = layout.takeAt(0) widget = item.widget() if widget is not None: widget.setParent(None) else: self.deleteItemsOfLayout(item.layout())
class TestWidget(QVBoxLayout): def __init__(self, parent): super().__init__(parent) self.classifyExercises = parent.classifyExercises self.columns = [ 'Set', 'Exercise', 'Assigned Key', 'Accuracy', 'Latency', 'Avg.lat' ] self.exerciseLayouts = [] self.setButtons = [] self.initUi() print("init tab2") def initUi(self): # top labels self.mainLayout = QVBoxLayout() self.labels = QHBoxLayout() for x in self.columns: label = QLabel(x) self.labels.addWidget(label) self.labels.setAlignment(label, QtCore.Qt.Alignment.AlignHCenter) self.mainLayout.addLayout(self.labels) self.mainLayout.setAlignment(self.labels, QtCore.Qt.Alignment.AlignTop) if self.classifyExercises is not None: for e in range(0, self.classifyExercises.number_of_gestures): alignment = self.exerciseLayout(e) self.mainLayout.addLayout(alignment) self.mainLayout.setAlignment(alignment, QtCore.Qt.Alignment.AlignTop) self.addLayout(self.mainLayout) self.setAlignment(self.mainLayout, QtCore.Qt.Alignment.AlignTop) def exerciseLayout(self, index): hLayout = QHBoxLayout() setSpinBox = QSpinBox() setSpinBox.setRange(1, 100) setSpinBox.setValue(5) setSpinBox.setMaximumWidth(80) startButton = QPushButton(self.classifyExercises.exercises[index].name) startButton.setMaximumWidth(120) assignedKey = QPushButton( self.classifyExercises.exercises[index].assigned_key[0]) assignedKey.setStyleSheet('background-color: grey; color: white;') assignedKey.setMaximumWidth(50) assignedKey.setEnabled(False) progress = QProgressBar() progress.setMaximumWidth(150) progress.setValue(randint(1, 100)) progress.setAlignment(QtCore.Qt.Alignment.AlignCenter) latency = QLabel(str(randint(50, 250)) + 'ms') avgLatency = QLabel(str(randint(50, 250)) + 'ms') hLayout.addWidget(setSpinBox) hLayout.setAlignment(setSpinBox, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(startButton) hLayout.setAlignment(startButton, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(assignedKey) hLayout.setAlignment(assignedKey, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(progress) hLayout.setAlignment(progress, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(latency) hLayout.setAlignment(latency, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(avgLatency) hLayout.setAlignment(avgLatency, QtCore.Qt.Alignment.AlignHCenter) hLayout.setContentsMargins(0, 10, 0, 10) self.exerciseLayouts.append(hLayout) return hLayout
def exerciseLayout(self, index): hLayout = QHBoxLayout() setSpinBox = QSpinBox() setSpinBox.setRange(1, 100) setSpinBox.setValue(5) setSpinBox.setMaximumWidth(80) startButton = QPushButton(self.classifyExercises.exercises[index].name) startButton.setMaximumWidth(120) assignedKey = QPushButton( self.classifyExercises.exercises[index].assigned_key[0]) assignedKey.setStyleSheet('background-color: grey; color: white;') assignedKey.setMaximumWidth(50) assignedKey.setEnabled(False) progress = QProgressBar() progress.setMaximumWidth(150) progress.setValue(randint(1, 100)) progress.setAlignment(QtCore.Qt.Alignment.AlignCenter) latency = QLabel(str(randint(50, 250)) + 'ms') avgLatency = QLabel(str(randint(50, 250)) + 'ms') hLayout.addWidget(setSpinBox) hLayout.setAlignment(setSpinBox, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(startButton) hLayout.setAlignment(startButton, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(assignedKey) hLayout.setAlignment(assignedKey, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(progress) hLayout.setAlignment(progress, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(latency) hLayout.setAlignment(latency, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(avgLatency) hLayout.setAlignment(avgLatency, QtCore.Qt.Alignment.AlignHCenter) hLayout.setContentsMargins(0, 10, 0, 10) self.exerciseLayouts.append(hLayout) return hLayout
def __init__(self): super().__init__() self.setWindowTitle("📸 Random Image Tools V1.2 🔨") self.image_list = [] # ToDo: Add a "rename?" flag. Like rename image files # to store the directory path for later use self.directory_path_name = "/" # Set up the layouts layer_one = QHBoxLayout() # Select a folder, selected directory layer_one_and_a_half = QHBoxLayout() # Selected directory contents layer_two = QHBoxLayout() # Second line of buttons layer_two_vertical_one = QVBoxLayout() # Store the first column w/checkbox and "Convert" layer_two_vertical_two = QVBoxLayout() # Store the second column w/checkbox and "Open in File Browser" layer_three = QHBoxLayout() # Conversion process state vertical_layout_parent = QVBoxLayout() # Parent widget widget = QWidget() # Displays selected directory self.directory_label = QLabel() self.directory_label.setText("Directory to be worked on will show here ") self.directory_label.show() # Displays "Select folder" button self.select_a_folder_button = QPushButton() self.select_a_folder_button.setText("Select a folder:") self.select_a_folder_button.clicked.connect(self.select_folder_prompt) self.select_a_folder_button.show() # Displays the image contents of the selected folder self.image_paths_list_widget = QListWidget() self.image_paths_list_widget.show() # Displays button to initiate image conversion self.convert_to_png_button = QPushButton() self.convert_to_png_button.setText("Convert to PNG") self.convert_to_png_button.clicked.connect(self.convert_folder_to_png) self.convert_to_png_button.show() # Check boxes for "Create new folder for PNGs" and "Delete original files after converting" self.create_new_folder_checkbox = QCheckBox() self.create_new_folder_checkbox.setText("Create new folder to store converted PNG's?") self.create_new_folder_checkbox.show() self.delete_original_files_checkbox = QCheckBox() self.delete_original_files_checkbox.setText("Delete original files after converting them to PNG?") self.create_new_folder_checkbox.show() # Displays button to open selected directory in the file browser self.show_folder_button = QPushButton() self.show_folder_button.setText("Open selected folder in file browser") self.show_folder_button.clicked.connect(self.open_folder) self.show_folder_button.show() # Displays label when conversion is finished, and the corresponding progress bar self.conversion_finished_or_error_label = QLabel() self.conversion_finished_or_error_label.setText("👀 waiting for you to press \"Convert to PNG\" ") # Put the find folder button and folder selected button together layer_one.addWidget(self.select_a_folder_button) layer_one.addWidget(self.directory_label) # Image paths of selected folder layer_one_and_a_half.addWidget(self.image_paths_list_widget) # Put the convert button and open-in-finder button together layer_two_vertical_one.addWidget(self.convert_to_png_button) layer_two_vertical_one.addWidget(self.delete_original_files_checkbox) layer_two.addLayout(layer_two_vertical_one) layer_two_vertical_two.addWidget(self.show_folder_button) layer_two_vertical_two.addWidget(self.create_new_folder_checkbox) layer_two.addLayout(layer_two_vertical_two) # Label and progress bar layer_three.addWidget(self.conversion_finished_or_error_label) layer_three.setAlignment(Qt.AlignmentFlag.AlignHCenter) # Put the "convert to png" button beneath vertical_layout_parent.addLayout(layer_one) vertical_layout_parent.addLayout(layer_one_and_a_half) vertical_layout_parent.addLayout(layer_two) vertical_layout_parent.addLayout(layer_three) widget.setLayout(vertical_layout_parent) self.setCentralWidget(widget)
def initUI(self): self.setWindowTitle("登录蓝奏云") self.setWindowIcon(QIcon(SRC_DIR + "login.ico")) logo = QLabel() logo.setPixmap(QPixmap(SRC_DIR + "logo3.gif")) logo.setStyleSheet("background-color:rgb(0,153,255);") logo.setAlignment(Qt.AlignmentFlag.AlignCenter) self.tabs = QTabWidget() self.auto_tab = QWidget() self.hand_tab = QWidget() # Add tabs self.tabs.addTab(self.auto_tab,"自动获取Cookie") self.tabs.addTab(self.hand_tab,"手动输入Cookie") self.auto_get_cookie_ok = AutoResizingTextEdit("🔶点击👇自动获取浏览器登录信息👇") self.auto_get_cookie_ok.setReadOnly(True) self.auto_get_cookie_btn = QPushButton("自动读取浏览器登录信息") auto_cookie_notice = '支持浏览器:Chrome, Chromium, Opera, Edge, Firefox' self.auto_get_cookie_btn.setToolTip(auto_cookie_notice) self.auto_get_cookie_btn.clicked.connect(self.call_auto_get_cookie) self.auto_get_cookie_btn.setStyleSheet("QPushButton {min-width: 210px;max-width: 210px;}") self.name_lb = QLabel("&U 用户") self.name_lb.setAlignment(Qt.AlignmentFlag.AlignCenter) self.name_ed = QLineEdit() self.name_lb.setBuddy(self.name_ed) self.pwd_lb = QLabel("&P 密码") self.pwd_lb.setAlignment(Qt.AlignmentFlag.AlignCenter) self.pwd_ed = QLineEdit() self.pwd_ed.setEchoMode(QLineEdit.EchoMode.Password) self.pwd_lb.setBuddy(self.pwd_ed) self.cookie_lb = QLabel("&Cookie") self.cookie_ed = QTextEdit() notice = "由于滑动验证的存在,需要输入cookie,cookie请使用浏览器获取\n" + \ "cookie会保存在本地,下次使用。其格式如下:\n ylogin=value1; phpdisk_info=value2" self.cookie_ed.setPlaceholderText(notice) self.cookie_lb.setBuddy(self.cookie_ed) self.show_input_cookie_btn = QPushButton("显示Cookie输入框") self.show_input_cookie_btn.setToolTip(notice) self.show_input_cookie_btn.setStyleSheet("QPushButton {min-width: 110px;max-width: 110px;}") self.show_input_cookie_btn.clicked.connect(self.change_show_input_cookie) self.ok_btn = QPushButton("登录") self.ok_btn.clicked.connect(self.change_ok_btn) self.cancel_btn = QPushButton("取消") self.cancel_btn.clicked.connect(self.change_cancel_btn) lb_line_1 = QLabel() lb_line_1.setText('<html><hr />切换用户</html>') lb_line_2 = QLabel() lb_line_2.setText('<html><hr /></html>') self.form = QFormLayout() self.form.setLabelAlignment(Qt.AlignmentFlag.AlignRight) self.form.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow) # 覆盖MacOS的默认样式 self.form.addRow(self.name_lb, self.name_ed) self.form.addRow(self.pwd_lb, self.pwd_ed) if is_windows: def set_assister_path(): """设置辅助登录程序路径""" assister_path = QFileDialog.getOpenFileName(self, "选择辅助登录程序路径", self._cwd, "EXE Files (*.exe)") if not assister_path[0]: return None assister_path = os.path.normpath(assister_path[0]) # windows backslash if assister_path == self._cookie_assister: return None self.assister_ed.setText(assister_path) self._cookie_assister = assister_path self.assister_lb = QLabel("登录辅助程序") self.assister_lb.setAlignment(Qt.AlignmentFlag.AlignCenter) self.assister_ed = MyLineEdit(self) self.assister_ed.setText(self._cookie_assister) self.assister_ed.clicked.connect(set_assister_path) self.assister_lb.setBuddy(self.assister_ed) self.form.addRow(self.assister_lb, self.assister_ed) hbox = QHBoxLayout() hbox.addWidget(self.show_input_cookie_btn) hbox.addStretch(1) hbox.addWidget(self.ok_btn) hbox.addWidget(self.cancel_btn) user_box = QHBoxLayout() self.user_num = 0 self.user_btns = {} for user in self._config.users_name: user = str(user) # TODO: 可能需要删掉 self.user_btns[user] = QDoublePushButton(user) self.user_btns[user].setStyleSheet("QPushButton {border:none;}") if user == self._config.name: self.user_btns[user].setStyleSheet("QPushButton {background-color:rgb(0,153,2);}") self.tabs.setCurrentIndex(1) self.user_btns[user].setToolTip(f"点击选中,双击切换至用户:{user}") self.user_btns[user].doubleClicked.connect(self.choose_user) self.user_btns[user].clicked.connect(self.delete_chose_user) user_box.addWidget(self.user_btns[user]) self.user_num += 1 user_box.addStretch(1) self.layout = QVBoxLayout(self) self.layout.addWidget(logo) vbox = QVBoxLayout() if self._config.name: vbox.addWidget(lb_line_1) user_box.setAlignment(Qt.AlignmentFlag.AlignCenter) vbox.addLayout(user_box) vbox.addWidget(lb_line_2) if self.user_num > 1: self.del_user_btn = QPushButton("删除账户") self.del_user_btn.setIcon(QIcon(SRC_DIR + "delete.ico")) self.del_user_btn.setStyleSheet("QPushButton {min-width: 180px;max-width: 180px;}") self.del_user_btn.clicked.connect(self.call_del_chose_user) vbox.addWidget(self.del_user_btn) else: self.del_user_btn = None vbox.addStretch(1) vbox.addLayout(self.form) vbox.addStretch(1) vbox.addLayout(hbox) vbox.setAlignment(Qt.AlignmentFlag.AlignCenter) self.hand_tab.setLayout(vbox) auto_cookie_vbox = QVBoxLayout() auto_cookie_vbox.addWidget(self.auto_get_cookie_ok) auto_cookie_vbox.addWidget(self.auto_get_cookie_btn) auto_cookie_vbox.setAlignment(Qt.AlignmentFlag.AlignCenter) self.auto_tab.setLayout(auto_cookie_vbox) self.layout.addWidget(self.tabs) self.setLayout(self.layout) self.update_selection(self._config.name)