Python Forum
Trouble with Tkinter labels
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Trouble with Tkinter labels
#1
So I am new at Tkinter

So I'm trying to create what I thought was a simple program
I made this program in a standard Python script
I thought all I had to do was convert certain things over to Tkinter
but I'm finding out that's not true

This simple script downloads my programs from my archive
to a Pacific folder and then install it, the download part works perfectly

But when it comes time to install them
I am using os.system when this is activated the labels
will not display their contents it's almost like it bypasses the labels

I have used time.sleep() just before os.system and that didn't solve my problem either
if I remove os.system and replace it with print() both labels will work
so I don't know what else to try I am opened up for suggestions


        # ---- download the program ----
        down_inst = Label(root, text='Downloading ' + ck_folder + ' from archive', font=('Arial', 15))
        down_inst.place(x=100, y=420)
        root.after(5000, down_inst.destroy)  # 1000=1 second
        shutil.copyfile(dw_source_path + dw_file_name, td_dest_path + dw_file_name)

        # ---- installing program ----
        down_inst = Label(root, text='And Installing ' + ck_folder, font=('Arial', 15))
        down_inst.place(x=150, y=450)
        root.after(5000, down_inst.destroy)  # 1000=1 second
        os.system(td_dest_path + dw_file_name + parameters)


parameters = r' /S /norestart'
Reply
#2
Are you trying to get some kind of effect like this?

import tkinter as tk
from random import choice

textlist = ['text', 'more text', 'how about this?', 'still more text', 'some text']

def destroy_label(root, label):
    label.destroy()
    root.after(3000, lambda: create_label(root, label))
    

def create_label(root, label):
    label = tk.Label(root, text=choice(textlist), font=(None, 25, 'normal'))
    label.pack(fill='x')
    root.after(3000, lambda: destroy_label(root, label))
    

root = tk.Tk()
label = tk.Label(root,text='Some text', font=(None, 25, 'normal'))
label.pack(fill='x')
root.after(3000, lambda: destroy_label(root, label))
root.mainloop()
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags


Reply
#3
(Sep-10-2023, 12:31 AM)menator01 Wrote: Are you trying to get some kind of effect like this?

import tkinter as tk
from random import choice

textlist = ['text', 'more text', 'how about this?', 'still more text', 'some text']

def destroy_label(root, label):
    label.destroy()
    root.after(3000, lambda: create_label(root, label))
    

def create_label(root, label):
    label = tk.Label(root, text=choice(textlist), font=(None, 25, 'normal'))
    label.pack(fill='x')
    root.after(3000, lambda: destroy_label(root, label))
    

root = tk.Tk()
label = tk.Label(root,text='Some text', font=(None, 25, 'normal'))
label.pack(fill='x')
root.after(3000, lambda: destroy_label(root, label))
root.mainloop()


Thank you for replying

Sorry if I haven't explain myself very well
I am still considered a new programmer

I can't give you the whole thing so maybe this will help
Basically this script looks for a program on the computer
it will ask you if you want to install it if it doesn't exist
this script also contains a sub script this is the sub script below
where I can add items to the list as you see below
I am using ccleaner as an example

import os

# items in listbox
my_listbox.insert(0, 'install ccleaner')
my_listbox.insert(1, 'install empty for now')
my_listbox.insert(2, 'install empty for now')
my_listbox.insert(3, 'install empty for now')
my_listbox.insert(4, '333install empty for now')


def path_check_locations():
    label = Label(root, text='looking for: ' + ck_folder, font=('Arial', 15))
    label.place(x=150, y=420)
    root.after(5000, label.destroy)  # 1000=1 second

    if os.path.isdir(os.path.join(ck_root, ck_folder)):
        label = Label(root, text='exists in root : ', font=('Arial', 15))
        label.place(x=150, y=450)
        root.after(5000, label.destroy)  # 1000=1 second

    elif os.path.isdir(os.path.join(ck_dir1, ck_folder)):
        label = Label(root, text='exists in Program Files', font=('Arial', 15))
        label.place(x=150, y=450)
        root.after(5000, label.destroy)  # 1000=1 second

    elif os.path.isdir(os.path.join(ck_dir2, ck_folder)):
        label = Label(root, text='exists in Program Files (x86)', font=('Arial', 15))
        label.place(x=150, y=450)
        root.after(5000, label.destroy)  # 1000=1 second

    else:
        label = Label(root, text=ck_folder + ' Doesnt exist', font=('Arial', 15))
        label.place(x=150, y=450)
        root.after(5000, label.destroy)  # 1000=1 second

    root.bell()
    if messagebox.askyesno(title='program installation', message='Do you want to install ' + ck_folder):
        # ---- exists or not ----
        if not os.path.exists(td_dest_path):
            # ---- if not created ----
            os.makedirs(td_dest_path)

        # ---- download the program ----
        down_inst = Label(root, text='Downloading ' + ck_folder + ' from archive', font=('Arial', 15))
        down_inst.place(x=100, y=420)
        root.after(5000, down_inst.destroy)  # 1000=1 second
        shutil.copyfile(dw_source_path + dw_file_name, td_dest_path + dw_file_name)

        # ---- installing program ----
        down_inst = Label(root, text='And Installing ' + ck_folder, font=('Arial', 15))
        down_inst.place(x=150, y=450)
        root.after(5000, down_inst.destroy)  # 1000=1 second
        print('Hi')
        os.system(td_dest_path + dw_file_name + parameters)

    else:
        label = Label(root, text="As you wish I won't install " + ck_folder, font=('Arial', 15))
        label.place(x=100, y=450)
        root.after(5000, label.destroy)  # 1000=1 second


"""
[global-variable-undefined]
look in your Documentation about this
this will help with variables so that this doesn't happen [global-variable-undefined]
"""
# ----[global-variable-undefined]----
ck_folder = 'Hi Ray'  # the name here is unimportant
dw_file_name = 'Hi Ray'  # the name here is unimportant

# ----path check locations----
ck_root = r'C:\\'
ck_dir1 = r'\Program Files'
ck_dir2 = r'\Program Files (x86)'

# ----Download program,  Where the programs are kept----
dw_source_path = r'\\source location'
# ----installs the program----
parameters = r' /wait/S /norestart'  # space after r' needs to be there to work correctly


def sel_0():
    global ck_folder  # [global-variable-undefined]
    ck_folder = 'ccleaner'  # name of folder to look for
    global dw_file_name
    dw_file_name = r'\ccsetup551.exe'  # name of executable file

    path_check_locations()


def sel_1():
    # this label is towards the bottom of the window

    label = Label(root, text='looking for: ' + ck_folder, font=('Arial', 15))
    label.place(x=150, y=420)
    root.after(5000, label.destroy)  # 1000=1 second


def sel_2():
    # this label is towards the bottom of the window

    label = Label(root, text="Test is this 2", font=('Arial', 15))
    label.place(x=150, y=450)
    root.after(5000, label.destroy)  # 1000=1 second
    print('Test is this 2')


def sel_3():
    # this label is towards the bottom of the window

    label = Label(root, text="Test is this 3", font=('Arial', 15))
    label.place(x=150, y=450)
    root.after(5000, label.destroy)  # 1000=1 second
    print('Test is this 3')


def sel_4():
    # this label is towards the bottom of the window

    label = Label(root, text="Test is this 4", font=('Arial', 15))
    label.place(x=150, y=450)
    root.after(5000, label.destroy)  # 1000=1 second
    print('Test is this 4')


def select():
    # this is linked to the Menu_Tkinter.py
    # this calls the functions from above

    selection = my_listbox.curselection()
    if selection == (0,):
        sel_0()
    elif selection == (1,):
        sel_1()
    elif selection == (2,):
        sel_2()
    elif selection == (3,):
        sel_3()
    elif selection == (4,):
        sel_4()
Reply
#4
This does not draw the label.
        down_inst = Label(root, text='And Installing ' + ck_folder, font=('Arial', 15))
        down_inst.place(x=150, y=450)
This draws the label
root.mainloop()
You can see this if you run the program below. We force the window to update after making the first label, but the second label waits for mainloop() to update the root window.
import tkinter as tk
from time import sleep

root = tk.Tk()
tk.Label(root, text="How many labels", font=(None, 64)).pack()
root.update()
tk.Label(root, text="do you see?", font=(None, 64)).pack()
sleep(5)
root.mainloop()
And before you start adding update() commands all over the place, stop and think about what you are using tkinter for. If you block mainloop() from running the window stops responding to user actions (button clicks, typing) and the window stops updating, even if you make request to change the windows appearance. Do you want your window to go dead while the program is busy. Your users will not be impressed.

Are you blocking mainloop() from running? Is there something that takes a long time to run and this prevents your window from updating? If so, that code should be run in a separate thread.

This is not the correct way to modify a label.
        down_inst = Label(root, text='Downloading ' + ck_folder + ' from archive', font=('Arial', 15))
        down_inst.place(x=100, y=420)
        root.after(5000, down_inst.destroy)  # 1000=1 second
        shutil.copyfile(dw_source_path + dw_file_name, td_dest_path + dw_file_name)
 
        # ---- installing program ----
        down_inst = Label(root, text='And Installing ' + ck_folder, font=('Arial', 15))
        down_inst.place(x=150, y=450)
You should hardly ever use destroy(). Make the window and labels at the start of run. To display a different message, change the label text. The example below uses a tk.StringVar to change the label text.
import tkinter as tk
from time import sleep


class Window(tk.Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.message = tk.StringVar()
        label = tk.Label(self, textvariable=self.message, width=60, font=(None, 32))
        label.pack(padx=10, pady=10)

    def display_message(self, message_list, delay=10):
        if message_list:
            self.message.set(message_list[0])
            self.after(delay * 1000, self.display_message, message_list[1:], delay)
        else:
            self.message.set("")


window = Window()
window.display_message(
    (
        "Twas the night before Christmas, when all through the house",
        "Not a creature was stirring, not even a mouse",
        "The stockings were hung by the chimney with care",
        "In hopes that St. Nicholas soon would be there",
    ),
    delay=3,
)
window.mainloop()
You should not use place() to set the location of a widget. Use pack() or grid(). What if you have a user that selected a larger system font? Your labels will resize, but are they correctly spaced? Using pack() or grid() lets tkinter adjust the window to fit the contents. It also lets you easily make resizable windows.
Reply
#5
You must really like typing. As far as I am concerned, this is duplicate code, and duplicate code should be avoided.
    if os.path.isdir(os.path.join(ck_root, ck_folder)):
        label = Label(root, text='exists in root : ', font=('Arial', 15))
        label.place(x=150, y=450)
        root.after(5000, label.destroy)  # 1000=1 second
 
    elif os.path.isdir(os.path.join(ck_dir1, ck_folder)):
        label = Label(root, text='exists in Program Files', font=('Arial', 15))
        label.place(x=150, y=450)
        root.after(5000, label.destroy)  # 1000=1 second
 
    elif os.path.isdir(os.path.join(ck_dir2, ck_folder)):
        label = Label(root, text='exists in Program Files (x86)', font=('Arial', 15))
        label.place(x=150, y=450)
        root.after(5000, label.destroy)  # 1000=1 second
 
    else:
        label = Label(root, text=ck_folder + ' Doesnt exist', font=('Arial', 15))
        label.place(x=150, y=450)
        root.after(5000, label.destroy)  # 1000=1 second
 
Same thing here. Nearly duplicate code.
def sel_0():
    global ck_folder  # [global-variable-undefined]
    ck_folder = 'ccleaner'  # name of folder to look for
    global dw_file_name
    dw_file_name = r'\ccsetup551.exe'  # name of executable file
 
    path_check_locations()
 
 
def sel_1():
    # this label is towards the bottom of the window
 
    label = Label(root, text='looking for: ' + ck_folder, font=('Arial', 15))
    label.place(x=150, y=420)
    root.after(5000, label.destroy)  # 1000=1 second
 
 
def sel_2():
    # this label is towards the bottom of the window
 
    label = Label(root, text="Test is this 2", font=('Arial', 15))
    label.place(x=150, y=450)
    root.after(5000, label.destroy)  # 1000=1 second
    print('Test is this 2')
 
 
def sel_3():
    # this label is towards the bottom of the window
 
    label = Label(root, text="Test is this 3", font=('Arial', 15))
    label.place(x=150, y=450)
    root.after(5000, label.destroy)  # 1000=1 second
    print('Test is this 3')
 
 
def sel_4():
    # this label is towards the bottom of the window
 
    label = Label(root, text="Test is this 4", font=('Arial', 15))
    label.place(x=150, y=450)
    root.after(5000, label.destroy)  # 1000=1 second
    print('Test is this 4')
 
 
def select():
    # this is linked to the Menu_Tkinter.py
    # this calls the functions from above
 
    selection = my_listbox.curselection()
    if selection == (0,):
        sel_0()
    elif selection == (1,):
        sel_1()
    elif selection == (2,):
        sel_2()
    elif selection == (3,):
        sel_3()
    elif selection == (4,):
        sel_4()
When I see a program where the same instructions appear over and over again, I see if I can separate the code that is the same each time from the code that is different. In this example, the methods that are performed when you select a program are the same for each program. The only thing that changes is the folder where the program files might reside. The code that executes the programs is likely very similar. Code that is the same, regardless of the selection, and code that is specific to each program.

In the code below I put the program specific stuff, dictionaries and commands, in a dictionary. This lets me use the same code to install any program.
import tkinter as tk
from tkinter import ttk
from pathlib import Path
import shutil


# Where I look for programs
program_paths = {
    "root": Path("c:/"),
    "Program Files": Path("c:/Program Files"),
    "Program Files (x86)": Path("c:/Program Files (x86)"),
}

# Programs I can install
programs = {
    "ccleaner": ["folder name", "print('Replace with command to install ccleaner')"],
    "dirtier": ["folder name", "print('Replace with command to install dirtier')"],
}


class Window(tk.Tk):
    def __init__(self):
        super().__init__()

        label = tk.Label(self, text="Select Program")
        self.program = tk.StringVar()
        selector = ttk.Combobox(self, textvariable=self.program, values=list(programs))
        selector.bind("<<ComboboxSelected>>", self.select_program)
        self.message = tk.StringVar(self, "No program Selected")
        message = tk.Label(self, textvariable=self.message, width=60)
        self.button = tk.Button(
            self,
            text="Install Program",
            command=self.install_program,
            state=tk.DISABLED,
        )

        label.grid(row=0, column=0, padx=10, pady=10, sticky="news")
        selector.grid(row=0, column=1, padx=(0, 10), pady=10, sticky="news")
        message.grid(
            row=1, column=0, columnspan=2, padx=10, pady=(0, 10), sticky="news"
        )
        self.button.grid(
            row=2, column=0, columnspan=2, padx=10, pady=(0, 10), sticky="news"
        )

    def set_message(self, message):
        self.message.set(message)
        self.update()

    def select_program(self, *_):
        program = self.program.get()
        for folder, path in program_paths.items():
            if (path / folder).is_dir():
                self.message.set(f"{program} found in {str(path)}.")
                self.button["state"] = tk.DISABLED
        else:
            self.message.set(f"{program} not found.")
            self.button["state"] = tk.NORMAL

    def install_program(self):
        program = self.program.get()
        folder, command = programs[program]
        # If command can take long time, can run this code in another thread.
        (Path(td_dest_path) / folder).mkdir(parents=True, exist_ok=True)
        self.set_message(f"Installing {program}")
        eval(command)  # <- This executes the python command from the programs directory.
        self.set_message("")


Window().mainloop()
To add another program to my program, all I have to do is add an entry to the programs dictionary.
Reply
#6
(Sep-10-2023, 03:46 PM)deanhystad Wrote: This does not draw the label.
        down_inst = Label(root, text='And Installing ' + ck_folder, font=('Arial', 15))
        down_inst.place(x=150, y=450)
This draws the label
root.mainloop()
You can see this if you run the program below. We force the window to update after making the first label, but the second label waits for mainloop() to update the root window.
import tkinter as tk
from time import sleep

root = tk.Tk()
tk.Label(root, text="How many labels", font=(None, 64)).pack()
root.update()
tk.Label(root, text="do you see?", font=(None, 64)).pack()
sleep(5)
root.mainloop()
And before you start adding update() commands all over the place, stop and think about what you are using tkinter for. If you block mainloop() from running the window stops responding to user actions (button clicks, typing) and the window stops updating, even if you make request to change the windows appearance. Do you want your window to go dead while the program is busy. Your users will not be impressed.

Are you blocking mainloop() from running? Is there something that takes a long time to run and this prevents your window from updating? If so, that code should be run in a separate thread.

This is not the correct way to modify a label.
        down_inst = Label(root, text='Downloading ' + ck_folder + ' from archive', font=('Arial', 15))
        down_inst.place(x=100, y=420)
        root.after(5000, down_inst.destroy)  # 1000=1 second
        shutil.copyfile(dw_source_path + dw_file_name, td_dest_path + dw_file_name)
 
        # ---- installing program ----
        down_inst = Label(root, text='And Installing ' + ck_folder, font=('Arial', 15))
        down_inst.place(x=150, y=450)
You should hardly ever use destroy(). Make the window and labels at the start of run. To display a different message, change the label text. The example below uses a tk.StringVar to change the label text.
import tkinter as tk
from time import sleep


class Window(tk.Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.message = tk.StringVar()
        label = tk.Label(self, textvariable=self.message, width=60, font=(None, 32))
        label.pack(padx=10, pady=10)

    def display_message(self, message_list, delay=10):
        if message_list:
            self.message.set(message_list[0])
            self.after(delay * 1000, self.display_message, message_list[1:], delay)
        else:
            self.message.set("")


window = Window()
window.display_message(
    (
        "Twas the night before Christmas, when all through the house",
        "Not a creature was stirring, not even a mouse",
        "The stockings were hung by the chimney with care",
        "In hopes that St. Nicholas soon would be there",
    ),
    delay=3,
)
window.mainloop()
You should not use place() to set the location of a widget. Use pack() or grid(). What if you have a user that selected a larger system font? Your labels will resize, but are they correctly spaced? Using pack() or grid() lets tkinter adjust the window to fit the contents. It also lets you easily make resizable windows.

Wow thank you very much most of these I got from YouTube I assume they knew what they were talking about
but it just goes to show can't believe everything you see
thanks a lot for looking at my program I will look at what you have and compare with what I've learned and make the necessary adjustments
thanks again
Reply
#7
Wading through the sea of crap that is python tutorials and videos to find the few that are good could be a full time job. It doesn't help that the same "lessons" are regurgitated by anyone who likes python and has a blog. Even content from trustworthy sources is often out-of-date or just barely scratches the surface.

Trust nothing. Verifiy everything. Including this. Always use multiple sources.
menator01 likes this post
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [Tkinter] Trouble changing Font within tkinter frame title AnotherSam 1 4,154 Sep-30-2021, 05:57 PM
Last Post: menator01
  [Tkinter] modify the html table to include data from tkinter labels rwahdan 0 1,626 Jun-20-2021, 10:33 AM
Last Post: rwahdan
  Tkinter having problems with packing labels? wallgraffiti 0 1,549 Aug-02-2020, 09:26 AM
Last Post: wallgraffiti
  Creating and destroying dynamic labels in Tkinter MarcusRoberts 1 4,323 May-02-2020, 06:49 PM
Last Post: Yoriz
  Spacing Between two labels are very far and Top label is not in Center using Tkinter barry76 2 7,103 Jul-30-2019, 10:49 AM
Last Post: wuf

Forum Jump:

User Panel Messages

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