Bottom Page

Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
 [Tkinter] Call a class method from another (Tk GUI) class?
#1
I am trying to create a simple timed event class that I can use to trigger repeating events in other programs (e.g.: data logger). I know that since Python functions (methods) are first class objects they can be passed around easily, stored in lists or dicts, etc. so I thought that it would be easy to just store a function as a class attribute and call it from there when needed. But, I'm having trouble calling the stored function. In my App class (Tk) I need to call the function in App.run_events() but if I try without the parenthesis it does nothing and if I add them the program hangs. I suspect I'm missing something obvious but after spending the last decade coding in LabVIEW my brain might just be corrupted in some way.

The issue is down between the lines of ###########s...

If I'm doing something "un-pythonic" and you feel there's a better way to tackle this please feel free to say so. I'm finally back to Python in my main job so I want to move forward doing things the right way.

Thanks All,
K

#! /usr/bin/env python

import tkinter as tk
import time

class Event(object):
    """ Event Class for timing repetitive events. """

    event_list = []

    def __init__(self, name, interval, method_to_call):
        self.name = name
        self.interval = interval # The time delay (in seconds) between subsequent triggers of this event.
        self.method_to_call = method_to_call # The function to be executed when this event is triggered.
        self.init_time = time.time() # Keep the timestamp of when the event was initialized for later use.
        self.last_time = self.init_time
        Event.event_list.append(self)

    def __str__(self):
        return f"EVENT -- Name: {self.name}, Interval: {self.interval}, Method Called: {self.method_to_call.__name__}."

    def check_event_ready(self):
        """ Test whether an event interval has elapsed and it's ready to run again. """

        if time.time() - self.last_time >= self.interval:
            self.last_time = time.time()
            return True
        else:
            return False


class App():
    def __init__(self):
        self.root = tk.Tk()

        self.event_listbox = tk.Listbox(width=50, height=25)
        self.event_listbox.pack()

        self.status_listbox = tk.Listbox(width=50, height=5)
        self.status_listbox.pack()

        self.setup() # Load up the Events to run.
        self.run_events() # Start the Event checking loop.
        self.root.mainloop() # Start the Tk GUI.

    def setup(self):
        """ Setup the events with their interval timing and function to execute. """

        ev1 = Event("Collect Data", 2, self.collect_data)
        ev2 = Event("Update Network", 5, self.update_network)
        for e in Event.event_list:
            print(e)

#####################################################################################################################
    def run_events(self):
        """ Spins a fast loop (using Tk.root.after()) to constantly check whether it's time to trigger an event. """

        for event in Event.event_list:
            if event.check_event_ready():
                self.event_listbox.insert(tk.END, event.name)
                event.method_to_call ### HOW DO I CALL THIS METHOD???
                print(event.method_to_call.__name__) # It prints just fine.
######################################################################################################################

        self.root.after(10, self.run_events) # Repeat at 10mS resolution.

    def collect_data(self):
        self.status_listbox.insert(tk.END, "Collect Data Running")
        time.sleep(500) # Add time delay to see if I need to use threading.

    def update_network(self):
        self.status_listbox.insert(tk.END, "Update Network Running")
        time.sleep(500)

app = App()
"So, brave knights, if you do doubt your courage or your strength, come no further, for death awaits you all with nasty, big, pointy teeth!" - Tim the Enchanter
Quote
#2
Looks like I got ahead of myself and caused the problem. Blush It was the time.sleep() functions I added to the methods I wanted to call through the events that were causing the program to hang. I knew I would eventually need to thread the functions running under Tk so I should have left the calls to sleep() out until I had the basics working. I keep forgetting the python's sleep() function is in seconds, NOT milli-seconds so of course it looked like the program was hanging when it was working fine.

If you want to run the code just change the 500 in time.sleep(500) to a small number of seconds and you can see that the functions are being called but then tie up the thread. Time to start working with the threading and multi-processor modules...
"So, brave knights, if you do doubt your courage or your strength, come no further, for death awaits you all with nasty, big, pointy teeth!" - Tim the Enchanter
Quote
#3
Instead of time.sleep, use tkinter's after method.
Quote
#4
Thanks for your reply! I'm using .after() in the Event class to poll for when an event is ready to run but I can't use it to replace sleep since sleep is only a simulation for testing. In the real code, an event like collect_data will cause real hardware to scan a bunch of signals and it will actually take a few seconds. I don't want the GUI to go unresponsive so I'm pretty sure the best solution is threading (or multi-processing). I'm working on that now... Slowly. Wall
"So, brave knights, if you do doubt your courage or your strength, come no further, for death awaits you all with nasty, big, pointy teeth!" - Tim the Enchanter
Quote

Top Page

Possibly Related Threads...
Thread Author Replies Views Last Post
  Class function does not create command button Heyjoe 2 138 Aug-22-2020, 08:06 PM
Last Post: Heyjoe
  [Tkinter] Troubles with accessing attr from other class zarize 3 208 Aug-20-2020, 06:05 PM
Last Post: deanhystad
  [Tkinter] Use function from other class (Tkinter) zarize 8 314 Aug-17-2020, 09:47 AM
Last Post: zarize
  [PyQt] remove widget from other class issac_n 2 271 Aug-05-2020, 01:55 PM
Last Post: deanhystad
  [Tkinter] Creation of Buttons with Shared Command Inside Class MulliganAgain 1 176 Jul-08-2020, 06:22 PM
Last Post: Yoriz
  How to place global tk text widget in class or on canvas puje 1 208 Jul-04-2020, 09:25 AM
Last Post: deanhystad
  [PyQt] I get a name Name Error: when calling a method inside a class radoo 2 258 Jun-11-2020, 05:02 PM
Last Post: radoo
  Getting a variable from one class to another class menator01 6 397 Apr-26-2020, 04:36 PM
Last Post: Larz60+
  Updating a variable within a class MC2020 2 294 Apr-17-2020, 11:31 AM
Last Post: MC2020
  [Tkinter] Program with Multiple Windows - how to use Class: Riddle 1 360 Apr-09-2020, 08:30 PM
Last Post: Riddle

Forum Jump:


Users browsing this thread: 1 Guest(s)