I have 2 Listboxes next to each other and I try to create a checkbox for each entry of these Listboxes. Unfortunately, I do not manage to make the checkboxes and listbox elements have the same height/be on the same position, as you can see in the screenshot below.
Do you have any idea how i can modify it to have something similar to checkboxes in a list(which is not possible in Tkinter afaik)?
For my Listboxes, I use a customized version of this snippet:
https://stackoverflow.com/a/16056555/3429131
I hope I explained my problem in an understandable way.
Thanks for your help.
If it's not 100% necessary to have everything in a listbox then you could try and display the data using grid or pack which would make them line up properly, grid would probably be better.
Just declare it as something like:
master = Tk()
Model1 = Label(master, text="F45")
Part1 = Label(master, text="AUFN-BUCHSE")
Active1 = Checkbutton(master, variable=Var)
Model1.grid(row=0,column=0)
Part1.grid(row=0, column=1)
Active1.grid(row=0, column=2)
And if you wanted to repeat this you could pull the Model and Part sections out of a file and then create a for loop that creates a list containing the Labels.
You could then use a for loop to grid the labels, something like this:
for Counter1 in range(0, NumberOfRows)
Model[Counter1].grid(row=Counter1, column=0)
Part[Counter1].grid(row=Counter1, column=1)
Checkbutton.grid(row=Counter1, column=2)
Something along the lines of this, with a few tweaks, where Model[] would be something like [F45, F46, F47...] and Part[] would be [AUFN-BUCHSE, AUFN-BUCHSE-BOLZEN...]
Again you may have to tweak my code a little, not sure if it's spot on what you wanted but all of this depends on whether list boxes are completely necessary or not.
If you want to read up some more on gird method, check this out:
http://effbot.org/tkinterbook/grid.htm
Related
Hi I didn't really understand how furas made the below code work. Why didn't he get an error message about grid and pack on the same root when he added a box? In the addbox function he sets a frame to the root which is pack already and even uses the pack inside the function and then uses the grid.
Can someone please explain to me how this "magic" works?
a link to the his answer:
Creating new entry boxes with button Tkinter
from Tkinter import *
#------------------------------------
def addBox():
print "ADD"
frame = Frame(root)
frame.pack()
Label(frame, text='From').grid(row=0, column=0)
ent1 = Entry(frame)
ent1.grid(row=1, column=0)
Label(frame, text='To').grid(row=0, column=1)
ent2 = Entry(frame)
ent2.grid(row=1, column=1)
all_entries.append( (ent1, ent2) )
#------------------------------------
def showEntries():
for number, (ent1, ent2) in enumerate(all_entries):
print number, ent1.get(), ent2.get()
#------------------------------------
all_entries = []
root = Tk()
showButton = Button(root, text='Show all text', command=showEntries)
showButton.pack()
Thanks
There's no magic, it's just working as designed. The code uses pack in the root window, and uses grid inside a frame. Each widget that acts as a container for other widgets can use either grid or pack. You just can't use both grid and pack together for widgets that have the same master.
not really an answer but I think you will be helped by the link.
tkinter and it's layout is indeed a bit hard to understand.
I never understood how to deal with it until I stumbled over this presentation which explained the layout particulars in a way where I finally could get the hang of it.
Just putting it out there for others to find as well.
tkinter tutorial by beazley
I think you miss out on what pack and grid actually are. Consider such code:
import tkinter as tk
root = tk.Tk()
myFrame = tk.Frame(root)
myFrame.pack()
myButton1 = tk.Button(myFrame, text='This is button 1')
myButton2 = tk.Button(myFrame, text='This is button 2')
myButton1.grid(row=0, column=0)
myButton2.grid(row=1, column=0)
root.mainloop()
By creating root we create a new window. In this window we will put everything else. Then we create myFrame. Note, that the actual "thing" (in more adequate terms - widget) is created in line myFrame = tk.Frame(root). Note, that we have to specify where we are going to put this widget in brackets and we've written that it is going to be root - our main window. Blank frame probably isn't the best example since you can not see it being placed (not unless you use some more specifications at least), but still. We have created it, but not placed it in our user interface. The we use .pack() to place it. Now you refer to widgets as being used as packs or grids. That is not true though. Pack and grid are just the set of rules, on which the widgets are being placed inside some kind of window. Because of that, if you want to add something more to the root in our case, you will have to use .pack() again. Why? If you will give two sets of rules on how to place things on the screen for your computer - they will most likely conflict with each other. However, if we go one more level down and now want to place something inside our myFrame, we can again choose which set of rules to use. It is because it does not matter, where our frame is going to end up inside root, we now just want to specify where our Buttons 1 and 2 are going to end up inside the frame. Therefore we can again use .pack() or switch to .grid().
To conclude: .pack(), .grid() and .place() are sets of rules on how place widgets inside other widgets. In more general terms though these are rules on how place boxes in other boxes. One boxes in which we arrange other boxes can only have one set of rules.
I hope this example helps.
Tkinter Requirements
So I am relatively new to using tkinter and I am struggling with a very specific doubt here. I tried finding solutions to this but as much as I find it obvious, the solution to this doesn't seem to be easy to understand. So if you can see the image above, I am trying to create a GUI for a particular project which requires multi-layer (I am calling it 3D array based) widgets.
Let's say the variables used for this pointer system are i, j, and k.
I am creating individual layer widgets using for loop:
for n in range(i):
frame_x[i] = Frame(root).grid(row = 1, column = i)
entry_x[i] = Entry(frame_x[i]).grid(row = 2, column = i)
button_x[i] = Button(frame_x[i]).grid(row=3, column = i)
Please note this is not a functional code, I have tried to keep it to the point just to give an idea of the method I am using. (Let me know if you want a more detailed code block.)
Now coming to the problem. I am able to do the basic part of this. But the problem is that I want it to work dynamically.
Let's say if the user enters j = 4 first. 4 blocks will be created.
Later if he changes the value to j = 2 and the presses the button, ideally it should make the widgets at block j= 3 and 4 disappear. But I guess tkinter works on overlapping basis and doesn't change a grid element until something is specifically overlapped over it. How do I do that. I tried destroying the entire frame just after entering the for loop, but that doesn't work as for the first time no widget is created before destroying and python throws NameError saying I can't use a variable before assignment.
Anyways, please let me know how do I do this efficiently.
And also in general, if there is a better way to go about the whole thing. Please refer the image above and let me know if it doesn't make sense.
I am not very comfortable with classes in general. I prefer the inefficient way by only using functions to do everything I have to. So it would be great if you can share me a framework without using classes. But its okay if you use them. I know I should start working with classes at some point.
First off, I want to address this part of the question:
I guess tkinter works on overlapping basis and doesn't change a grid element until something is specifically overlapped over it.
I'm not entirely sure what you mean by that, but if it means what I think it means, it is a false statement. tkinter doesn't "work on an overlapping basis". If you destroy a widget, it is destroyed. It doesn't matter if it's overlapped or not.
Based on the tiny bit of code you posted, the main problem is that you aren't putting the entry and button in the frame. Because of that, they are not destroyed when you destroy the frame.
The reason you aren't putting the widgets into the frame is because of this line:
frame_x[i] = Frame(root).grid(row = 1, column = i)
In python, when you do x=y().z(), x has the value of z(). Thus, when you do frame_x[i] = Frame(...).grid(...), frame_x[i] has the value of .grid(...), and .grid(...) always returns None. Thus, frame_x[i] will be None.
When you next do entry_x[i] = Entry(frame_x[i]).grid(...), it's the same as doing entry_x[i] = Entry(None).grid(...). Because the master of the Entry is None, it becomes a child of the root window.
So, the first step is to separate the creation of the widget from the layout of the widget.
frame_x[i] = Frame(root)
frame_x[i].grid(row = 1, column = i)
Once you do that, the Entry and Button widgets will become a child of the frame, and you can remove widgets you don't want by destroying the frame (eg: frame_x[i].destroy()), since destroying a widget will also cause all children of the widget to be destroyed.
Once you have that in place, you can destroy unwanted widgets by simply calling .destroy() on the frame. For example, if you have previously created 10 groups and now need only 5, you can destroy the others and then remove them from the list like this:
# assume 'num' contains the number of frames that we want,
# and that it is smaller than the number of items in frames_x
for frame in frames_x[num:]:
frame.destroy()
frames_x = frames_x[:num]
Here is a complete working program to illustrate. Enter a number and click the button. It will create that many frame+entry+button combinations. Enter a new number that is larger or smaller and it will either add or remove widgets.
This would be easier if you used classes, but you specifically asked for a solution that doesn't use classes. In your real code you probably need to also save the entry widgets in an array so that you can reference them later, but this example is focuses on the creation of the widgets rather than writing your whole program for you.
import tkinter as tk
frames_x = [] def create_widgets():
global frames_x
num = int(num_widgets.get())
# if the number is less than the previous number of
# widgets, delete the widgets we no longer want
for frame in frames_x[num:]:
frame.destroy()
frames_x = frames_x[:num]
# if the number is greater than the previous number of
# widgets, create additional widgets
for i in range(len(frames_x), num):
# create new widget
frame = tk.Frame(root, bd=1, relief="raised")
entry = tk.Entry(frame)
button = tk.Button(frame, text="click me")
# pack entry and button in frame
button.pack(side="right")
entry.pack(side="left", fill="x", expand=True)
# grid the frame in the parent
frame.grid(row=i+1, column=0, columnspan=2)
# save the new frame in the array
frames_x.append(frame)
root = tk.Tk() num_widgets = tk.Entry(root) button = tk.Button(root, text="Create widgets", command=create_widgets)
button.grid(row=0, column=1) num_widgets.grid(row=0, column=0, sticky="ew")
root.mainloop()
Beginner programmer here, working on making a basic GUI as part of a tutorial I was following online, but none of them say how to get a Text box to update using the output of the other parts of your code.
I tried multiple other answers on the site, including one using StringVar's, which got me nowhere, another using a decorator, and the rest seemed way out of my depth.
Here's my code:
import tkinter as tk
import time
#Creating Root
root = tk.Tk()
#GUI TEMPLATE
frame =tk.Frame(root,
height = 100,
width = 400)
frame.pack()
v = StringVar()
colour = ["red","blue","green","white","yellow"]
labels = range(5)
#change number to change how many labels
for i in range(5):
l= tk.Label(root,
text = colour[i],
bg = colour[i])
l.place(x = 10 +i*70, y = 10, width=60, height=25)
T1 = tk.Text(root, height=2, width=40)
words = "Don't name your files after module names!"
T1.insert(tk.END, textvariable=v)
T1.place(x = 10, y= 40)
S = tk.Scrollbar(root)
S.config(command=T1.yview)
S.place(x = 340, y=40)
T1.config(yscrollcommand=S.set)
root.mainloop()
v.set("Something Else!")
Now, what it should output is a row of coloured labels, which works fine, and a text box with a scroll bar, which should instantly update to read 'Something Else!', which does not work fine.
Instead I get the following error:
NameError: name 'StringVar' is not defined
I know what this error means, it's just I've hit a wall when it comes to finding a solution that works for me, and doesn't need a doctorate to understand.
What I'm asking for is if someone can give me a solution that would work for this, and hopefully explain it!
Thanks in advance.
EDIT:
So after fixing the syntax error, and then finding out what I'm trying to do doesn't work, how would I go about this?
Could I use a label instead? Or is there another, better way?
Thanks again!
StringVar should accessed via tk:
v = tk.StringVar()
On another note, tk.Text.insert does not take a textvariable parameter, so the following won't work:
T1.insert(tk.END, textvariable=v)
# ^^^^^^^^^^^^??
From the docs:
Unlike for example the entry widget, text widgets don't support a
"textvariable" configuration option
Also see How can I connect a StringVar to a Text widget in Python/Tkinter? as to why this won't work.
I was experimenting with learning threading with Tkinter and have made something work to insert and update text in a Tkinter text box in Python3 which may be of help.
I found that by deleting the text I could then insert new text. Untill I deleted the existing text the instruction to insert text seamed to be ignored.
{ foo = input("Give me input: " )
self.T.delete("1.0", END) #Clear the text window so we can write.
self.T.insert(END,foo) #Write the new text.}
I'm sorry if this has been asked already, but I haven't been able to find it. I'm also just starting to learn programming so feedback is appreciated. :)
My end goal is to create an 8 by "x" grid of buttons that change their own color when pushed. I want to use this to make a grid I can upload to the POV toy I've built. This code creates a column of 8 buttons each with a callback passing itself as an argument. The idea being the callback function can do things to the button like change it's color, or delete it.
import Tkinter
def unpack(i):
buttons[i].pack_forget()
print i
top = Tkinter.Tk() buttons = [] for i in range(0, 8):
buttons.append(Tkinter.Button(top, text='Hello', command=lambda: unpack(i)))
for button in buttons:
button.pack()
top.mainloop()
When I do this I get a windows with column of 8 buttons, and when I click on one one gets deleted. When I click on a second nothing happens. In my command prompt I get the number 7 printed no matter which button I press. I suspect the problem is in the for loop that creates the buttons, but I have no idea how to fix it.
Thanks!
Pass the button object to the callback function instead of the index, because the index is change after the item deletion in the list.
import Tkinter
top = Tkinter.Tk()
for i in range(0, 8):
btn = Tkinter.Button(top, text='Hello')
btn['command'] = lambda b=btn: b.pack_forget()
btn.pack()
top.mainloop()
NOTE: To prevent late binding problem, I used default parameter in the above code.
How to create multi-lines in an entry widget in tkinter and use those inputs to create something?
For example, I want a textbox widget to come up and ask the user:
How many squares do you want? (ex: 4x4, 5x5)
What color do you want them?
And with the users input, I would like to create that many x-amount of squares in that specific height/width and specify the colors etc.
I am totally new to tkinter and I'm not really sure how to approach this.
I tried using this, but i'm not really sure how to add more lines and to use the values inputted.
import tkinter
from tkinter import *
class Squares:
root = Tk()
root.title('Random')
x = Label(text='How many squares? (ex: 4x4, 5x3)').pack(side=TOP,padx=10,pady=10)
Entry(root, width=10).pack(side=TOP,padx=10,pady=10)
Button(root, text='OK').pack(side= LEFT)
Button(root, text='CLOSE').pack(side= RIGHT)
You have a number of problems here.
I'm not sure what the Squares class is supposed to be doing, but it's basically not doing anything. You have a bunch of code that runs when you define the class, creating a few variables (which will end up as class attributes, shared by all instances of the class), and… that's it. Rather than try to figure out what you're intending here, I'm just going to scrap the class and make it all module-level code.
You never call root.mainloop(), so your program will just define a GUI and then never run it.
You don't bind your buttons to anything, so there's no way they can have any effect. You need to create some kind of function that does something, then pass it as the command argument, or .bind it later.
You don't store references for any of your controls, so there's no way to access them later. If you want to get the value out of the entry, you need some way to refer to it. (The exception is your x variable, but that's going to be None, because you're setting it to the result of calling pack on the Label, not the Label itself.)
Once you've done that, you just need to parse the value, which is pretty easy.
Putting it all together:
import tkinter
from tkinter import *
root = Tk()
root.title('Random')
Label(text='How many squares? (ex: 4x4, 5x3)').pack(side=TOP,padx=10,pady=10)
entry = Entry(root, width=10)
entry.pack(side=TOP,padx=10,pady=10)
def onok():
x, y = entry.get().split('x')
for row in range(int(y)):
for col in range(int(x)):
print((col, row))
Button(root, text='OK', command=onok).pack(side=LEFT)
Button(root, text='CLOSE').pack(side= RIGHT)
root.mainloop()
You just have to change that print to do something useful, like creating the squares.
If you don't need an outline for the text box, create_text would be the easiest thing, even though it doesn't have a wrap text feature(at least, in python 3 you can do this):
from tkinter import *
tk = Tk()
canvas = Canvas(tk, 1000, 1000)
canvas.pack()
canvas.create_text(200, 200, text="Example Text")
Try it!