Question

I am trying to simultaneously read data from a HID with pywinusb and then update a tkinter window with that data. When something happens on the HID side, I want my tkinter window to immediately reflect that change.

Here is the code:

import pywinusb.hid as hid
from tkinter import *

class MyApp(Frame):
    def __init__(self, master):           
        super(MyApp, self).__init__(master)
        self.grid() 
        self.setupWidgets()
        self.receive_data()

    def setupWidgets(self):
        self.data1 = StringVar()
        self.data1_Var = Label(self, textvariable = self.data1)
        self.data1_Var.grid(row = 0, column = 0, sticky = W)

    def update_data1(self, data):
        self.data1.set(data)
        self.data1_Var.after(200, self.update_data1)

    def update_all_data(self, data):
        self.update_data1(data[1])
        #self.update_data2(data[2]), all points updated here...

    def receive_data(self):
        self.all_hids = hid.find_all_hid_devices()
        self.device = self.all_hids[0]
        self.device.open()
        #sets update_all_data as data handler
        self.device.set_raw_data_handler(self.update_all_data)

root = Tk()
root.title("Application")
root.geometry("600x250")
window = MyApp(root)
window.mainloop()

When I run the code and make the device send data, I get this error:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Program Files\Python 3.3\lib\tkinter\__init__.py", line 1442, in __call__
    return self.func(*args)
  File "C:\Program Files\Python 3.3\lib\tkinter\__init__.py", line 501, in callit
    func(*args)
TypeError: update_data1() missing 1 required positional argument: 'data'

I guess my question is:

How do I continually update the label with the current data from the HID? How can I pass the new data to update_data1()?

Edit: Should I be using threading, so that I have one thread receiving data and the mainloop() thread periodically checking for new data? I haven't used threading before, but could this be a solution?

If there is a better way to do this, please let my know.

Thanks!

Was it helpful?

Solution

self.data1_Var.after(200, self.update_data1) is the problem. You need to pass self.update_data1's parameter to self.data1_Var.after (e.g. self.data1_Var.after(200, self.update_data1, some_data)). Otherwise after 200 milliseconds, self.update_data1 will be called without the parameter, causing the error you are seeing.

BTW, why don't directly edit the label's text instead of putting the code in self.update_all_data. It's not clear to me why self.data1_Var.after(200, self.update_data1) is required, because whenever new data is received, update_all_data is called, which calls update_data1 which updates the text.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top