I have created a couple of frames and now want to put some buttons and labels on them, but from the first button that I created, I am facing a problem. Nothing is showing in the tkinter window.
from tkinter import *
class STproject():
def __init__(self,app): #1
self.stframe=Frame(app,background='blue',height=90,width=350)
self.stframe.grid(row=0,column=0)
self.ndframe=Frame(app,background='red',height=90,width=350)
self.ndframe.grid(row=1,column=0)
self.rdframe=Frame(app,background='yellow',height=90,width=350)
self.rdframe.grid(row=2,column=0)
self.ndstframe=Frame(self.ndframe,background='black',width=145)
self.ndstframe.grid(row=0,column=0,rowspan=3,sticky='ns')
self.ndndframe=Frame(self.ndframe,background='white',height=45,width=205)
self.ndndframe.grid(row=1,column=1)
self.ndrdframe=Frame(self.ndframe,background='green',height=45,width=205)
self.ndrdframe.grid(row=2,column=1)
def buttons(self):
self.importbutton=Button(self.stframe,text='Import',width=4,height=2)
self.importbutton.grid(row=0,column=0)
root=Tk()
root.title('SteelBox Inc. Calculator')
application=STproject(root) #2
root.mainloop() #3
You have put the creating of the button in a separate function, but you never call it.
Add self.buttons() at the end of the __init__ and the button will appear.
Related
this is the first question I am posting here. I recently created a window in Tkinter that contains a frame. After clicking a button a label containing text should appear inside the frame. When clicking the button again - the label should disappear. It works fine until I click the button for a third time to call the label inside the frame again.
Here is the code:
from tkinter import *
root=Tk()
root.geometry("500x500+100+100")
root.title("Switch label")
root.resizable(False,False)
is_off=True
def label_disappear():
global label
global is_off
label.destroy()
button.config(text="Add",command=label_appear)
is_off=True
def label_appear():
global label
global is_off
if is_off:
label.place(x=20,y=20)
button.config(text="Remove",command=label_disappear)
is_off=False
else:
label_disappear()
frame=Frame(root,bg="light green",width=460,height=200)
frame.place(x=20,y=20)
label=Label(frame,text="This is label",bg="light green")
button=Button(root,text="Add",command=label_appear)
button.place(relx=0.5,y=250,anchor="center")
root.mainloop()
and here is the error that PyCharm throws:
Image of the error
How can I change it so that it works as a real switch and not only as one time on/off button?
Thank you in advance!
It is because you have destroyed the label inside label_disappear(). If you want the label to be shown again, replace label.destroy() by label.place_forget() inside label_disappear():
def label_disappear():
global label
global is_off
label.place_forget() # don't destroy the label, just make it invisible
button.config(text="Add",command=label_appear)
is_off=True
What i am trying to do: I am trying to build a GUI using tkinter in Python (i am using version 3.7.7 on Windows) with a main window that has a Listbox and a second window that contains a Combobox.
In the Listbox there are different files that can be opened. When clicking on each entry some additional information are displayed in the main window (That part is not in my shorter example code below). So what i did was binding the Listbox to a function that loads and displays the information (function_1 in the code below) with the <<ListboxSelect>> event.
The second window can be opened with a button and should edit the selected file. In the Combobox in the second window are different options that change other elements of the second window depending on whats selected. Thats why i bind the <<ComboboxSelected>> event to a different function (function_2 in the code below).
My problem with this is: When i select a value in the Combobox of the second window, the first function that is binded to the Listbox of the first window is executed just after the correct function for the Combobox. This only happens the first time a value for the Combobox is selected, for each time the second window is created. Also when looking at the selected value of the Listbox it returns the selected value of the Combobox.
Edit: I just noticed this problem only happens when i previously selected an item in the Listbox. So like i said below it might have something to do that the Listbox is still active or something like that.
My code and an example:
import tkinter as tk
from tkinter import ttk
class MainGUI:
def __init__(self):
self.root = tk.Tk()
items = ['Test 1', 'Test 2', 'Test 3']
self.item_box = tk.Listbox(self.root)
self.item_box.insert('end', *items)
self.item_box.bind('<<ListboxSelect>>', self.function_1)
self.item_box.pack()
tk.Button(self.root, text='Open second window',
command=self.open_window).pack()
self.root.mainloop()
def function_1(self, event):
print('MainGUI function:', event)
print('Text in Listbox:', self.item_box.selection_get())
def open_window(self):
SecondGUI()
class SecondGUI:
def __init__(self):
self.window = tk.Toplevel()
self.window.grab_set()
items = ['A', 'B', 'C']
self.dropdown = ttk.Combobox(self.window, values=items)
self.dropdown.current(0)
self.dropdown.pack()
self.dropdown.bind('<<ComboboxSelected>>', self.function_2)
def function_2(self, event):
print('SecondGUI function:', event)
MainGUI()
Image of the GUI before and after the option B is clicked
The output after selecting Test 1, opening the second window with the button and selecting B looks like this:
MainGUI function: <VirtualEvent event x=0 y=0>
Text in Listbox: Test 1
SecondGUI function: <VirtualEvent event x=0 y=0>
MainGUI function: <VirtualEvent event x=0 y=0>
Text in Listbox: B
My guess: If i had to guess what the problem is, i would say the Combobox maybe had some sort of Listbox in it that sends the event, but as i wasn't able to find more about when and how these events are sent, i couldn't really find anything about it (Edit: Less likely). When looking at the picture, you can see that the entry in the first window is still selected until the entry in the second window is clicked, so my second guess would be that the Listbox is still active and takes the new selected value when it is clicked or something like that (Edit: more likely).
My question: Why does the first function execute when i use a different widget in a different window, how can i fix this, or are there any better way to do this in the first place?
TL;DR: A Listbox recieves an event when a Combobox is selected in a different window. Why?
Thanks in advance!
It may be due to that exportselection=False is not set for both the Listbox and Combobox. So when an item in the Combobox is selected, it will clear the selection of Listbox which triggers the <<ListboxSelect>> event.
Also you have used wrong function, self.item_box.selection_get(), to get the current selected item of Listbox. self.item_box.get(self.item_box.curselection()) should be used instead.
Below changes should fix the issue:
class MainGUI:
def __init__(self):
...
self.item_box = tk.Listbox(self.root, exportselection=False)
...
def function_1(self, event):
print('MainGUI function:', event)
print('Text in Listbox:', self.item_box.get(self.item_box.curselection()))
...
class SecondGUI:
def __init__(self):
...
self.dropdown = ttk.Combobox(self.window, values=items, exportselection=False)
...
...
I'm making an app in tkinter which uses the ttk.Scale widget to show the process of an mp3 song.
I have a function that I want to add buttons with the names of which (the buttons) should be relied on filenames. Therefore I've made this example:
from tkinter import Tk, Button
from tkinter.filedialog import askopenfilenames
from tkinter.ttk import Scale
from threading import Timer
root = Tk()
slider = Scale(root, from_=0, to=100, orient='horizontal')
slider.pack()
# slider is continuously set to a bigger number so that it keeps going
def update_slider(num):
slider.set(num)
num += 1
root.after(50, update_slider, num)
update_slider(num=0)
# this function creates buttons based on the files opened
def add_buttons():
# the 'X' button of this particular window slows down execution of update_slider function
files = askopenfilenames(title='Add Buttons')
for i in list(files):
Button(root, text=i).pack()
button = Button(root, text='Browse', command=lambda: Timer(0.1, add_buttons).start())
button.pack()
root.mainloop()
The problem I'm facing is that when I open the askopenfilenames dialog box or when I press its 'X' button, my slider which is running continuously in the background gets stuck, and as a result doesn't show the process correctly.
Here is a picture where I hold down the 'X' button and the ttk.Scale stops moving:
I've tried using threading to run the add_buttons function but the behavior of the program remains the same.
Can I edit the askopenfilenames dialog box with something similar like overrideredirect(True) so that I can make my own title bar and 'X' button and the events generated not to slow down my Scale?
Replying to:
I cannot reproduce the issue in Linux, the scale keeps moving no matter what I do with the filedialog window. So this may be an OS specific issue.
I'm aware that this problem doesn't appear on Linux. I faced the same problem with the root's close button and other Toplevels' close button, but I fixed it by replacing the title bar using overrideredirect(True).
Is there anything similar I can do with this askopenfilenames window?
The code is simple. In tkinter I create a button which opens a new window. The difference in the pictures below might be hard to see but if you look closely you can see that in the first picture the root window is selected even though it's behind the new opened window.
In my actual program I use keybindings to operate the second window so it would be nice to instantly select this window so you don't have to click on it to use keys to operate it. How can I select the Toplevel window as soon as it opens?
from tkinter import *
def open_new_window():
top = Toplevel(root)
root = Tk()
Button(root, text="open new window", command=open_new_window).pack()
root.mainloop()
Possible duplicate of this question
Like acw1668 said, simply add top.focus() at the end of your function open_new_window
Your new open_new_window function will look like this:
def open_new_window():
top = Toplevel(root)
top.focus()
I started to learn Python and I got a problem that is not discussed in any of the tutorials I've found.
Basically when the program got more complicated I've lost the ability to control where the new elements are appearing. It's difficult to explain it for me since English is not my native language so i made a mock-up program that shows what is wrong with my main program.
import Tkinter as tk
import ttk as ttk
clutter=['1PLACEHOLDER', '2PLACEHOLDER', '3PLACEHOLDER', 'PICK ME']
class GRAPHIC_INTERFACE(tk.Frame):
def __init__(self,*args):
tk.Frame.__init__(self, *args)
self.grid()
self.first_window()
def first_window(self):
self.button1=tk.Button(self, text="PLACEHOLDER")
self.button1.grid()
self.button2=tk.Button(self, text="CLICK ME", command=self.second_window)
self.button2.grid()
self.button3=tk.Button(self, text="PLACEHOLDER")
self.button3.grid()
#the additional button apears here
def second_window(self):
alpha=tk.Toplevel(self)
self.button4=tk.Button(alpha, text="PLACEHOLDER")
self.button4.grid()
self.button5=tk.Button(alpha, text="CLICK ME", command= self.third_window)
self.button5.grid()
def third_window(self):
beta=tk.Toplevel(self)
self.BOXXY=ttk.Combobox(beta, values= clutter, state='readonly')
self.BOXXY.bind("<<ComboboxSelected>>", self.misplaced_button) #after choosing the third option an aditional button is created
self.BOXXY.current(0)
self.BOXXY.grid()
self.button6=tk.Button(beta, text="PLACEHOLDER")
self.button6.grid()
#the additional button needs to appear here
def misplaced_button(self, *args):
Catie=self.BOXXY.get()
if Catie=='PICK ME':
self.button7=tk.Button(self, text="I am that problematic button")#this button needs to be in the third window
self.button7.grid()
else:
print "that was not the chosen one"
root=tk.Tk()
root.title("Mockup")
root.geometry("180x200")
app=GRAPHIC_INTERFACE(root)
root.mainloop()
At first I was thinking that i can control the placement of the widgets by giving them names (i.e alpha, beta) but apparently I was wrong.
If self.button7 is supposed to be in the third window, all you have to do is use the third window as the parent of the button.
You can accomplish this many ways: you can save the window as an attribute, you can pass the window in when calling the function, or you can compute the window based on which widow caught the event.
Here's a solution that puts the button in the toplevel that got the event:
def misplaced_button(self, event):
...
toplevel = event.widget.winfo_toplevel()
self.button7=tk.Button(toplevel,...)
...