I am creating an app and this is the part of it. I will put a canvas up to the screen so I want these variables to be at the bottom of the page but when I run this code it places everything on top left corner as shown in the photo(figure1). I am using grid function but I couldn't understand why it doesn't place where I want.(Sorry for bad english)
main = Tkinter.Tk()
main.geometry("1500x1000")
main.title("Momentum")
ml1 = Tkinter.Label(main, text ="MASS OF THE FIRST OBJECT")
ml2 = Tkinter.Label(main, text ="MASS OF THE SECOND OBJECT")
me1 = Tkinter.Entry(main)
me2 = Tkinter.Entry(main)
ml1.grid(row=600, column =400)
ml2.grid(row =600, column =600 )
me1.grid(row=650, column =400)
me2.grid(row=650, column=600)
main.mainloop()
Related
I have a tkinter app that has multiple combo boxes and at the bottom also a Text widget. In the beginning, I used the style method in order to change the Combobox look but then I had to use a canvas in order to put text over the picture background and for some reason, my comboxes are now not changing their style anymore and are staying plain. here is a part of my code with only one combo box since the whole code is long but the concept i think should be applied the same:
roo = Tk()
roo.title('Shift Request')
roo.geometry('600x450')
dir_path_main_bg = os.path.join(dir_path, r"JUSTT BG For Main Window.png")
picture = PhotoImage(file=dir_path_main_bg, master=roo)
bg = Label(roo, image=picture)
bg.place(x=0, y=0, relwidth=1, relheight=1)
# Changing the combobox menu style.
roo.option_add('*TCombobox*Listbox.selectBackground', '#30D5C8') # change highlight color
roo.option_add('*TCombobox*Listbox.selectForeground', 'white') # change text color
style = ttk.Style()
style.configure('TCombobox', background='#30D5C8') # Create a border around the combobox button.
style.map('TCombobox', foreground=[('hover', 'black')], background=[('hover', '#30D5C8')]) # style the combobox when
# it's beeing hovered on.
# Creating a canvas for the main window menu to choose your shifts.
main_menu_canvas = Canvas(roo, width=500, height=450, highlightbackground='#30D5C8', highlightcolor='#30D5C8')
main_menu_canvas.pack(fill='both', expand=True)
main_menu_canvas.create_image(0, 0, image=picture, anchor='nw')
# A function to stop the highlighting when choosing a value.
def defocus(event):
event.widget.master.focus_set()
# Second drop-down menu.
chosen2 = tk.StringVar(value='Shift Starting Hour')
vyber2 = ttk.Combobox(roo, textvariable=chosen2, state='readonly')
vyber2['values'] = start_shift
vyber2.bind("<FocusIn>", defocus)
vyber2.place(relx=0.27, rely=0.16, relwidth=0.45, relheight=0.09)
vyber2.config(font=('calibri', '13'))
# Changing the combobox menu style.
roo.option_add('*TCombobox*Listbox.selectBackground', '#30D5C8') # change highlight color
roo.option_add('*TCombobox*Listbox.selectForeground', 'white') # change text color
style = ttk.Style()
style.configure('TCombobox', background='#30D5C8') # Create a border around the combobox button.
style.map('TCombobox', foreground=[('hover', 'black')], background=[('hover', '#30D5C8')]) # style the combobox when
# # it's beeing hovered on.
# Creating the text box to write notes.
default_val = tk.StringVar(value='Notes...').get()
text_box = Text(main_menu_canvas, width=45, height=6, font=('calibri','13'))
text_box.insert(INSERT, default_val)
text_box.config(highlightthickness=0.5, highlightbackground='#30D5C8', highlightcolor='#30D5C8')
main_menu_canvas.create_window(300, 336, window=text_box)
roo.mainloop()
My desired result is to make it look like how it was before. The first screenshot is the way it looks now and the second screenshot it's how it was before the text addition.
Would appreciate any help.
I have recently been playing with tkinter (specifically buttons and labels) and so far I have created some simple code which displays a label, then using a button the label is removed, and through another button the label is brought back.
However, if I display two labels, only the most recent label can be removed, and I cannot find a way to remove the previous label. Here is the code so you can try it and look at the problem yourself:
import tkinter as tk
top = tk.Tk()
def on_click():
global label
label.after(10, label.destroy())
def restore():
global label
label = tk.Label (top, text = "INCOMING")
label.pack(pady = 20)
tk.Button(top, text = "Delete?", command=on_click).pack()
tk.Button(top, text = "Restore?", command=restore).pack()
label = tk.Label(top, text = "TACTICAL NUKE")
label.pack(pady = 20)
top.mainloop()
How can I solve this?
The variable label is overwritten with a reference to the last label that is inserted. Therefore, you lose the references to the previous labels. You need to keep them somewhere in your program.
A good way to keep multiple related values in Python is to use a list. (Read about lists here.)
In this case you can use a list to implement a data structure called "stack", where you add values to the end (by using the append method of the list) and remove them from the end (by using the pop method).
The simplest possible change to make this work would be to replace the global variable label by a global variable labels which is a list that contains references to labels.
import tkinter as tk
top = tk.Tk()
def on_click():
label = labels.pop()
label.after(10, label.destroy())
def restore():
label = tk.Label (top, text = "INCOMING")
label.pack(pady = 20)
labels.append(label)
tk.Button(top, text = "Delete?", command=on_click).pack()
tk.Button(top, text = "Restore?", command=restore).pack()
label = tk.Label(top, text = "TACTICAL NUKE")
label.pack(pady = 20)
labels = [label]
top.mainloop()
Now you need to consider what should happen after the original label has been removed.
I'm trying to make a page for my tkinter GUI and when I try to put a button to go to the previous page at the bottom left corner it never seems to work.
I have created a frame to put inside the window, packing it to the left side, then packing the button in that frame to the bottom of it. I have also tried it the other way round, so frame at the bottom and the button on the left. Changing the values of the size of the frame seems to do nothing.
previousPageF = tk.Frame(self, height = "100", width = "500")
previousPageF.pack(side = "bottom")
previousPageB = tk.Button(previousPageF, font = BASIC_FONT, text = "<--", command = lambda: controller.show_frame(LoginPage))
previousPageB.pack(side = "left")
Picture of the results of the code
I want it to be the very bottom left corner and not in the position it is currently in. I would like to use pack as it is not a very complicated GUI design and pack also puts it automatically in the centre of the window, whereas with grid I would have to do some maths to get it perfectly in the centre. Furthermore, I have done all of my other work with pack so I would prefer not to change all of it just to get this to work.
Figured it out with trial and error.
previousPageB = tk.Button(self, font = BASIC_FONT, text = "<--", command = lambda: controller.show_frame(LoginPage))
previousPageB.pack(anchor = "w", side = "bottom")
This will result in the button being in the bottom left corner:
enter image description here
It will also work if you do:
previousPageB = tk.Button(self, font = BASIC_FONT, text = "<--", command = lambda: controller.show_frame(LoginPage))
previousPageB.pack(anchor = "s", side = "left")
You don't have to use frame for this.You can directly mention fill='none' and side='left' in pack to place widget to left in window.
import tkinter as tk
root = tk.Tk()
previousPageB = tk.Button(root, text = "<--", command = lambda:
controller.show_frame(LoginPage))
previousPageB.pack(fill='none',side = "left")
For a project I need to specify a certain value for N subfiles (sets of data), and this value can either be evenly spaced (omitted here), requiring only a starting value and an increment, or unevenly spaced, which means each subfile has its own value. I've decided to use a Notebook to separate the two methods of entry.
As the number of subfiles can get into hundreds, I would need a scrollbar, and after consulting Google I've found out that to use a scrollbar in such manner I would need to use a canvas and place a frame in it with everything I would want to scroll through.
The number can vary each time, so I decided to use a dictionary, that would be iteratively filled, to contain all 'entry frames' that each contain a label, an entry field and a variable, rolled up into one custom class IterEntryField. After a class instance is created, it's packed inside one container frame. After the for loop is over, the container frame is placed on a canvas and the scrollbar is given a new scrollregion.
from tkinter import *
from tkinter.ttk import Notebook
N = 25
class IterEntryField:
def __init__(self, frame, label):
self.frame = frame
self.label = label
def pack(self):
self.valLabel = Label(self.frame, text = self.label, anchor = 'w')
self.valLabel.pack(fill = X, side = LEFT)
self.variable = StringVar()
self.variable.set('0')
self.valEntry = Entry(self.frame, textvariable = self.variable)
self.valEntry.pack(fill = X, side = RIGHT)
def notebookpopup():
zSetupWindow = Toplevel(root)
zSetupWindow.geometry('{}x{}'.format(800, 300))
notebook = Notebook(zSetupWindow)
evspace = Frame(notebook)
notebook.add(evspace, text = "Evenly spaced values")
sOverflow = Label(evspace, text = 'Ignore this')
sOverflow.pack()
uevspace = Frame(notebook)
notebook.add(uevspace, text = "Individual values")
canvas = Canvas(uevspace, width = 800, height = 400)
vsb = Scrollbar(canvas, command=canvas.yview)
canvas.config(yscrollcommand = vsb.set)
canvas.pack(side = LEFT, fill = BOTH, expand = True)
vsb.pack(side = RIGHT, fill = Y)
entryContainer = Frame(canvas)
entryContainer.pack(fill = BOTH)
frameDict = {}
for i in range(0, N):
frameDict[i] = Frame(entryContainer)
frameDict[i].pack(fill = X)
entry = IterEntryField(frameDict[i], 'Z value for subfile {}'.format(i+1))
entry.pack()
canvas.create_window(200, 0, window = entryContainer)
canvas.config(scrollregion = (0,0,100,1000))
notebook.pack(fill = X)
root = Tk()
button = Button(root, text = 'new window', command = notebookpopup)
button.pack()
root.mainloop()
I'm having three problems with this code:
The pages are incredibly short, only showing a couple lines.
I can't figure out the "proper" offset in create_window. I thought 0, 0 would place it in upper left corner of the canvas, but apparently the upper left corner of the window is taken instead. This could probably fixed by some reverse of the canvasx and canvasy methods, but I haven't been able to find any.
The entry fields and labels are cramped together instead of taking up the entire width of the canvas. This wasn't a problem when I only used the notebook page frame as the container.
Your first problem goes back to how you pack your notebook. Simply change notebook.pack(...) to below:
notebook.pack(fill="both", expand=True)
The second one can be solved by specifying the anchor position in your create_window method:
canvas.create_window(0, 0, window = entryContainer, anchor="nw")
I don't understand what the 3rd problem is - it looks exactly as expected.
When I run the following code the created labels appear over top of the Entry boxes as if they are not being added to the same grid.
class Application(Frame):
def __init__(self,master):
super(Application,self).__init__(master)
self.grid()
self.new_intervals()
def new_intervals(self):
self.int_label = Label(text="Interval Name")
self.int_label.grid(row=0, column=0,sticky=W)
self.int_time_label = Label(text="Time (HH:MM:SS)")
self.int_time_label.grid(row=0, column=1,sticky=W)
self.box1 = Entry(self)
self.box1.grid(row=1,column=0,sticky=W)
self.box2 = Entry(self)
self.box2.grid(row=1,column=1,sticky=W)
self.box3 = Entry(self)
self.box3.grid(row=2,column=0,sticky=W)
self.box4 = Entry(self)
self.box4.grid(row=2,column=1,sticky=W)
root = Tk()
root.title("Interval Timer")
root.geometry("400x500")
app=Application(root)
root.mainloop()
I know that i can add these boxes in a loop, however, I can't get it to work without the loop at the moment
The application frame is in row 0, column 0 of the main window. That is the default when you don't specify anything. Also as a default, they appear in the middle
This frame has four entry widgets spread across two rows, making the frame grow to fit around those entry widgets
The "Interval Name" label is also being placed in row 0, column 0 of the main window, because that's what you explicitly tell it to do, and because its parent is the main window.
The "Time" label is also in row 0 of the main window because, again, it's parent is the main window
both of these labels are appearing in the vertical center of the row because that is the default behavior which you haven't overridden, which is why they appear on top of the entry widgets.
So, because the labels and the application frame are in the same row of the main window, and because the labels default to being in the vertical center, they appear to be in the middle of the entry widgets.
I assume you intended for the labels to be children of the frame, so you need to specify "self" as the first parameter when creating them:
self.int_label = Label(self, text="Interval Name")
...
self.int_time_label = Label(self, text="Time (HH:MM:SS)")
I also recommend grouping all of your grid statements for a particular master window together, so it's easier to see the organization of your widgets. In my experience this makes the code easier to read and easier to maintain.
For example:
self.int_label = Label(...)
self.int_time_label = Label(...)
self.box1 = Entry(...)
...
self.int_label.grid(...)
self.int_time_label.grid(...)
self.box1.grid(...)
...