PyQt6 应用程序意外自动关闭,没有留下任何错误消息

问题描述 投票:0回答:1

我正在开发一个 PyQt6 应用程序,该应用程序可以实时采集随时间变化的光子强度跟踪并实时绘制它,然后调用 pyo3 函数对数据进行后处理。用户可以选择是否“自动执行多次采集”。例如,如果他们选择连续进行 5 次采集,软件将按顺序执行采集。 在我的主窗口中,我已经初始化了这些处理队列获取实时数据的变量:

self.pull_from_queue_timer = QTimer() self.pull_from_queue_timer.timeout.connect(partial(IntensityTracing.pull_from_queue, self))

在控制器类中,我有以下功能:

start_button_pressed

通过执行各种操作来初始化采集过程,包括 GUI 操作和调用另一个函数,该函数将实际调用负责启动采集的外部库:

@staticmethod
  def start_button_pressed(app):
        IntensityTracingButtonsActions.clear_intensity_grid_widgets(app) 
        app.acquisition_stopped = False
        app.warning_box = None
        app.settings.setValue(SETTINGS_ACQUISITION_STOPPED, False)
        #app.control_inputs[DOWNLOAD_BUTTON].setEnabled(app.write_data and app.acquisition_stopped)
        #self.set_download_button_icon()
        warn_title, warn_msg = MessagesUtilities.invalid_inputs_handler(
            app.bin_width_micros,
            app.time_span,
            app.acquisition_time_millis,
            app.control_inputs[SETTINGS_FREE_RUNNING_MODE],
            app.enabled_channels,
            app.selected_conn_channel,
        )
        if warn_title and warn_msg:
            message_box = BoxMessage.setup(
                warn_title, warn_msg, QMessageBox.Icon.Warning, GUIStyles.set_msg_box_style(), app.test_mode
            )
            app.warning_box = message_box
            return
        app.control_inputs[START_BUTTON].setEnabled(False)
        app.control_inputs[STOP_BUTTON].setEnabled(app.free_running_acquisition_time)   
        app.intensity_charts.clear()
        app.intensity_lines.clear()
        app.last_acquisition_ns = 0
        app.gt_charts.clear()
        app.cps_ch.clear()
        for chart in app.intensity_charts:
            chart.setVisible(False)
        for chart in app.gt_charts:
            chart.setVisible(False)
        for channel, curr_conn in app.intensity_connectors.items():    
            curr_conn.disconnect()
        remove_widget(app.layouts[PLOT_GRIDS_CONTAINER], app.widgets[GT_WIDGET_WRAPPER])      
        gt_widget = create_gt_wait_layout(app)
        insert_widget(app.layouts[PLOT_GRIDS_CONTAINER], gt_widget, 1)    
        app.intensity_connectors.clear()
        app.gt_lines.clear()         
        app.intensity_charts_wrappers.clear()
        QApplication.processEvents()         
        IntensityTracingButtonsActions.intensity_tracing_start(app)
        if not app.widgets[GT_WIDGET_WRAPPER].isVisible():
            IntensityTracingButtonsActions.show_gt_widget(app, True) 
        IntensityTracing.start_photons_tracing(app)

start_photons_tracing

函数与外部库通信开始采集并启动连接到pull_from_queue函数的定时器:

@staticmethod
    def start_photons_tracing(app):
        try:
            free_running_mode = app.control_inputs[SETTINGS_FREE_RUNNING_MODE].isChecked()
            acquisition_time_millis = (
                None if app.acquisition_time_millis in (0, None) or
                        free_running_mode
                else app.acquisition_time_millis
            )
            print("Selected firmware: " + (str(app.selected_firmware)))
            print("Free running enabled: " + str(free_running_mode))
            print("Acquisition time (ms): " + str(acquisition_time_millis))
            print("Time span (s): " + str(app.time_span))
            print("Max points: " + str(40 * app.time_span))
            print("Bin width (µs): " + str(app.bin_width_micros))
            result = flim_labs.start_intensity_tracing(
                enabled_channels=app.enabled_channels,
                bin_width_micros=app.bin_width_micros, 
                write_bin=False,  
                write_data=True,  
                acquisition_time_millis=acquisition_time_millis, 
                firmware_file=app.selected_firmware,
            )
            if app.acquisitions_count >= app.selected_average:           
                app.widgets[PROGRESS_BAR_WIDGET].clear_acquisition_timer(app)
            if not free_running_mode:
                app.widgets[PROGRESS_BAR_WIDGET].update_acquisitions_count()
                app.widgets[PROGRESS_BAR_WIDGET].setVisible(True)
            file_bin = result.bin_file
            if file_bin != "":
                print("File bin written in: " + str(file_bin))
            app.blank_space.hide()
            app.pull_from_queue_timer.start(1)
            app.last_cps_update_time.start()  
        except Exception as e:
            error_title, error_msg = MessagesUtilities.error_handler(str(e))
            BoxMessage.setup(
                error_title,
                error_msg,
                QMessageBox.Icon.Critical,
                GUIStyles.set_msg_box_style(),
                app.test_mode
            )

pull_from_queue

函数通过调用外部库检索实时数据。如果用户设置了按顺序完成一定数量的采集,一旦完成一个并且尚未达到所选的采集数量,则再次调用

start_button_pressed 重新启动该过程
: @staticmethod def pull_from_queue(app): val = flim_labs.pull_from_queue() if len(val) > 0: for v in val: if v == ('end',): # End of acquisition print("Got end of acquisition, stopping") IntensityTracing.stop_button_pressed(app) if app.acquisitions_count < app.selected_average: IntensityTracingButtonsActions.start_button_pressed(app) break ((time_ns), (intensities)) = v IntensityTracing.calculate_cps(app, time_ns[0], intensities)

这是 
stop_button_pressed

函数,称为:

    def stop_button_pressed(app, app_close = False):
        time.sleep(0.5)
        try:
            flim_labs.request_stop()
        except:
            pass  
        if app.acquisitions_count >= app.selected_average:           
            app.acquisition_count = 0
        else:    
            app.acquisitions_count = app.acquisitions_count + 1  
        app.widgets[PROGRESS_BAR_WIDGET].update_acquisitions_count()            
        app.last_cps_update_time.invalidate() 
        app.control_inputs[START_BUTTON].setEnabled(len(app.enabled_channels) > 0)    
        app.control_inputs[STOP_BUTTON].setEnabled(False)
        if not app_close and app.acquisitions_count == app.selected_average: 
            remove_widget(app.layouts[PLOT_GRIDS_CONTAINER], app.widgets[GT_WIDGET_WRAPPER])
            gt_widget = create_gt_loading_layout(app)
            insert_widget(app.layouts[PLOT_GRIDS_CONTAINER], gt_widget, 1)
        QApplication.processEvents()
        app.pull_from_queue_timer.stop() 
        for channel, curr_conn in app.intensity_connectors.items():     
            curr_conn.pause()          
        if not app_close: 
            if app.acquisitions_count == app.selected_average:
                FCSPostProcessing.get_input(app)  

问题是这样的:
如果我选择执行多次采集,此过程会随机且意外地冻结,有时会关闭应用程序而不会释放任何错误。调试时,应用程序总是在 stop_button_pressed 内冻结,但冻结的点是随机的。

当我进行多次采集时,我尝试使用另一个 QTimer 单独处理逻辑,但没有任何改变。问题可能出在哪里?谢谢。

python pyqt pyqt6 qtimer
1个回答
0
投票
flim_labs.pull_from_queue()

被阻塞,它可以冻结 GUI。

尝试使用 QThread 将耗时的操作(如( 

flim_labs.start_intensity_tracing()

flim_labs.pull_from_queue()
)移至分离线程。
    

© www.soinside.com 2019 - 2024. All rights reserved.