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

Python从其他类向tkinter表格写数据报AttributeError如何解决?

报错根因
  • 执行顺序错误:build_gui方法中先启动了write_table的线程,之后才初始化self.tree属性,线程执行时self.tree还不存在
  • 多实例错误:on_scan回调中每次都会新建mainGUI实例,该实例未执行build_gui方法,自然没有self.tree属性,且和你实际打开的GUI窗口不是同一个实例,写数据也不会显示到可见窗口中
  • 跨线程操作问题:Tkinter的GUI组件不允许在非主线程中操作,直接在线程中调用self.tree.insert后续会出现随机崩溃问题
  • Bridge类变量使用错误:update_data中使用global var1指向的是模块全局变量,而非Bridge类的类属性,数据存储和读取会出现不一致
修复代码

修改 app_example.py

import myGUI
import time
import logging
# 自行补充你缺失的GatewayMessageHandler、Client、ScanEvent等相关导入

logger = logging.getLogger(__name__)
serNo = 1 # 初始化全局序列号
mygui = None # 全局单例GUI实例

class Bridge:  # 修复类变量读写逻辑
    _user_data = "data"

    @classmethod
    def update_data(cls, user_info):
        cls._user_data = user_info

    @classmethod
    def get_data(cls):
        return cls._user_data

# API提供的用于获取扫描数据的函数
def on_scan(client: Client, event: ScanEvent) -> None:
    global serNo
    # 补充扫码结果获取逻辑,你原有代码漏了这步,根据实际API替换即可
    response_text = event.json() 
    user_name = response_text["user"]
    Bridge.update_data(user_name) 
    # 调用全局GUI实例的写入方法,用after把操作丢到GUI主线程执行
    if mygui:
        mygui.window.after(0, mygui.write_table)

# 补充你缺失的其他事件回调函数示例,按需实现
def on_connected(client):
    logger.info("scanner connected")
def on_disconnected(client):
    logger.info("scanner disconnected")
def on_error(client, error):
    logger.error(f"error occur: {error}")
def on_button_pressed_event(client, event):
    logger.info("button pressed")

# API提供的函数
def app_example():     
    global mygui
    handler = GatewayMessageHandler(
        on_scanner_connected=on_connected,
        on_scanner_disconnected=on_disconnected,
        on_scan=on_scan,
        on_error=on_error,
        on_button_pressed=on_button_pressed_event
    )
    logger.info('application started, press Ctrl-C to exit')

    mygui = myGUI.mainGUI()
    mygui.build_gui()  # 调用GUI 

    try:
        while True:
            time.sleep(1000)
    except KeyboardInterrupt:
        gateway.stop()

修改 myGUI.py

import tkinter as tk
from tkinter import ttk
from app_example import Bridge, serNo

class mainGUI:
    def __init__(self):
        # 提前声明属性避免不存在报错
        self.window = None
        self.tree = None

    def build_gui(self):
        self.window = tk.Tk()
        self.window.title("Barcode Scanner 1.0")

        frame_COMinf = tk.Frame(self.window)
        frame_COMinf.grid(row=1, column=1)
        
        # 删除原有的write_table线程启动逻辑,避免跨线程操作GUI
        style = ttk.Style()
        style.theme_use("clam")
        style.element_create("Custom.Treeheading.border", "from", "default")
        style.layout("Custom.Treeview.Heading", [
            ("Custom.Treeheading.cell", {'sticky': 'nswe'}),
            ("Custom.Treeheading.border", {'sticky': 'nswe', 'children': [
                ("Custom.Treeheading.padding", {'sticky': 'nswe', 'children': [
                    ("Custom.Treeheading.image", {'side': 'right', 'sticky': ''}),
                    ("Custom.Treeheading.text", {'sticky': 'we'})
                ]})
            ]}),
        ])

        frame = tk.Frame(self.window)
        style.theme_use("clam")
        frame.grid(row=3, column=1)

        # 先完成tree组件初始化
        self.tree = ttk.Treeview(frame, columns=(1, 2, 3, 4, 5), height=20, show="headings", 
                     style="Custom.Treeview")
        self.tree.pack(side='left')

        style.configure("Custom.Treeview.Heading",
                    background="blue", foreground="white", relief="flat")
        style.map("Custom.Treeview.Heading",
              relief=[('active', 'groove'), ('pressed', 'sunken')])

        self.tree.heading(1, text="Ser.No")
        self.tree.heading(2, text="user")

        self.tree.column(1, width=50, anchor='center')
        self.tree.column(2, width=100, anchor='center')

        self.scroll = tk.Scrollbar(frame, orient="vertical", command=self.tree.yview)
        self.scroll.pack(side='right', fill=tk.Y)
        self.tree.configure(yscrollcommand=self.scroll.set)
        self.window.mainloop()

    def write_table(self):
        global serNo
        # 加判断避免tree未初始化时报错
        if not self.tree:
            return
        user_data = Bridge.get_data()
        self.tree.insert('', 'end', values=(serNo, user_data), tags=('gr',))
        serNo += 1
        self.tree.tag_configure('gr', background='green')

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 01:57:07