You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用AlleleTyper WebView后,打开CSV程序崩溃问题排查求助

基因检测GUI程序崩溃问题排查与修复

问题背景

开发基因检测报告流程的GUI程序,采用标签页工作流。在AlleleTyper标签页使用WebView功能后,切换至双倍型计算器标签页打开CSV文件时程序直接关闭,相关csv_window函数代码如下:

def csv_window(file_path):
    data, header_list = read_csv_file(file_path)

    sg.popup_quick_message('Building your main window.... one moment....', background_color='#1c1e23', text_color='white', keep_on_top=True, font='_ 30')

    # ------ Window Layout ------
    layout = [  [sg.Text('Click a heading to sort on that column or enter a filter and click a heading to search for matches in that column')],
                [sg.Text(f'{len(data)} Records in table', font='_ 18')],
                [sg.Text(k='-RECORDS SHOWN-', font='_ 18')],
                [sg.Text(k='-SELECTED-')],
                [sg.T('Filter:'), sg.Input(k='-FILTER-', focus=True, tooltip='Not case sensative\nEnter value and click on a col header'),
                 sg.B('Reset Table', tooltip='Resets entire table to your original data'),
                 sg.Checkbox('Sort Descending', k='-DESCENDING-'), sg.Checkbox('Filter Out (exclude)', k='-FILTER OUT-', tooltip='Check to remove matching entries when filtering a column'), sg.Push()],
                [sg.Table(values=data, headings=header_list, max_col_width=25,
                        auto_size_columns=True, display_row_numbers=True, vertical_scroll_only=True,
                        justification='right', num_rows=50,
                        key='-TABLE-', selected_row_colors='red on yellow', enable_events=True,
                        expand_x=True, expand_y=True,
                        enable_click_events=True)],
                [sg.Sizegrip()]]

    # ------ Create Window ------
    window = sg.Window('CSV Table Display', layout, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT,  resizable=True, size=(800, 600), finalize=True)
    window.bind("<Control_L><End>", '-CONTROL END-')
    window.bind("<End>", '-CONTROL END-')
    window.bind("<Control_L><Home>", '-CONTROL HOME-')
    window.bind("<Home>", '-CONTROL HOME-')
    original_data = data        # save a copy of the data
    # ------ Event Loop ------
    while True:
        event, values = window.read()
        # print(event, values)
        if event in (sg.WIN_CLOSED, 'Exit'):
            break
        if values['-TABLE-']:           # Show how many rows are slected
            window['-SELECTED-'].update(f'{len(values["-TABLE-"])} rows selected')
        else:
            window['-SELECTED-'].update('')
        if event[0] == '-TABLE-':
        # if isinstance(event, tuple):
            filter_value = values['-FILTER-']
            # TABLE CLICKED Event has value in format ('-TABLE=', '+CLICKED+', (row,col))
            if event[0] == '-TABLE-':
                if event[2][0] == -1 and event[2][1] != -1:  # Header was clicked and wasn't the "row" column
                    col_num_clicked = event[2][1]
                    # if there's a filter, first filter based on the column clicked
                    if filter_value not in (None, ''):
                        filter_out = values['-FILTER OUT-']     # get bool filter out setting
                        new_data = []
                        for line in data:
                            if not filter_out and (filter_value.lower() in line[col_num_clicked].lower()):
                                new_data.append(line)
                            elif filter_out and (filter_value.lower() not in line[col_num_clicked].lower()):
                                new_data.append(line)
                        data = new_data
                    new_table = sort_table(data, (col_num_clicked, 0), values['-DESCENDING-'])
                    window['-TABLE-'].update(new_table)
                    data = new_table
                    window['-RECORDS SHOWN-'].update(f'{len(new_table)} Records shown')
                    window['-FILTER-'].update('')           # once used, clear the filter
                    window['-FILTER OUT-'].update(False)  # Also clear the filter out flag
        elif event == 'Reset Table':
            data = original_data
            window['-TABLE-'].update(data)
            window['-RECORDS SHOWN-'].update(f'{len(data)} Records shown')
        elif event == '-CONTROL END-':
            window['-TABLE-'].set_vscroll_position(100)
        elif event == '-CONTROL HOME-':
            window['-TABLE-'].set_vscroll_position(0)
        elif event == 'Edit Me':
            sg.execute_editor(__file__)
        elif event == 'Version':
            sg.popup_scrolled(__file__, sg.get_versions(), location=window.current_location(), keep_on_top=True, non_blocking=True)
    window.close()

可能的原因及修复方案

1. WebView资源未正确释放

PySimpleGUI的WebView组件在切换标签页时可能未释放占用的GUI线程或内存资源,导致后续创建CSV窗口时出现资源冲突,触发程序崩溃。

  • 修复: 在切换出AlleleTyper标签页的事件中,显式销毁WebView组件:
    # 假设WebView组件的key是'-WEBVIEW-'
    def on_tab_change(event):
        if event == '双倍型计算器':
            window['-WEBVIEW-'].destroy()
    
    或者在每次切换到AlleleTyper标签页时重新初始化WebView,避免长期占用资源。

2. 多窗口事件循环冲突

csv_window作为独立窗口拥有自己的事件循环,而WebView可能占用了GUI主线程资源,导致主标签页循环与子窗口循环发生竞争,引发崩溃。

  • 修复: 将CSV窗口设置为模态窗口,让子窗口阻塞主循环直到关闭,减少资源竞争:
    修改csv_window中的窗口创建代码,添加modal=True参数:
    window = sg.Window('CSV Table Display', layout, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, 
                       resizable=True, size=(800, 600), finalize=True, modal=True)
    

3. CSV数据类型不兼容

read_csv_file返回的数据可能包含非字符串类型的单元格,在WebView导致内存状态异常时,Table组件渲染这类数据会触发隐式错误,直接导致程序崩溃而非抛出异常。

  • 修复:
    1. 在read_csv_file中统一将所有单元格转为字符串:
      def read_csv_file(file_path):
          # 原有读取逻辑...
          # 转义所有单元格为字符串
          data = [[str(cell) if cell is not None else "" for cell in row] for row in data]
          return data, header_list
      
    2. 在csv_window开头添加异常捕获,避免崩溃扩散:
      def csv_window(file_path):
          try:
              data, header_list = read_csv_file(file_path)
              # 后续窗口创建和事件循环代码
          except Exception as e:
              sg.popup_error(f"加载CSV失败: {str(e)}")
              return
      

4. Table事件处理的潜在索引错误

当前csv_window的事件处理中,未判断event是否为元组就直接访问event[0]、event[2],当WebView导致事件队列异常时,会触发索引错误导致程序崩溃。

  • 修复: 先校验事件类型,再处理Table点击事件:
    # 替换原有的Table事件判断代码
    if isinstance(event, tuple) and event[0] == '-TABLE-':
        filter_value = values['-FILTER-']
        # 确保点击的是表头列
        if len(event) >=3 and event[2][0] == -1 and event[2][1] != -1:
            col_num_clicked = event[2][1]
            # 原有过滤和排序逻辑...
    

内容的提问来源于stack exchange,提问作者ClarkThark

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 15:49:52