def GeneratePreview(self): self.preview_thread = QThread() east_id = self.SearchTeamID(self.cloth_east, True) south_id = self.SearchTeamID(self.cloth_south, True) west_id = self.SearchTeamID(self.cloth_west, True) north_id = self.SearchTeamID(self.cloth_north, True) if self.config["save_route"] is None: save_to_route = THISDIR else: save_to_route = self.config["save_route"] self._createProgressBar() self.preview_worker = GenerateImageThread(self.background, self.table_border, east_id, south_id, west_id, north_id, self.technical_lines.isChecked(), save_to_route, self.bg_image, True) self.preview_worker.moveToThread(self.preview_thread) self.preview_thread.started.connect(self.preview_worker.run) self.preview_worker.update_progress.connect(self.UpdateStatus) self.preview_worker.finished.connect(self.preview_thread.quit) self.preview_worker.finished.connect(self.preview_worker.deleteLater) self.preview_thread.finished.connect(self.preview_thread.deleteLater) self.preview_thread.finished.connect(self.PreviewWindow) self.preview_thread.start()
def slot_remove_redundant(self) -> None: ''' Disables all constraints that only contain redundant information and don't create more relations ''' progress_dialog = self.api.get_progress_dialog( 'Constraint Cleaner', 'Removing redundant constraints...', False) progress_dialog.show() self.thread = QThread() self.worker = RemoveRedundantWorker() self.worker.moveToThread(self.thread) self.worker.signal_progress.connect( lambda progress: progress_dialog.set_progress(progress)) self.worker.signal_done.connect( lambda: ( # https://stackoverflow.com/a/13672943 self.thread.quit(), progress_dialog.close(), QMessageBox.information( self.api.main_window, 'Constraint Cleaner', 'All redundant constraints are removed.'))) self.worker.signal_fail.connect(lambda: ( self.thread.quit(), progress_dialog.close(), QMessageBox.critical( self.api.main_window, 'Constraint Cleaner', 'Failed to add a constraint.\nSee console for more information.' ))) self.thread.started.connect(self.worker.process) self.thread.start()
def genData(self): if self.ofile == "": return self.thread = QThread() self.worker = Worker(self.adf, self.bbdf) self.worker.moveToThread(self.thread) self.thread.started.connect(self.worker.run) self.updateSb(u"正在处理数据") self.worker.finished.connect(self.thread.quit) self.worker.finished.connect(self.worker.deleteLater) self.worker.finished.connect(lambda: self.updateSb(u"处理完成")) self.worker.finished.connect( lambda: self.logger(u"数据处理完成,请检查生成的文件。\n")) self.thread.finished.connect(self.thread.deleteLater) self.worker.progress.connect(lambda p: self.ui.progressBar.setValue(p)) self.worker.output.connect(lambda c: self.logger(c)) self.worker.content.connect( lambda content: self.writeFile(content, self.ofile)) self.thread.start() self.ui.pushButton_start.setEnabled(False) self.thread.finished.connect( lambda: self.ui.pushButton_start.setEnabled(True))
def runFunctionInstallCoreBackend(self): """ Script that run a class as Thread to don't freeze main app """ nameOfFunction = sys._getframe().f_code.co_name nameOfFile = __file__ print(f'[{nameOfFile}][{nameOfFunction}] Started') # Step 1: Create worker # Step 2: Create a QThread object self.thread = QThread() # Step 3: Create a worker object self.worker = WorkerBashCommand() # Step 4: Move worker to the thread self.worker.moveToThread(self.thread) # Step 5: Connect signals and slots self.thread.started.connect( self.worker.runBashCommand(COMMAND_GIT_CLONE_CORE_BACKEND)) self.worker.finished.connect(self.thread.quit) self.worker.finished.connect(self.worker.deleteLater) self.thread.finished.connect( self.runFunctionInstallCoreBackendFinished) # Step 6: Start the thread self.thread.start() print(f'[{nameOfFile}][{nameOfFunction}] Finished')
def start(self, config, generic_log_handler, validation_log_handler): """ Starts the thread connecting the log panels to the relevant signals :param config: Config for the transformation to run :param generic_log_handler: The handler to consume all log records :param validation_log_handler: The handler to consume validation log records """ self.on_start() self.thread = QThread() self.worker = ControllerRunner(config) self.worker.moveToThread(self.thread) self.worker.finished.connect(self.on_finish) self.worker.finished.connect(self.thread.quit) self.worker.finished.connect(self.worker.deleteLater) self.thread.started.connect(self.worker.run) self.thread.finished.connect(self.thread.deleteLater) # connect the log handlers back to the main window self.worker.generic_log_record.connect(generic_log_handler.emit) self.worker.validation_log_record.connect(validation_log_handler.emit) self.thread.start()
def __init__(self): # gui self.app = QApplication([]) self.main_window = MainWindow(controller=self) # device self.device = Device() # fps stats self.fps_timer = QTimer() self.fps_timer.timeout.connect(self.update_ui_fps) self.spf = 1 # seconds per frame self.timestamp_last_capture = 0 # acquisition thread self.continuous_acquisition = False self.worker_wait_condition = QWaitCondition() self.acquisition_worker = AcquisitionWorker(self.worker_wait_condition, device=self.device) self.acquisition_thread = QThread() self.acquisition_worker.moveToThread(self.acquisition_thread) self.acquisition_thread.started.connect(self.acquisition_worker.run) self.acquisition_worker.finished.connect(self.acquisition_thread.quit) # self.acquisition_worker.finished.connect(self.acquisition_thread.deleteLater) # self.acquisition_thread.finished.connect(self.acquisition_worker.deleteLater) self.acquisition_worker.data_ready.connect(self.data_ready_callback) self.acquisition_thread.start() # default timebase self.set_timebase("20 ms") # on app exit self.app.aboutToQuit.connect(self.on_app_exit)
def checkLock(i): if i == 1: self.lock1 = True if i == 2: self.lock2 = True if self.lock1 and self.lock2: self.updateSb(u"正在处理数据") self.th3 = QThread() self.comp = Comparer(self.file1, self.file2) self.comp.moveToThread(self.th3) self.th3.started.connect(self.comp.run) self.comp.finished.connect(self.th3.quit) self.comp.finished.connect(self.comp.deleteLater) self.th3.finished.connect(self.th3.deleteLater) self.comp.progress.connect(lambda p: up(p)) self.comp.output.connect(lambda c: self.logger(c)) self.comp.content1.connect( lambda content: self.writeFile(content, self.ofileadd)) self.comp.content2.connect( lambda content: self.writeFile(content, self.ofilerem)) self.th3.finished.connect( lambda: self.ui.progressBar.setValue(100)) self.comp.finished.connect( lambda: self.logger(u"数据处理完成,请检查生成的文件。\n")) self.comp.finished.connect(lambda: self.updateSb(u"处理完成")) self.th3.finished.connect( lambda: self.ui.pushButton_start.setEnabled(True)) self.th3.start()
def handleClicked(self): if not self.ui.locationInput.text(): msgBox = QMessageBox() msgBox.setIcon(QMessageBox.Warning) msgBox.setText("지역을 설정해주세요.") else: filter = json.load(open("mod.json"))["filter"] filter_list = [] for c in self.checkboxes: if c.isChecked(): filter_list.append(filter[c.text()]) filter = ":".join(filter_list) #thread self.thread = QThread() self.worker = Worker(self.ui.locationInput.text(), filter) self.worker.moveToThread(self.thread) self.thread.started.connect(self.worker.run) self.worker.finished.connect(self.thread.quit) self.worker.finished.connect(self.worker.deleteLater) self.thread.finished.connect(self.thread.deleteLater) self.worker.progress.connect(self.ui.progressBar.setValue) self.thread.start() self.ui.startButton.setEnabled(False) self.thread.finished.connect(self.handleFinished)
def init_tracker(self, video_file): if self.current_state != State.Nothing_Loaded: self.prepare_destroy_tracker() self.destroyOnLoad = True self.tempVideoFile = video_file else: self.current_state = State.Initializing #Init tracker self.tracker = video_tracker(video_file, self.debugging) #Setup tracker thread self.tracker_thread = QThread(self) self.tracker.moveToThread(self.tracker_thread) #Setup Property Editor self.pe = pe_controller(self.ui.propertyEditor, self.tracker, self.debugging) #Connect signals and slots self.tracker.gen_start.connect(self.tracker.receive_signal) self.tracker.finished.connect(self.tracker_thread.quit) self.tracker.FrameSignal.connect(self.update_frames) self.tracker.stopped.connect(self.tracker_stopped) self.tracker.gen_history.connect(self.tracker.render_history) self.tracker_thread.start() self.current_state = State.Idle self.init_controls(self.tracker.video_data.num_frames)
class Window(QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.clicksCount = 0 self.setupUi() def setupUi(self): self.setWindowTitle("Freezing GUI") self.resize(300, 150) self.centralWidget = QWidget() self.setCentralWidget(self.centralWidget) # Create and connect widgets self.clicksLabel = QLabel("Counting: 0 clicks", self) self.clicksLabel.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.stepLabel = QLabel("Long-Running Step: 0") self.stepLabel.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.countBtn = QPushButton("Click me!", self) self.countBtn.clicked.connect(self.countClicks) self.longRunningBtn = QPushButton("Long-Running Task!", self) self.longRunningBtn.clicked.connect(self.runLongTask) # Set the layout layout = QVBoxLayout() layout.addWidget(self.clicksLabel) layout.addWidget(self.countBtn) layout.addStretch() layout.addWidget(self.stepLabel) layout.addWidget(self.longRunningBtn) self.centralWidget.setLayout(layout) def countClicks(self): self.clicksCount += 1 self.clicksLabel.setText(f"Counting: {self.clicksCount} clicks") def reportProgress(self, n): self.stepLabel.setText(f"Long-Running Step: {n}") def runLongTask(self): # 创建 QThread self.thread = QThread() # 创建 worker 对象 self.worker = Worker() # 将 work 移到 thread self.worker.moveToThread(self.thread) # 连接信号和槽 self.thread.started.connect(self.worker.run) self.worker.finished.connect(self.thread.quit) self.worker.finished.connect(self.worker.deleteLater) self.thread.finished.connect(self.thread.deleteLater) self.worker.progress.connect(self.reportProgress) # 启动线程 self.thread.start() # 结束 self.longRunningBtn.setEnabled(False) self.thread.finished.connect( lambda: self.longRunningBtn.setEnabled(True)) self.thread.finished.connect( lambda: self.stepLabel.setText("Long-Running Step: 0"))
def __init__(self, songQueue, marqueeFunc, parent=None): self.parent = parent self.player = vlc.MediaPlayer() self.songQueue = songQueue self.currentSong = None self.marqueeFunc = marqueeFunc self.thread = QThread() self.worker = Worker(self) self.worker.moveToThread(self.thread) self.worker.check.connect(self.songEndCheck) self.thread.started.connect(self.worker.run) self.thread.start()
def slot_start_server(self) -> None: self.server_thread = QThread() self.server_worker = ServerWorker() self.server_worker.signal_connected.connect(self.slot_connected) self.server_worker.signal_error.connect(self.slot_error) self.server_worker.signal_started.connect(self.slot_server_started) self.server_worker.signal_shutdown.connect(self.slot_server_stopped) self.server_worker.signal_script_addr.connect(self.slot_script_addr) self.server_worker.moveToThread(self.server_thread) self.server_thread.started.connect(self.server_worker.process) self.server_thread.start() self.slot_server_running(True)
class ConstraintCleanerPlugin: name = 'Constraint Cleaner' description = 'Cleans up duplicate constraints\nand disables redundant constraints' hidden = True def __init__(self, api: PluginApi) -> None: self.api = api def load(self) -> None: #self.action_remove_duplicate = self.api.register_menu_entry('Remove duplicate constraints', self.slot_remove_duplicate) self.action_remove_redundant = self.api.register_menu_entry( 'Remove redundant constraints', self.slot_remove_redundant) def unload(self) -> None: #self.api.remove_menu_entry(self.action_remove_duplicate) self.api.remove_menu_entry(self.action_remove_redundant) def slot_remove_duplicate(self) -> None: # TODO pass def slot_remove_redundant(self) -> None: ''' Disables all constraints that only contain redundant information and don't create more relations ''' progress_dialog = self.api.get_progress_dialog( 'Constraint Cleaner', 'Removing redundant constraints...', False) progress_dialog.show() self.thread = QThread() self.worker = RemoveRedundantWorker() self.worker.moveToThread(self.thread) self.worker.signal_progress.connect( lambda progress: progress_dialog.set_progress(progress)) self.worker.signal_done.connect( lambda: ( # https://stackoverflow.com/a/13672943 self.thread.quit(), progress_dialog.close(), QMessageBox.information( self.api.main_window, 'Constraint Cleaner', 'All redundant constraints are removed.'))) self.worker.signal_fail.connect(lambda: ( self.thread.quit(), progress_dialog.close(), QMessageBox.critical( self.api.main_window, 'Constraint Cleaner', 'Failed to add a constraint.\nSee console for more information.' ))) self.thread.started.connect(self.worker.process) self.thread.start()
def run(optimiser): app = QApplication(sys.argv) # Thread for running slow parts of the optimiser without pausing GUI opt_worker = OptWorker(optimiser) opt_thread = QThread() opt_worker.moveToThread(opt_thread) app.aboutToQuit.connect(opt_thread.quit) opt_thread.start() # Queue and thread for updating text field queue = Queue() sys.stdout = WriteStream(queue) window = BayesOptWindow(optimiser, opt_worker) window.show() write_thread = QThread() receiver = Receiver(queue) receiver.signal.connect(window.write_to_textfield) receiver.moveToThread(write_thread) write_thread.started.connect(receiver.run) app.aboutToQuit.connect(write_thread.quit) write_thread.start() # app.exec_() sys.exit(app.exec_())
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() #ui self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.startButton.clicked.connect(self.handleClicked) self.checkboxes = [ self.ui.checkBox, self.ui.checkBox_2, self.ui.checkBox_3, self.ui.checkBox_4, self.ui.checkBox_5, self.ui.checkBox_6 ] def handleClicked(self): if not self.ui.locationInput.text(): msgBox = QMessageBox() msgBox.setIcon(QMessageBox.Warning) msgBox.setText("지역을 설정해주세요.") else: filter = json.load(open("mod.json"))["filter"] filter_list = [] for c in self.checkboxes: if c.isChecked(): filter_list.append(filter[c.text()]) filter = ":".join(filter_list) #thread self.thread = QThread() self.worker = Worker(self.ui.locationInput.text(), filter) self.worker.moveToThread(self.thread) self.thread.started.connect(self.worker.run) self.worker.finished.connect(self.thread.quit) self.worker.finished.connect(self.worker.deleteLater) self.thread.finished.connect(self.thread.deleteLater) self.worker.progress.connect(self.ui.progressBar.setValue) self.thread.start() self.ui.startButton.setEnabled(False) self.thread.finished.connect(self.handleFinished) def handleFinished(self): self.ui.startButton.setEnabled(True) self.ui.progressBar.setValue(0) msgBox = QMessageBox() msgBox.setIcon(QMessageBox.Information) msgBox.setText("수집이 완료되었습니다.") msgBox.setDefaultButton(QMessageBox.Ok) ret = msgBox.exec_() if ret == QMessageBox.Ok: path = os.getcwd() + "/result" webbrowser.open('file:///' + path)
class RunThread: """ Wraps the thread and worker setting up the log signals to pass the log messages to the main window thread :param on_start: Method to call before the transformation begins :param on_finish: Method to call after the transformation ends """ def __init__(self, on_start, on_finish): self.on_start = on_start self.on_finish = on_finish self.worker = None """The controller runner""" self.thread = None """The thread the worker will be ran on""" def start(self, config, generic_log_handler, validation_log_handler): """ Starts the thread connecting the log panels to the relevant signals :param config: Config for the transformation to run :param generic_log_handler: The handler to consume all log records :param validation_log_handler: The handler to consume validation log records """ self.on_start() self.thread = QThread() self.worker = ControllerRunner(config) self.worker.moveToThread(self.thread) self.worker.finished.connect(self.on_finish) self.worker.finished.connect(self.thread.quit) self.worker.finished.connect(self.worker.deleteLater) self.thread.started.connect(self.worker.run) self.thread.finished.connect(self.thread.deleteLater) # connect the log handlers back to the main window self.worker.generic_log_record.connect(generic_log_handler.emit) self.worker.validation_log_record.connect(validation_log_handler.emit) self.thread.start()
def slot_start_server(self) -> None: self.server_thread = QThread() self.server_worker = ServerWorker() self.server_worker.signal_connected.connect(self.slot_connected) self.server_worker.signal_disconnected.connect(self.slot_disconnected) self.server_worker.signal_error.connect(self.slot_error) self.server_worker.signal_c_code.connect(self.slot_received_c_code) self.server_worker.signal_started.connect(self.slot_server_started) self.server_worker.signal_shutdown.connect(self.slot_server_stopped) self.server_worker.signal_extract_data.connect(self.slot_extract_data) self.server_worker.signal_fetch_decompilation.connect( self.slot_fetch_decompilation) self.server_worker.signal_upload_function.connect( self.slot_download_requested) self.server_worker.moveToThread(self.server_thread) self.server_thread.started.connect(self.server_worker.process) self.server_thread.start() self.slot_server_running(True)
def mcts_players(self, players: typing.Sequence[MctsPlayer]): self.stop_workers() self.log_display = LogDisplay() self.mcts_workers = {player.player_number: MctsWorker(player) for player in players} if not self.mcts_workers: self.worker_thread = None else: self.worker_thread = QThread() for worker in self.mcts_workers.values(): worker.move_chosen.connect(self.make_move) # type: ignore worker.move_analysed.connect(self.analyse_move) # type: ignore # noinspection PyUnresolvedReferences self.move_needed.connect(worker.choose_move) # type: ignore # noinspection PyUnresolvedReferences self.move_made.connect(worker.analyse_move) # type: ignore worker.moveToThread(self.worker_thread) self.worker_thread.start()
def create_log_parser(self): thread = QThread() log_path = self.game_path / 'Logs' log_file = log_path / self.settings_data.get('log_file', '') if log_file.exists(): self.log_parser = LogParserThreadObject(log_file) self.log_parser.data_ready.connect(self.process_log_data) self.log_parser.moveToThread(thread) thread.started.connect(self.log_parser.run) return thread
def GenerateImage(self): self.statusBar().showMessage('Generating image...') self._createProgressBar() if self.config["save_route"] is None: self.config["save_route"] = THISDIR save_to_route = QFileDialog.getExistingDirectory(self, "Where to save the image", self.config["save_route"], QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks) if self.config["save_route"] != save_to_route: temp_file = open(THISDIR + "\\config\\config.json", "r", encoding="utf-8") fp_teams = json.loads(temp_file.read()) fp_teams["save_route"] = save_to_route fp_teams["image_route"] = self.bg_image new_file = open(THISDIR + "\\config\\config.json", "w+", encoding="utf-8") new_file.write(json.dumps(fp_teams, indent=4)) new_file.close() self.background = Image.open(THISDIR + "\\images\\mat.png") self.table_border = Image.open(THISDIR + "\\images\\table_border.png") self.tech_lines = Image.open(THISDIR + "\\images\\technical_lines.png") self.thread = QThread() east_id = self.SearchTeamID(self.cloth_east, True) south_id = self.SearchTeamID(self.cloth_south, True) west_id = self.SearchTeamID(self.cloth_west, True) north_id = self.SearchTeamID(self.cloth_north, True) self.worker = GenerateImageThread(self.background, self.table_border, east_id, south_id, west_id, north_id, self.technical_lines.isChecked(), save_to_route, self.bg_image) self.worker.moveToThread(self.thread) self.thread.started.connect(self.worker.run) self.worker.update_progress.connect(self.UpdateStatus) self.worker.finished.connect(self.thread.quit) self.worker.finished.connect(self.worker.deleteLater) self.thread.finished.connect(self.thread.deleteLater) self.thread.finished.connect(self.GeneratedDialog) self.thread.start()
def add_worker(self, worker, auto_start=True): thread = QThread() if auto_start: self.threads.append(thread) worker.moveToThread(thread) thread.started.connect(worker.run) worker.finished.connect(lambda success, worker=worker, thread=thread: self.worker_finished(worker, thread, success)) thread.finished.connect(lambda thread=thread: self.thread_finished(thread)) worker.error.connect(lambda error, worker=worker: self.worker_error.emit(str(worker), error)) worker.progress.connect(lambda progress, worker=worker: self._worker_progress(worker, progress)) self.workers[str(worker)] = thread
def slot_start_server(self) -> None: if self.ui.checkBoxCopySaves.isChecked( ) and self.ui.lineEditSaveFolder.text().strip() == '': self.api.show_error( 'Entity Explorer Bridge', 'You need to set the folder where to store the copies.') return self.server_thread = QThread() self.server_worker = ServerWorker() self.server_worker.signal_connected.connect(self.slot_connected) self.server_worker.signal_disconnected.connect(self.slot_disconnected) self.server_worker.signal_error.connect(self.slot_error) self.server_worker.signal_started.connect(self.slot_server_started) self.server_worker.signal_shutdown.connect(self.slot_server_stopped) self.server_worker.moveToThread(self.server_thread) self.server_thread.started.connect(self.server_worker.process) self.server_thread.start() self.slot_server_running(True) self.set_folders_active(False)
def main(): # initialize app = QApplication([]) # create connection to the server client = Client(address=('127.0.0.1', 8888), debug=True) client.client_connect() # create a main window window = MainWindow(window_width=400, window_height=600) window.setWindowTitle("Python chat") # waiting for messages global client_worker, network_thread # TODO: refactor this network_thread = QThread() network_thread.setTerminationEnabled(True) client_worker = ClientWorker(client_socket=client.client()) client_worker.recieved_message.connect(window.recieved_message_handler) client_worker.moveToThread(network_thread) network_thread.started.connect(client_worker.start) network_thread.start() window.show() return app.exec_()
def __init__(self): super(App, self).__init__() self.combo = None self.MainProcess = MainProcess() self.MainProcess.get_image_functions() self.fps_label = QLabel('FPS: XXX') self.initUI() self._thread = QThread(self) self.video_worker = VideoThread(self.MainProcess.list_of_filters) #self.combo.currentIndexChanged.connect(self.video_worker.new_filter_slot) self.combo.currentIndexChanged.connect(self._new_ind) self.video_worker.change_pixmap_signal.connect(self.update_image) self.video_worker.update_fps_signal.connect(self._new_fps) self.video_worker.moveToThread(self._thread) self.combo.setCurrentIndex(self.MainProcess.blank_index) # connect the buttons self.start_button.clicked.connect(self.video_worker.start) self.quit_button.clicked.connect( self.close) # force this to run on current thread self._thread.start()
def runLongTask(self): # 创建 QThread self.thread = QThread() # 创建 worker 对象 self.worker = Worker() # 将 work 移到 thread self.worker.moveToThread(self.thread) # 连接信号和槽 self.thread.started.connect(self.worker.run) self.worker.finished.connect(self.thread.quit) self.worker.finished.connect(self.worker.deleteLater) self.thread.finished.connect(self.thread.deleteLater) self.worker.progress.connect(self.reportProgress) # 启动线程 self.thread.start() # 结束 self.longRunningBtn.setEnabled(False) self.thread.finished.connect( lambda: self.longRunningBtn.setEnabled(True)) self.thread.finished.connect( lambda: self.stepLabel.setText("Long-Running Step: 0"))
def slot_test_shiftability(self) -> None: progress_dialog = self.api.get_progress_dialog( 'Shiftability Tester', 'Testing shiftability...', False) progress_dialog.show() self.thread = QThread() self.worker = TestShiftabilityWorker() self.worker.moveToThread(self.thread) self.worker.signal_progress.connect( lambda progress: progress_dialog.set_progress(progress)) self.worker.signal_done.connect( lambda: (self.thread.quit(), progress_dialog.close(), self.api.show_message( 'Shiftability Tester', 'Test complete. See console for more information.'))) self.worker.signal_fail.connect( lambda message: (self.thread.quit(), progress_dialog.close( ), self.api.show_error('Shiftability Tester', message))) self.worker.signal_locations.connect(self.slot_set_locations) self.thread.started.connect(self.worker.process) self.thread.start()
def __init__(self, parent=None): super().__init__(parent) self.thread = QThread() self.worker = None grid_layout = QGridLayout(self) login_group_box = self.create_login_group() data_group_box = self.create_data_group() self.enable_editables.connect(login_group_box.setEnabled) self.enable_editables.connect(data_group_box.setEnabled) self.import_button = QPushButton('Importar', self) self.import_button.setEnabled(False) self.enable_editables.connect(self.import_button.setEnabled) self.import_button.clicked.connect(self.enable_editables) self.import_button.clicked.connect(self.load_data) self.bgg_user_line_edit.textChanged.connect(self.enable_import) self.ludo_mail_line_edit.textChanged.connect(self.enable_import) self.ludo_pass_line_edit.textChanged.connect(self.enable_import) grid_layout.addWidget(login_group_box, 1, 1, 1, 2) grid_layout.addWidget(data_group_box, 2, 1, 1, 2) grid_layout.addWidget(self.import_button, 8, 2) self.log_widget = QTextEdit(self) self.log_widget.setReadOnly(True) grid_layout.addWidget(self.log_widget, 9, 1, 30, 2)
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.l, m = load_gif(self) self.l.setGeometry(0, 0, 20, 20) self.app: QApplication = QApplication.instance() self.calc: QThread = QThread() self.frm: QFrame = QFrame(self) self.tray_icon_menu: QMenu = QMenu(self) self.tray_icon: QSystemTrayIcon = QSystemTrayIcon(self) self.app.view_main = self Setting() About() self.init_settings() self.init_main_window() self.init_tray_icon() self.init_frm() self.setAttribute(Qt.WA_TransparentForMouseEvents) self.shortcut_settings = QShortcut(QKeySequence("Ctrl+,"), self) self.shortcut_settings.activated.connect(self.show_settings) self.shortcut_refresh = QShortcut(QKeySequence("Ctrl+r"), self) self.shortcut_refresh.activated.connect(self.start_to_hope) self.shortcut_refresh = QShortcut(QKeySequence("Ctrl+q"), self) self.shortcut_refresh.activated.connect(self.close) if 'darwin' in sys.platform: menubar = self.menuBar() hope_menu = menubar.addMenu('Hope') hope_menu.addAction( QAction('About', self, triggered=self.show_about)) hope_menu.addAction( QAction('Settings', self, triggered=self.show_settings)) self.show() # self.show_settings() self.start_to_check_update()
def __init__(self, time): QThread.__init__(self) self.time = float(int(time) / 1000)
class Importador(QWidget): """GUI class for the BGG -> Ludopedia importer""" enable_editables = Signal(bool) alternative_chosen = Signal(object) def __init__(self, parent=None): super().__init__(parent) self.thread = QThread() self.worker = None grid_layout = QGridLayout(self) login_group_box = self.create_login_group() data_group_box = self.create_data_group() self.enable_editables.connect(login_group_box.setEnabled) self.enable_editables.connect(data_group_box.setEnabled) self.import_button = QPushButton('Importar', self) self.import_button.setEnabled(False) self.enable_editables.connect(self.import_button.setEnabled) self.import_button.clicked.connect(self.enable_editables) self.import_button.clicked.connect(self.load_data) self.bgg_user_line_edit.textChanged.connect(self.enable_import) self.ludo_mail_line_edit.textChanged.connect(self.enable_import) self.ludo_pass_line_edit.textChanged.connect(self.enable_import) grid_layout.addWidget(login_group_box, 1, 1, 1, 2) grid_layout.addWidget(data_group_box, 2, 1, 1, 2) grid_layout.addWidget(self.import_button, 8, 2) self.log_widget = QTextEdit(self) self.log_widget.setReadOnly(True) grid_layout.addWidget(self.log_widget, 9, 1, 30, 2) def create_qlineedit(self, text): """Creates a label with the given text and an accompanying line edit""" line_edit = QLineEdit(self) line_edit_label = QLabel(text, line_edit) line_edit_label.setBuddy(line_edit) return (line_edit, line_edit_label) def create_login_group(self): """Create labels and line edits for providing BGG and ludopedia login information""" (self.bgg_user_line_edit, bgg_user_label) = self.create_qlineedit('Usuario BoardGameGeek:') (self.ludo_mail_line_edit, ludo_mail_label) = self.create_qlineedit('E-mail Ludopedia:') (self.ludo_pass_line_edit, ludo_pass_label) = self.create_qlineedit('Senha Ludopedia:') self.ludo_pass_line_edit.setEchoMode(QLineEdit.PasswordEchoOnEdit) group_box = QGroupBox('Login') grid_layout = QGridLayout(group_box) grid_layout.addWidget(bgg_user_label, 1, 1) grid_layout.addWidget(self.bgg_user_line_edit, 1, 2) grid_layout.addWidget(ludo_mail_label, 2, 1) grid_layout.addWidget(self.ludo_mail_line_edit, 2, 2) grid_layout.addWidget(ludo_pass_label, 3, 1) grid_layout.addWidget(self.ludo_pass_line_edit, 3, 2) group_box.setLayout(grid_layout) return group_box def create_data_group(self): """Creates group for holding specific choice data selection""" button_group = QButtonGroup(self) button_group.setExclusive(True) colecao_radio_button = QRadioButton('Coleção') self.partidas_radio_button = QRadioButton('Partidas') colecao_radio_button.setChecked(True) button_group.addButton(colecao_radio_button) button_group.addButton(self.partidas_radio_button) (self.min_date_picker, min_date_label) = create_date_picker('À Partir de:', self) (self.max_date_picker, max_date_label) = create_date_picker('Até:', self) self.min_date_picker.dateChanged.connect( self.max_date_picker.setMinimumDate) colecao_radio_button.toggled.connect(self.min_date_picker.setDisabled) colecao_radio_button.toggled.connect(self.max_date_picker.setDisabled) self.map_users_button = QPushButton( 'Ver mapa de usuarios BGG -> Ludopedia', self) self.map_users_button.setEnabled(False) self.map_users_button.clicked.connect(self.user_map) colecao_radio_button.toggled.connect(self.map_users_button.setDisabled) group_box = QGroupBox('Dados') grid_layout = QGridLayout(group_box) grid_layout.addWidget(colecao_radio_button, 1, 1) grid_layout.addWidget(self.partidas_radio_button, 1, 2) grid_layout.addWidget(min_date_label, 2, 1) grid_layout.addWidget(self.min_date_picker, 2, 2) grid_layout.addWidget(max_date_label, 3, 1) grid_layout.addWidget(self.max_date_picker, 3, 2) grid_layout.addWidget(self.map_users_button, 4, 1, 1, 2) group_box.setLayout(grid_layout) return group_box def enable_import(self): """Slot to toggle state of the import button""" self.import_button.setDisabled(not self.bgg_user_line_edit.text() or not self.ludo_mail_line_edit.text() or not self.ludo_pass_line_edit.text()) def log_text(self, message_type, text): """Logs the given text to the QPlainTextWidget""" current_time = QTime.currentTime().toString() if message_type == MessageType.ERROR: self.log_widget.insertHtml( f'[{current_time}] {ERROR_HTML}{text}<br>') elif message_type == MessageType.GENERIC: self.log_widget.insertHtml(f'[{current_time}] {text}<br>') elif message_type == MessageType.DEBUG and ENABLE_DEBUG: self.log_widget.insertHtml( f'[{current_time}] {DEBUG_HTML}{text}<br>') self.log_widget.moveCursor(QTextCursor.End) if ENABLE_DEBUG: print(text) def disconnect_thread(self): """Disconnect the started signal from the thread""" self.thread.started.disconnect() def configure_thread(self, worker): """Does basic thread startup and cleanup configuration""" worker.finished.connect(self.thread.quit) worker.moveToThread(self.thread) self.thread.started.connect(worker.run) worker.message.connect(self.log_text) worker.finished.connect(self.disconnect_thread) worker.exit_on_error.connect(self.thread.quit) worker.exit_on_error.connect(lambda: self.enable_editables.emit(True)) def load_data(self): """Load data from bgg""" try: (session, ludo_user_id) = self.login_ludopedia() bgg_user = self.bgg_user_line_edit.text() if self.partidas_radio_button.isChecked(): current_date = format_qdate(QDate.currentDate()) min_date = parse_date( format_qdate(self.min_date_picker.date()), current_date) max_date = parse_date( format_qdate(self.max_date_picker.date()), min_date) self.worker = BGGPlayFetcher(bgg_user, min_date, max_date) self.configure_thread(self.worker) self.worker.finished.connect(lambda plays: self.post_plays( session, plays, bgg_user, ludo_user_id)) else: self.worker = BGGColectionFetcher(bgg_user) self.configure_thread(self.worker) self.worker.finished.connect( lambda bgg_collection: self.import_collection( session, bgg_collection)) self.thread.start() except InputError: self.enable_editables.emit(True) def show_play_table(self, plays): """Shows a table with all the plays to be imported, allowing user to select some to skip""" tree_model = PlayTableModel(plays) table_widget = QTableView() table_widget.setModel(tree_model) table_widget.verticalHeader().setVisible(False) table_view_header = table_widget.horizontalHeader() table_view_header.setStretchLastSection(True) for column in range(tree_model.columnCount()): column_size = tree_model.data(tree_model.index(0, column), PlayTableModel.SIZE_ROLE) table_view_header.resizeSection(column, column_size) table_widget_dialog = QDialog(self) table_widget_dialog.setModal(True) grid_layout = QGridLayout(table_widget_dialog) grid_layout.addWidget(table_widget, 1, 1) table_widget_dialog.resize(800, 600) table_widget_dialog.exec_() skipped_plays = tree_model.get_skipped_plays() return [play for play in plays if play.id not in skipped_plays] def post_plays(self, session, plays, bgg_user, ludo_user_id): """Receives plays from the Play Fetched thread and start the Ludopedia Logger""" user_map = self.get_bgg_to_ludo_users() if bgg_user not in user_map: user_map[bgg_user] = ludo_user_id selected_plays = self.show_play_table(plays) self.worker = LudopediaPlayLogger(session, selected_plays, bgg_user, user_map) self.worker.request_search.connect( self.request_search_and_show_alternatives, Qt.BlockingQueuedConnection) self.worker.request_alternative.connect(self.request_alternative, Qt.BlockingQueuedConnection) self.alternative_chosen.connect(self.worker.receive_alternative, Qt.DirectConnection) self.configure_thread(self.worker) self.worker.finished.connect(lambda: self.enable_editables.emit(True)) self.thread.start() def user_map(self): """Slot to show user map from bgg to ludopedia""" user_map_dialog = QDialog(self) user_map_dialog.setModal(True) bgg_to_ludo = self.get_bgg_to_ludo_users() user_list = [f'{key} -> {value}' for key, value in bgg_to_ludo.items()] list_widget = QListWidget(user_map_dialog) list_widget.addItems(user_list) list_widget.setResizeMode(QListView.Adjust) list_widget.sortItems() grid_layout = QGridLayout(user_map_dialog) grid_layout.addWidget(list_widget, 1, 1) user_map_dialog.resize(400, 400) user_map_dialog.show() def login_ludopedia(self): """Logins into Ludopedia manually and returns the session and user_id""" self.log_text(MessageType.GENERIC, 'Obtendo dados do Ludopedia') payload = { 'email': self.ludo_mail_line_edit.text(), 'pass': self.ludo_pass_line_edit.text() } session = requests.Session() session_request = session.post(LUDOPEDIA_LOGIN_URL, data=payload) if 'senha incorretos' in session_request.text: self.log_text( MessageType.ERROR, 'Não foi possível logar na Ludopedia com as informações fornecidas' ) raise InputError user_re = re.search(r'id_usuario=(\d+)', session_request.text) user_id = user_re.group(1) if user_re else None return (session, user_id) def import_collection(self, session, collection): """Imports a given collection into Ludopedia""" self.worker = LudopediaCollectionLogger(session, collection) self.configure_thread(self.worker) self.worker.finished.connect(lambda: self.enable_editables.emit(True)) self.thread.start() def show_alternatives_dialog(self, bgg_play, data): """Show alternative games to use as the game to log a play""" alternatives_dialog = QInputDialog(self) alternatives_list = [ f'{item["nm_jogo"]} ({item["ano_publicacao"]})' for item in data ] alternatives_dialog.setComboBoxItems(alternatives_list) alternatives_dialog.setOption(QInputDialog.UseListViewForComboBoxItems) game_str = f'{bgg_play.game_name} ({bgg_play.year_published})' alternatives_dialog.setLabelText( f'Escolha uma alternativa para o jogo "{game_str}"') if alternatives_dialog.exec_(): selected_index = alternatives_list.index( alternatives_dialog.textValue()) return data[selected_index] return None def request_search_and_show_alternatives(self, session, bgg_play): """Request a new string to use for game search and then show results to be picked""" new_search_dialog = QInputDialog(self) game_str = f'{bgg_play.game_name} ({bgg_play.year_published})' new_search_dialog.setLabelText( f'Jogo "{game_str}" não encontrado\nBuscar por:') new_search_dialog.setInputMode(QInputDialog.TextInput) if new_search_dialog.exec_(): data = search_ludopedia_games(session, new_search_dialog.textValue()) data = self.show_alternatives_dialog(bgg_play, data) self.alternative_chosen.emit(data) def request_alternative(self, bgg_play, data): """Request an alternative from user and emit choice""" alternative = self.show_alternatives_dialog(bgg_play, data) self.alternative_chosen.emit(alternative) def get_bgg_to_ludo_users(self): """Reads usuarios.txt file to map a bgg user to its corresponding ludopedia one""" try: parser = ConfigParser() with open("usuarios.txt") as lines: lines = chain(("[top]", ), lines) parser.read_file(lines) bgg_to_ludo_user = dict(parser['top']) bgg_to_ludo_user_id = dict() for bgg_user, ludo_user in bgg_to_ludo_user.items(): if is_invalid_bgg_user(bgg_user): self.log_text( MessageType.ERROR, f'Usuário do BGG "{bgg_user}" inválido' f' no mapa de usuários') continue if ludo_user.isdigit(): bgg_to_ludo_user_id[bgg_user] = ludo_user self.log_text( MessageType.DEBUG, f'Usuário do BGG "{bgg_user}" já mapeado' f' ao id ludopedia: {ludo_user}') else: ludo_user_id = get_ludo_user_id(ludo_user) if ludo_user_id: self.log_text(MessageType.DEBUG, f'{ludo_user_id} para {ludo_user}') bgg_to_ludo_user_id[bgg_user] = ludo_user_id else: self.log_text( MessageType.ERROR, f'Falha ao buscar id de usuario da' f' ludopedia para "{ludo_user}"') return bgg_to_ludo_user_id except FileNotFoundError: self.log_error( MessageType.ERROR, 'Não foi possível encontrar o arquivo "usuarios.txt') return {}