class ProgressWidget(QWidget): ''' The ProgressWidget initializes the process and displays information about it. Args: progress_icon (str): the file path of the loading icon gif Attributes: thread (QThread): the thread used by the widget to delegate the processor to file_name_label (QLabel): displays the file name that was selected averaging_label (QLabel): displays the averaging duration number and unit selected start_label (QLabel): displays the start time selected (or N/A) end_label (QLabel): displays the end time selected (or N/A) movie (QMovie): runs the loading icon gif All labels are defined as attributes of the class so they can be modified at the start of each process. ''' def __init__(self, progress_icon): super().__init__() # delegation thread used to run the process off of the main event loop self.thread = QThread() self.thread.setObjectName("Data Processor Thread") # define information labels title_label = QLabel("Analysis in progress...") title_label.setObjectName("title") self.file_name_label = QLabel("") self.file_name_label.setObjectName("details") self.averaging_label = QLabel("") self.averaging_label.setObjectName("details") self.start_label = QLabel("") self.start_label.setObjectName("details") self.end_label = QLabel("") self.end_label.setObjectName("details") # define movie and container label self.movie = QMovie(progress_icon) loading_label = QLabel() loading_label.setAlignment(Qt.AlignCenter) loading_label.setMovie(self.movie) # define layout layout = QVBoxLayout() layout.addWidget(title_label) layout.addWidget(self.file_name_label) layout.addWidget(self.averaging_label) layout.addWidget(self.start_label) layout.addWidget(self.end_label) layout.addWidget(loading_label) self.setLayout(layout) # takes in all parameters related to the process and spawns a worker to run it def begin_progress(self, file_name, file_path, output_path, ad_num, ad_unit, start, end, pdf_header): # populate labels with inputted parameters self.file_name_label.setText("File Name: " + file_name) self.averaging_label.setText("Averaging Duration: " + str(ad_num) + " " + ad_unit) if start != None and end != None: self.start_label.setText("Start Time: " + start.toString()) self.end_label.setText("End Time: " + end.toString()) else: self.start_label.setText("Start Time: N/A") self.end_label.setText("End Time: N/A") # start icon gif and allow main event loop to process it self.movie.start() qApp.processEvents() # define a worker object, move it to a new thread, and begin the processor work self.processor = Processor(file_path, output_path, ad_num, ad_unit, start, end, pdf_header) self.processor.moveToThread(self.thread) self.thread.started.connect(self.processor.work) self.processor.result_signal.connect(self.finish) self.thread.start() # ends the process and makes a callback to the main window with the result @pyqtSlot(str, bool) def finish(self, output, error): # stop and disconnect the thread from the processor object self.thread.quit() self.thread.wait() self.thread.disconnect() self.movie.stop() self.parentWidget().parentWidget().complete_analysis(output, error)
class Application(): def __init__(self, get_resources): self.get_resources = get_resources # Get resources config.initiate() # Initiate configurations self.start_timer_thread() # Start timer on separate thread self.start_application() # Start application def start_timer_thread(self): # create Worker and Thread self.worker = Worker() # no parent! self.thread = QThread() # no parent! # Move the Worker object to the Thread object self.worker.moveToThread(self.thread) # Connect Thread started signal to Worker operational slot method self.thread.started.connect(self.worker.start) # Connect Worker`s Signals to update progressbar. self.worker.fire_alarm.connect(self.fire_alarm) self.thread.start() def start_application(self): app = QApplication(sys.argv) self.trayIcon = QSystemTrayIcon( QIcon("src/main/resources/base/alarm-clock.svg"), app) self.menu = QMenu() self.configureAction = self.menu.addAction('Configure') self.configureAction.triggered.connect(self.configure) self.notifyAction = self.menu.addAction('Notification') self.notifyAction.triggered.connect(self.restart_timer) self.quitAction = self.menu.addAction('Quit') self.quitAction.triggered.connect(self.exit) self.trayIcon.setContextMenu(self.menu) self.trayIcon.show() sys.exit(app.exec_()) def restart_timer(self): for timer in self.worker.timers: # Stop all timers timer.stop() self.thread.disconnect() self.thread.quit( ) # This is very important(Quit thread b4 restarting it) self.thread.started.connect(self.worker.start) while self.thread.isRunning(): pass else: self.thread.start() def fire_alarm(self, time, message): alarm_data = {'time': time, 'message': message} self.notification = Notification(self.get_resources, alarm_data) self.notification.show() def configure(self): self.preference = Preferences() self.preference.show() def exit(self): sys.exit()