I am trying to add my GUI and get data from the simple scanner demo application in python. This scanner demo application handles various events like scan event, scanner_connected, scanner_disconnected etc.
Initially I'm calling the GUI class in the demo application to initiate the GUI. When the scan event raises , I take the data and pass the data to a Bridge class. After that I call a GUI function called write_data which is responsible to print the data to a table. This write_table function calls the Bridge class to get the updated scan data
#app_example.py
import myGUI
class Bridge: # a class to store the data from the scan_event
var1 = "data"
def __init__(self):
# does
nothing
def update_data(self, user_info):
global var1
var1 = user_info
def get_data(self):
global var1
return var1
# function from the APi to get the scan data
def on_scan(client: Client, event: ScanEvent) -> None:
user_name = response_text["user"]
b = Bridge()
b.update_data(user_name) # saving the scan data to a function from Bridge class
mygui = mainGUI()
mygui.write_table() # calling the GUI function to write data to a table
# function from the APi
def app_example():
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 = mainGUI()
mygui.build_gui() # calling the GUI
try:
while True:
time.sleep(1000)
except KeyboardInterrupt:
gateway.stop()
# myGUI.py
class mainGUI:
def __init__(self):
# does
nothing
def build_gui(self):
window = tk.Tk()
window.title("Barcode Scanner 1.0")
frame_COMinf = tk.Frame(window)
frame_COMinf.grid(row=1, column=1)
# initating a thread to the function write_table
self.thread = Thread(target=self.write_table)
self.thread.start()
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(window)
style.theme_use("clam")
frame.grid(row=3, column=1)
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)
window.mainloop()
def write_table(self):
# this function calls the Bridge class and get the scan data
global serNo
bridge = Bridge()
user_data = bridge.get_data()
data = [[serNo, user_data]]
for val in data:
self.tree.insert('', 'end', values=(val[0], val[1]), tags=('gr',))
serNo = 1
self.tree.tag_configure('gr', background='green')
The error I get is
self.tree.insert('', 'end', values = (val[0], val[1]), tags=('gr',))
AttributeError: 'mainGUI' object has no attribute 'tree'
I do not have much knowledge in object-oriented programming using python. Could someone help how to write the data for this table?
CodePudding user response:
You started a thread to run write_data()
inside build_gui()
before creating self.tree
:
class mainGUI:
def __init__(self):
# does nothing
pass
def build_gui(self):
window = tk.Tk()
window.title("Barcode Scanner 1.0")
frame_COMinf = tk.Frame(window)
frame_COMinf.grid(row=1, column=1)
# initating a thread to the function write_table
self.thread = Thread(target=self.write_table)
self.thread.start()
### the above code will execute `write_table()` before `self.tree` is created
...
frame = tk.Frame(window)
style.theme_use("clam")
frame.grid(row=3, column=1)
self.tree = ttk.Treeview(frame, columns=(1, 2, 3, 4, 5), height=20, show="headings",
style="Custom.Treeview")
self.tree.pack(side='left')
...
window.mainloop()
So better create and start the thread before window.mainloop()
:
class mainGUI:
...
def build_gui(self):
window = tk.Tk()
window.title("Barcode Scanner 1.0")
frame_COMinf = tk.Frame(window)
frame_COMinf.grid(row=1, column=1)
...
frame = tk.Frame(window)
style.theme_use("clam")
frame.grid(row=3, column=1)
self.tree = ttk.Treeview(frame, columns=(1, 2, 3, 4, 5), height=20, show="headings",
style="Custom.Treeview")
self.tree.pack(side='left')
...
# initating a thread to the function write_table
self.thread = Thread(target=self.write_table)
self.thread.start()
window.mainloop()
Another suspect cause:
# function from the APi to get the scan data
def on_scan(client: Client, event: ScanEvent) -> None:
user_name = response_text["user"]
b = Bridge()
b.update_data(user_name) # saving the scan data to a function from Bridge class
mygui = mainGUI()
### as mygui.build_gui() is not called
### below line will raise the error
mygui.write_table() # calling the GUI function to write data to a table
CodePudding user response:
The write_data function is not indented and is not a method of the class mainGUI. (This was fixed)
You try to access the self.tree variable before it is initialized.
The line where you call self.tree:
self.thread = Thread(target=self.write_table)
And you are initializing it further down:
self.tree = ttk.Treeview(frame, columns=(1, 2, 3, 4, 5), height=20, show="headings",
style="Custom.Treeview")
A default self.tree in __ init__() would help you.
If you cannot set it in the init method of the class then maybe something like this can help:
for val in data:
try:
self.tree.insert('', 'end', values=(val[0], val[1]), tags=('gr',))
except AttributeError: # And do the initialization here. Pretty ugly though.
self.tree = ttk.Treeview(frame, columns=(1, 2, 3, 4, 5), height=20, show="headings", style="Custom.Treeview")
# ... do all other stuff with the Treeview widget.
# ...
# do as normal
But I don't know where exactly you need this initialized in the first place. This would be the absolute latest you need to initialize it.