tkinter grid manager behaviour - python

So i want to build an assistant off sorts which will do auto backs ups etc and instead of using .place i would like a proper grid to place widgets.
I cannot find a good example of the grid manager.
self.parent = tk.Frame(window, bg = BLACK)
username_label = ttk.Label(self.parent, text = "Username")
password_label = ttk.Label(self.parent, text = "Password")
self.parent.grid(column = 0, row = 0)
username_label.grid(column = 1, row = 1)
password_label.grid(column = 2, row = 2)
self.parent.grid_columnconfigure(0, weight = 1)
I want...
Button
Button
Label Entry Button
Label Entry Button
Button
I don't understand how i can position them like this as i want a blank space above the labels. so far grid has only let me place things next to each other.
Honestly, any websites or code examples would be greatly appreciated

So, if you want blank space above the label, you can either set pady as an argument to the grid method or simply put them in the corresponding row. Consider the following example:
import tkinter as tk
root=tk.Tk()
for i in range(6):
tk.Button(root,text='Button %d'%i).grid(row=i,column=1)
tk.Label(root,text='Label 0').grid(row=2,column=0,pady=20)
tk.Label(root,text='Label 1').grid(row=3,column=0)
root.mainloop()
Notice the effect of the pady argument. Also, if you only want a blank line above the Label, you can try to put a blank Label in the row above. E.g.:
import tkinter as tk
root=tk.Tk()
for i in range(6):
tk.Button(root,text='Button %d'%i).grid(row=i,column=1)
tk.Label(root,text='Label 0').grid(row=2,column=0,pady=20)
tk.Label(root,text='Label 1').grid(row=3,column=0)
tk.Label(root,text='').grid(row=6)
tk.Label(root,text='This is a Label with a blank row above').grid(row=7,columnspan=2)
root.mainloop()
You can refer to effbot for more information, which is the blog of tkinter's developer.

Related

Insert Image in a Line of other Images, Tkinter

I have a certain number of elements which I have saved as photos. These elements, and therefore the photos, all have different lengths and I want to keep them that way. (See pictures below)
The elements are all lined up in a certain order.
I would now like to use a dropdown menu (or something similar) to select the element and a second dropdown menu to determine the position where the image should be inserted. But the order of the other elements should not be changed by this.
Structure
This is the code, that i have by now:
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
tkFenster = Tk()
tkFenster.title('Test')
tkFenster.geometry('2700x1000')
frameElement = Frame(master=tkFenster, bg='#FBD975')
frameElement.place(x=5, y=340, width=2010, height=70)
imageElement1 = PhotoImage(file='E1.gif')
imageElement2 = PhotoImage(file='E2.gif')
imageElement3 = PhotoImage(file='E3.gif')
imageElement4 = PhotoImage(file='E4.gif')
labelElement = Label(master=frameElement, borderwidth=0, image=imageElement1)
labelElement.pack( side = LEFT)
labelElement2 = Label(master=frameElement, borderwidth=0, image=imageElement2)
labelElement2.pack( side = LEFT)
labelElement3 = Label(master=frameElement, borderwidth=0, image=imageElement4)
labelElement3.pack( side = LEFT)
labelElement4 = Label(master=frameElement, borderwidth=0, image=imageElement3)
labelElement4.pack( side = LEFT)
labelElement5 = Label(master=frameElement, borderwidth=0, image=imageElement4)
labelElement5.pack( side = LEFT)
labelElement6 = Label(master=frameElement, borderwidth=0, image=imageElement2)
labelElement6.pack( side = LEFT)
tkFenster.mainloop()
Repositioning labels in tkinter is relatively easy since most of the work is performed by tkinter.
In order to control label positions it is better to use the grid manager.
This method uses point and click as the easiest control.
Step 1:
Create a tk.Label and put an image into it:
label = tk.Label(labelFrame, image = a, anchor = tk.NW)
label.grid(row = 0, column = c)
Create a binding for each label:
label.bind('<ButtonPress-1>', swapImage)
Do this for all tk.Labels with images.
Step 2:
Images can now be selected via a single mouse click on label.
Since you need two images to swap, 'swapImage' must accumulate both label references before any action can take place.
Function swapImage must:
Find the label reference via label = event.widget
Store label reference in a list
Once this has been done for BOTH labels, extract their grid data with '.grid_info()'.
This will return a dictionary that contains all grid management data.
Now with both label grids available simply swap them.
Here is one example:
def swapImage(event):
labelB = event.widget
if items:
labelA = items[0]
ag = labelA.grid_info()
bg = labelB.grid_info()
labelA.grid(**bg)
labelB.grid(**ag)
items.clear()
else:
items.append(labelB)
NOTE: I've used a list called 'items' to accumulate user label selections.
To add more label images just repeat Step 1.

How do I make a LabelFrame's frame not visible? (Tkinter)

My code is the following:
import tkinter as tk
from tkinter import ttk
window = tk.Tk()
window.title('None')
label = ttk.LabelFrame(window, text = 'What I want to delete')
label.grid(column = 0, row = 0, padx = 5, pady = 5)
text = ttk.Label(label, text = 'Hello World')
text.grid(column = 0, row = 0)
window.mainloop()
with frame
Now what surprises me is that when I do the following changes:
import tkinter as tk
from tkinter import ttk
window = tk.Tk()
window.title('None')
label = ttk.LabelFrame(window, text = 'What I want to delete').grid(column = 0, row = 0, padx = 5, pady=5)
text = ttk.Label(label, text = 'Hello World').grid(column = 0, row = 0)
window.mainloop()
The label's frame does not appear. Only the text. As shown below:
without frame
Which means that the LabelFrame is existent, but not shown because there's no error. I think.
In summary, that's the way I "solved it". So, my question is, Is there a fuction that makes It possible not to show the frame in a LabelFrame?
ttk.LabelFrames are only visible if there is something inside it or if they have a fixed size. In the fisrt example you gave the ttl.Label widget with text='Hello Word' is clearly inside the LabelFrame since you passed it as its parent. But in the second example it's not. You may think it is because you also defined label as the ttk.Label parent but if you do print(label) you will see it will print None and, in tkinter, if you pass None as a widget master it will understand that the master is the root Tk() widget.
So, why this happens? The difference between the two examples is that in the first label=ttk.LabelFrame() which is a LabelFrame object (an instance of the LabelFrame class), while in the second label=ttk.LabelFrame().grid() which is the output of the grid method, and since the grid method does not return anything label is equal to None. In conclusion what you are doing is putting the LabelFrame with anything inside and then the second Label, both in the same position of the master window and this is why you can't see the LabelFrame.
Ok, then how to make the LabelFrame invisible? The best option is not using ttk.LabelFrame but tk.LabelFrame because now you can disappear with the border using label.configure({"relief":"flat", "text":""}). Of course this will look like the frame is not there, but everything inside the frame will still be visible. If you want to disappear with things inside the label you can use either label.destroy() (you will not be able to recover the label) or label.grid_forget() (which will only 'ungrid' the label).

json editor, how to delete tab and add label/entry inside the tab tkinter

I have this program that made tab i would like to made labels and entry for each tab
using a for loop or something?
from tkinter import *
import json
from tkinter.filedialog import asksaveasfile
import time
from tkinter import ttk
import math
import sys
root = Tk()
root.geometry('1000x1200')
root.title('Json Editor')
root.counter = 0
root.uncounter = -1
tabcontrol=ttk.Notebook(root, width=800, height=800)
NewWorkLab=Label(root,text="Name: ")
NewWorkLab.grid(row=0,column=0,sticky="W")
NewWorkEntry=Entry(root)
NewWorkEntry.grid(row=0,column=1,sticky="W")
def AddNewWork():
root.counter +=1
print(root.counter)
TabName=ttk.Frame(tabcontrol)
tabcontrol.add(TabName,text=NewWorkEntry.get())
TabName.ttk.Label(TabName, text ="Welcomes").grid(column = 0,
row = 0,
padx = 30,
pady = 30)
TabName.tabcontrol.ttk.Entry(TabName, text ="this label is wrong").grid(column = 1,
row = 0,
padx = 30,
pady = 30)
def deletetab():
tabcontrol.forget(tabcontrol.select())
# tabcontrol.destroy(TabName, root.counter)
AddWorkButton=Button(root,text=' Add ', command=AddNewWork)
AddWorkButton.grid(row=0,column=2, sticky="W")
RemWorkTab=Button(root,text=' Rem ', command=deletetab)
RemWorkTab.grid(row=0,column=3, sticky="W")
tabcontrol.grid(row=1,column=0,columnspan=2,padx=5)
root.mainloop()
finally my question
how can i make appear stuff like labels and entry inside the tabs that i created with the second program?
would be great having help thanks
how can i make appear stuff like labels and entry inside the tabs that i created with the second program?
You need to store a reference to the tab in a list or dictionary. You can then add widgets into a tab using the list index. For example, to add a label to tab i, you would do something like this:
tablist = []
def AddNewWork():
tab=ttk.Frame(tasktabs)
tasktabs.add(tab,text=NewWorkEntry.get())
tablist.append(tab)
...
i = # whatever tab number you want to modify
tab = tablist[i]
tab.button = Button(tab, text="Click me!")
tab.label = Label(tab, text="I'm a label")
How can i delete the tab that i created with the button?? Without having a fixed numbers of tabs as in the third program??
The same technique applies: call the destroy method on an element in the list. You should also remove the item from the list. For example, assuming you want to delete tab i, you would do something like this:
i = # whatever tab number you want to modify
tab = tablist.pop(i)
tab.destroy()

Need help completing code for password conversion

I'm very new at Python and need some help finishing the code. This is Tkiner related. I have an entry box, a button, and a lower frame for the output.
def loop_over_input(the_str=''):
master_list = []
for char in the_str:
tmp_char = passwordConversion[char]
master_list.append(tmp_char)
print("Master Pass List: ", master_list)
return master_list
This will work in command line with a couple of other lines. I'm not sure how tell it when I put text in the entry field and click the button to return the results in my lower frame. I have moved def loop_over_input to different parts of the code I think I may need to reference the test entry box and the button and the lower box.
I will post the complete code if requested to do so.
Firstly, you need to indent your code correctly. Everything that is in the function loop_over_input needs to be indented once more than the line def loop_over_input(the_str=''):
A few other notes. If you look up the documentation for the tkinter button, it will explain how to link a command to it. The piece of code you have supplied appears to be what you want the button command to be. Printing the list will do so in the shell, not in a frame below your entry field and button.
Here's some example code that should do what you want:
import tkinter as tk
# Creating tk window
window = tk.Tk()
# Master list
master_list = []
master_list_string = tk.StringVar()
# Frames
top_frame = tk.Frame(window)
top_frame.pack(expand = True, fill = 'x', pady = 10, padx = 10)
bottom_frame = tk.Frame(window)
bottom_frame.pack(expand = True, fill = 'both', padx = 10)
# Entry box
myEntry = tk.Entry(top_frame)
myEntry.pack(side = 'left',expand = True, fill = 'x', padx = 10)
# Label to display master list
myLabel = tk.Label(bottom_frame, textvariable = master_list_string)
myLabel.pack(expand = True, fill = 'both')
# Button to submit
def clicked():
master_list.append(myEntry.get())
myEntry.delete(0, 'end')
printed_list = ''
for password in master_list:
printed_list += "\n" + password
master_list_string.set(printed_list)
myButton = tk.Button(top_frame, text = "Submit", command = clicked)
myButton.pack(side = 'left', padx = 10)
# Mainloop
window.mainloop()
The two frames allow you to have the top section with your entry and button, while the bottom frame is for your output. However, you cannot just use a frame as your output, as your frame can't display text. Instead, use a Label widget linked to a StringVar which allows the text in the Label to update when the variable is changed.
The button command then takes the string entered into the entry, saves it to the master list and then sets the StringVar to the updated list, which automatically updates the Label.
I would highly recommend ready the documentation on Effbot, it's quite easy to understand with good examples. Link here

How can I place a widget at the very bottom of a tkinter window when positioning with .grid()?

I am aware that you cannot use different types of geometry managers within the same Tkinter window, such as .grid() and .pack(). I have a window that has been laid out using .grid() and I am now trying to add a status bar that would be snapped to the bottom of the window. The only method I have found online for this is to use .pack(side = BOTTOM), which will not work since the rest of the window uses .grid().
Is there a way that I can select the bottom of the window to place widgets from when using .grid()?
from tkinter import *
from tkinter.ttk import *
import tkinter as tk
class sample(Frame):
def __init__(self,master=None):
Frame.__init__(self, master)
self.status = StringVar()
self.status.set("Initializing")
statusbar = Label(root,textvariable = self.status,relief = SUNKEN, anchor = W)
statusbar.pack(side = BOTTOM, fill = X)
self.parent1 = Frame()
self.parent1.pack(side = TOP)
self.createwidgets()
def createwidgets(self):
Label(self.parent1,text = "Grid 1,1").grid(row = 1, column = 1)
Label(self.parent1,text = "Grid 1,2").grid(row = 1, column = 2)
Label(self.parent1,text = "Grid 2,1").grid(row = 2, column = 1)
Label(self.parent1,text = "Grid 2,2").grid(row = 2, column = 2)
if __name__ == '__main__':
root = Tk()
app = sample(master=root)
app.mainloop()
So using labels since I was kinda lazy to do other stuff, you can do frames to ensure that each section of your window can be packed/grid as required. Frames will be a useful tool for you to use when trying to arrange your widgets. Note that using a class can make things a little easier when deciding your parents. So imagine each frame is a parent and their children can be packed as required. So I would recommend drawing out your desired GUI and see how you will arrange them. Also if you want to add another frame within a frame simply do:
self.level2 = Frame(self.parent1)
You can check out additional settings in the docs
http://effbot.org/tkinterbook/frame.htm
PS: I am using a class hence the self, if you don't want to use classes then its okay to just change it to be without a class. Classes make it nicer to read though
Just give it a row argument that is larger than any other row. Then, give a weight to at least one of the rows before it.
Even better is to use frames to organize your code. Pack the scrollbar on the bottom and a frame above it. Then, use grid for everything inside the frame.
Example:
# layout of the root window
main = tk.Frame(root)
statusbar = tk.Label(root, text="this is the statusbar", anchor="w")
statusbar.pack(side="bottom", fill="x")
main.pack(side="top", fill="both", expand=True)
# layout of the main window
for row in range(1, 10):
label = tk.Label(main, text=f"R{row}")
label.grid(row=row, sticky="nsew")
main.grid_rowconfigure(row, weight=1)
...

Categories

Resources