I am trying to run a function every 10 milliseconds, but I am unable to do so. So I figured I would try to find the problem with using print("hi") and found that it only calls that line once, when the object app is created. I tried lambda, I tried threading, I tried a lot of stuff. But tkinter should have a .after() method but it doesn't work for me. Please help!
import customtkinter
import tkinter as tk
import os
from PIL import Image
from metals import Metal
from alloy_calculator import AlloyCalc as Alloy
# System Settings
customtkinter.set_appearance_mode("dark")
customtkinter.set_default_color_theme("blue")
class App(customtkinter.CTk):
def __init__(self):
super().__init__()
# Main Window
self.geometry("650x740")
self.title("Auto TerrafirmaCraft Alloy Calculator")
self.grid_rowconfigure((0), weight=0)
self.grid_rowconfigure((1), weight=0)
# first column is as big as necessary, second column expands to fit window
self.grid_columnconfigure((0), weight=0)
self.grid_columnconfigure((1), weight=1)
# Creates function 'button_function' that outputs a line in the command prompt
def button_function():
print("Button Pressed")
# Image Path and Declarations
image_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "assets")
self.logo_image = customtkinter.CTkImage(Image.open(os.path.join(image_path, "logo.png")), size=(628,20))
# Title Frame and Image Render
self.app_title = customtkinter.CTkLabel(self, text="", image=self.logo_image)
self.app_title.grid(row=0, column=0, padx=10, pady=10, columnspan=3)
# Selection Frame for Metals
self.material_frame = customtkinter.CTkFrame(self, fg_color="grey13", width=1, height=1)
self.material_frame.grid(row=1, column=0, sticky="nw")
# Selection Frame Label
self.material_frame_label = customtkinter.CTkLabel(self.material_frame, text="Metal Selection", compound="top", font=customtkinter.CTkFont(size=23, weight="bold"))
self.material_frame_label.grid(row=0, column=0, padx=(0,0), pady=0, sticky="ns")
# Selection Frame underscore (tkinter canvas widget and white rectrangle)
self.material_frame_placeholder_text = customtkinter.CTkLabel(self.material_frame, text=" 15 25 35 %", compound="top", font=customtkinter.CTkFont(family="Segoe UI Semibold", size=14, weight="normal"))
self.material_frame_placeholder_text.grid(row=1, column=0, padx=(3,0), pady=0, sticky="ns")
# Selection Frame for metal selection
self.metal_selection = Metal(self.material_frame)
self.metal_selection.grid(row=2, column=0, padx=0, pady=(0,20), sticky="n")
self.alloy_info = Alloy(self, width= 150, bg_color = "transparent")
self.alloy_info.grid(row=1, column=1, sticky="nw")
# Keeps window open
if __name__ == "__main__":
app = App()
app.after(10, print("hi"))
app.mainloop()
There are two problems with your code.
The first is that after
will only schedule something to run once, after a given time period. That is what it is designed to do.
The second is that after
requires a callable - a reference to a function. In your case you're immediately calling print("hi")
, and passing the result to after
.
If you want something to be done on an interval, you need to write a function that will call after
with itself as an argument, so that each time it's called it will schedule a future invocation.
def print_hi(app):
print("hi")
app.after(10, print_hi, app)
# schedule the first call, and pass `app` as an argument to the function
app.after(10, print_hi, app)