Python Forum
[Tkinter] Call a class method from another (Tk GUI) class?
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
Reply
#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
Reply
#3
Instead of time.sleep, use tkinter's after method.
Reply
#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
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
Video [PyQt] Get a executable file (.exe) from a .py file add a promoted class in a QWidget MiguelonReyes 0 615 Oct-17-2023, 11:43 PM
Last Post: MiguelonReyes
  [Tkinter] Take the variable of a cursor class delcencen 2 1,149 Feb-13-2023, 05:19 AM
Last Post: deanhystad
Lightbulb Using Tkinter With Concurrent.Futures / ThreadPoolExecutor Class AaronCatolico1 1 1,418 Dec-14-2022, 08:01 PM
Last Post: deanhystad
  [PyQt] CustomSortFilterProxyModel Class Using hasantr 2 1,167 Dec-02-2022, 01:57 PM
Last Post: hasantr
Bug [Tkinter] CanĀ“t create a class for frames ThomasFab 5 1,943 Sep-28-2022, 08:44 PM
Last Post: deanhystad
Lightbulb [Tkinter] Tkinter Class Import Module Issue AaronCatolico1 6 2,971 Sep-06-2022, 03:37 PM
Last Post: AaronCatolico1
  [Tkinter] define entry via class on a loop drSlump 9 3,375 Oct-27-2021, 05:01 PM
Last Post: deanhystad
  [Kivy] Acces atributes from a button defined in a class inside the .kv Tomli 2 2,054 Jun-10-2021, 01:05 AM
Last Post: Tomli
  [Tkinter] Modify Class on Button Click KDog 4 3,904 May-11-2021, 08:43 PM
Last Post: KDog
Question [PyQt] Need help with class composition / multiple inheritance / polymorphism (?) Alfalfa 4 3,014 May-11-2021, 12:55 PM
Last Post: deanhystad

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020