python3 tkinter event.x event.y negative values - python-3.x

In using the code reproduced below, I noticed that in both Press-Release and Motion actions, tkinter reports negative event.x values when we move the mouse from right to left.
My question: for the purposes of identifying correctly the widget that the mouse finally rested, whatever the direction taken, what is the correct way of identifying the (event.x, event.y) points in the containing frame?
#!/usr/bin/env python3
from tkinter import *
root = Tk()
def press(event):
print(f"{event.widget} clicked at: {event.x, event.y}")
print(f"{event.widget.grid_info()}")
def release(event):
print("RELEASE")
end_x, end_y = event.x, event.y
print(f"{end_x, end_y}")
locate(end_x, end_y)
def motion(event):
print(f"{event.widget}: mouse position motion at {event.x, event.y}")
def locate(end_x, end_y):
end_x = int(end_x)
end_y = int(end_y)
print(f"Released at {fr.grid_location(end_x, end_y)}")
end_col, end_row = fr.grid_location(end_x, end_y)
print(end_col, end_row)
print(f"Actual frame info: {fr.grid_info()}")
fr = Frame(root, width=200, height=300,bg="dark blue")
fr.grid(sticky=NSEW, padx=2, pady=2)
lbl1 = Label(master=fr, text="LABEL 1", padx=2, pady=2, width=10, relief=SUNKEN)
lbl1.grid(column=0, row=0, sticky=NSEW)
lbl2 = Label(master=fr, text="LABEL 2", padx=2, pady=2, width=10, relief=SUNKEN)
lbl2.grid(column=1, row=0, sticky=NSEW)
lbl3 = Label(master=fr, text="LABEL 3", padx=2, pady=2, width=10, relief=SUNKEN)
lbl3.grid(column=2, row=0, sticky=NSEW)
lbl4 = Label(master=fr, text="LABEL 4", padx=2, pady=2, width=10, relief=SUNKEN)
lbl4.grid(column=0, row=1, sticky=NSEW)
lbl5 = Label(master=fr, text="LABEL 5", padx=2, pady=2, width=10, relief=SUNKEN)
lbl5.grid(column=1, row=1, sticky=NSEW)
lbl6 = Label(master=fr, text="LABEL 6", padx=2, pady=2, width=10, relief=SUNKEN)
lbl6.grid(column=2, row=1, sticky=NSEW)
lbl1.bind_all("<Button-1>", press)
lbl1.bind_all("<ButtonRelease-1>", release)
lbl1.bind_all("<B3-Motion>", motion)
lbl1.bind_all("<ButtonRelease-3>", release)
root.mainloop()
Thanks.

for the purposes of identifying correctly the widget that the mouse finally rested, whatever the direction taken, what is the correct way of identifying the (event.x, event.y) points in the containing frame?
The x/y coordinates of the release event are relative to the widget that got the press event, which explains why the values can be negative.
The coordinates to use for finding the widget under the cursor are event.x_root and event.y_root, which you can pass to winfo_containing to get the actual widget.
For example:
def release(event):
window = root.winfo_containing(event.x_root, event.y_root)
print(f"window under the cursor: {window}")

Related

Tkinter Grid of Labels with fixed column-sizes

I just started to learn python and tried to setup a simple GUI with Tkinter.
I am having problems understanding the grid feature of Tkinter.
I want to create a GUI, where I can dynamically add new frames with a fixed setup.
For simplicity, I just used labels in this example.
This is my code:
from tkinter import *
def newLabelWithContent(root, name):
frame = Frame(root)
frame.grid_columnconfigure(tuple(range(18)), weight=1)
frame.grid_rowconfigure(0, weight=1)
frame.pack(fill="both", side = TOP)
Label(frame, text=name, borderwidth=2, relief="groove").grid(column=0, row=0, sticky="news", columnspan=6)
Label(frame, text="Actual", borderwidth=2, relief="groove").grid(column=6, row=0, sticky="news", columnspan=4)
Label(frame, text="Unit", borderwidth=2, relief="groove").grid(column=10, row=0, sticky="news", columnspan=1)
Label(frame, text="Type", borderwidth=2, relief="groove").grid(column=11, row=0, sticky="news", columnspan=1)
Label(frame, text="Set Value", borderwidth=2, relief="groove").grid(column=12, row=0, sticky="news", columnspan=4)
Label(frame, text="Set-/Action-Button", borderwidth=2, relief="groove").grid(column=16, row=0, sticky="news", columnspan=2)
for widget in frame.winfo_children():
widget.grid(padx=0, pady=2)
root = Tk()
root.title("BaseTopic")
root.geometry("500x200")
newLabelWithContent(root, "First Element")
newLabelWithContent(root, "Second Elemnt")
newLabelWithContent(root, "Short")
newLabelWithContent(root, "Looooooooooooooooooooong")
root.mainloop()
The result looks like this:
But I want that all columns have the same size, no matter which text is displayed on the labels. So it looks more like a table. When the window is resized the labels should resize too.
It is hard to align those labels if they are in different frames. Put all of them inside same frame instead.
from tkinter import *
def newLabelWithContent(frame, name):
cols, rows = frame.grid_size()
Label(frame, text=name, borderwidth=2, relief="groove").grid(column=0, row=rows, sticky="news", columnspan=6)
Label(frame, text="Actual", borderwidth=2, relief="groove").grid(column=6, row=rows, sticky="news", columnspan=4)
Label(frame, text="Unit", borderwidth=2, relief="groove").grid(column=10, row=rows, sticky="news", columnspan=1)
Label(frame, text="Type", borderwidth=2, relief="groove").grid(column=11, row=rows, sticky="news", columnspan=1)
Label(frame, text="Set Value", borderwidth=2, relief="groove").grid(column=12, row=rows, sticky="news", columnspan=4)
Label(frame, text="Set-/Action-Button", borderwidth=2, relief="groove").grid(column=16, row=rows, sticky="news", columnspan=2)
for widget in frame.winfo_children():
widget.grid(padx=0, pady=2)
root = Tk()
root.title("BaseTopic")
root.geometry("800x200")
frame = Frame(root)
frame.pack(fill='both', expand=1)
frame.grid_columnconfigure(tuple(range(18)), weight=1)
newLabelWithContent(frame, "First Element")
newLabelWithContent(frame, "Second Elemnt")
newLabelWithContent(frame, "Short")
newLabelWithContent(frame, "Looooooooooooooooooooong")
root.mainloop()

Why is the tkinter text widget screwing up my cell sizes?

All was going well as seen in the 1st pic below. all the cells are the same perfect size. its great.
But then comes the implementation of the textbox. and all hell breaks loose. as seen in the 2nd picture it completely disrupts my grid layout. i dont want the textbox adjusting cell sizes, i want it to go where i tell it to go like all the other widgets do. Ive spent hours on this and no avail!
import tkinter as tk
from tkinter import ttk, scrolledtext
root = tk.Tk()
root.state('zoomed')
root.configure(background='#8585ad')
for i in range(0,20):
for x in range(0,20):
root.columnconfigure(i, weight=1)
root.rowconfigure(x, weight=1)
for i in range(0, 20): # 0-19(20 is excluded) so this will loop 10x
for x in range(0, 20):
tk.Label(root, text=f"C-{i}, R-{x}", bg="green", fg="white").grid(column=i, row=x, sticky="NSEW", padx=1, pady=1)
main_frame = tk.Label(root, text="MAIN FRAME", bg="blue", fg="white", anchor="n").grid(column=1, row=1, columnspan=18, rowspan=18, sticky="NSEW")
frame1 = tk.Label(root, text="FRAME 1", bg="red", fg="white", anchor="n").grid(column=2, row=2, columnspan=3, rowspan=16, sticky="NSEW")
frame2 = tk.Label(root, text="FRAME 2", bg="green", fg="white", anchor="n").grid(column=6, row=2, columnspan=6, rowspan=16, sticky="NSEW")
frame3 = tk.Label(root, text=" FRAME 3", bg="red", fg="white", anchor="n").grid(column=13, row=2, columnspan=5, rowspan=16, sticky="NSEW")
for i in range(2, 5): # start at 2 and end after the 3rd loop.
for x in range(3, 18): # to loop 15x and for index to start at 3 so i then put (3,18), 18-3 = 15
tk.Label(root, text=f"Button-{(x-2)}", bg="white", fg="black").grid(column=i, row=x, sticky="EW", padx=5, pady=5)
frame1_header = tk.Label(root, text="User Panel", bg="black", fg="white").grid(column=2, row=2, columnspan=3, sticky="SEW", padx=5, pady=5)
frame2_header = tk.Label(root, text="Editor", bg="black", fg="white").grid(column=6, row=2, columnspan=6, sticky="SEW", padx=5, pady=5)
frame3_header = tk.Label(root, text="Info Panel", bg="black", fg="white").grid(column=13, row=2, columnspan=5, sticky="SEW", padx=5, pady=5)
frame2_text_area = tk.Label(root, text="Text Box", bg="black", fg="white", anchor="center").grid(column=6, row=3, columnspan=4, rowspan=15, sticky="NSEW", padx=5, pady=5)
frame2_list_box = tk.Label(root, text="List Box", bg="grey", fg="white", anchor="center").grid(column=10, row=3, columnspan=2, rowspan=15, sticky="NSEW", padx=5, pady=5)
frame3_tab_panel = ttk.Notebook(root)
frame3_tab_panel.grid(column=13, row=3, columnspan=5, rowspan=15, sticky="NSEW", padx=5, pady=5)
tab1 = ttk.Frame(root)
tab2 = ttk.Frame(root)
tab3 = ttk.Frame(root)
frame3_tab_panel.add(tab1, text ='Generic Editor')
frame3_tab_panel.add(tab2, text ='Text Compare')
frame3_tab_panel.add(tab3, text ='Script Ref')
# width and height does indeed adjust the texbox size but the textbox still isnt properly sticking to the grid that i set.
frame3_tab_panel_tab1 = tk.Text(root, relief="ridge", bd=2, undo=True, wrap="none", background='#1E1E1E', insertbackground='white')#, width=40, height=10)
frame3_tab_panel_tab1.grid(column=13, row=4, columnspan=5, rowspan=14, padx=5, pady=5)
frame3_tab_panel_tab1.config(font=('Consolas bold',10), fg="white")
frame3_tab_panel_tab1.focus()
root.mainloop()
"""
text_area = scrolledtext.ScrolledText(tab1, wrap = tk.WORD, width=40, height=10, font=("Times New Roman", 15))
text_area.grid(column = 0, pady = 10, padx = 10)
text_area.focus()
"""
without textbox. as you can see its all perfectly even.
FYI: this is just a template im working on so i can better understand tk's positioning.
textbox ruining grid by not adjusting itself accordingly and fitting to the grid i set.
There is a lot of wrong doing in your code and you really should take a good tutorial for tkinter and you may wish to have a brief overview of tkinters geometry management.
The biggest issue is whats causes your code to work differently as you expect it, you always define the root as the master. Every widget, except for the root window, has a master and is set by the ONLY positional argument every widget requiers. Note that if None is given, the root window is set by default. This is, because tkinter is built hirachically and at the top of this hirachy stands the root window (the instance of tk.Tk()).
A master should be a container and this means either the root window, a Toplevel or a Frame. Masters can have so called children, which can be every other widget plus frames that are handled as children. The relationship between a master and a frame are various, but for the scope of this question we will just look at the geometry.
Every widget has a geometry and can be received by the universal widget method .winfo_geometry() that will give you a geometry string 'widthxheight±x_offset±y_offset' (e.g. '120x50-0+20'). The geometry string is the basement for every calculations to order your widgets, which you can affect by choosing a geometry manager and different optional keywords. With those information an output will be created and displayed on your screen.
Suggestion:
import tkinter as tk
from tkinter import ttk, scrolledtext
def populate_frame_1():
frame_1_label = tk.Label(frame_1,text='User Panel',
background = 'black',
foreground = 'white')
frame_1_label.grid(column=0,row=0,sticky='ew',columnspan=3)
frame_1.columnconfigure(0,weight=1)
frame_1.columnconfigure(1,weight=1)
frame_1.columnconfigure(2,weight=1)
for i in range(0, 3):
for x in range(1, 16):
l = tk.Button(frame_1, text=f"Button-{(x-2)}",
bg="white", fg="black")
l.grid(column=i, row=x, sticky="EW", padx=5, pady=5)
def populate_frame_2():
frame_2_label = tk.Label(frame_2,text='Editor',
background = 'black',
foreground = 'white')
textbox = tk.Text(frame_2,width=35)
listbox = tk.Listbox(frame_2,bg='yellow')
frame_2_label.grid(column=0,row=0,sticky='ew',columnspan=6)
textbox.grid(column=0,row=1,sticky='ns',columnspan=4)
listbox.grid(column=4,row=1,sticky='ns',columnspan=2)
frame_2.rowconfigure(1,weight=2)
def populate_frame_3():
frame_3_label = tk.Label(frame_3,text='Info Panel',
background = 'black',
foreground = 'white')
frame_3_label.grid(column=0,row=0,sticky='ew',columnspan=5)
control_panel = ttk.Notebook(frame_3)
tab1 = ttk.Frame(control_panel)
tab2 = ttk.Frame(control_panel)
tab3 = ttk.Frame(control_panel)
control_panel.add(tab1, text ='Generic Editor')
control_panel.add(tab2, text ='Text Compare')
control_panel.add(tab3, text ='Script Ref')
control_panel.grid(column=0,row=1,sticky='nswe')
frame3_tab_panel_tab1 = tk.Text(tab1, relief="ridge", bd=2, undo=True,
wrap="none", background='#1E1E1E',
insertbackground='white',width=40, height=10)
frame3_tab_panel_tab1.pack(fill=tk.BOTH,expand=True)
frame3_tab_panel_tab1.config(font=('Consolas bold',10), fg="white")
frame3_tab_panel_tab1.focus()
frame_3.rowconfigure(1,weight=2)
frame_3.columnconfigure(0,weight=2)
XOFFSET = 75
YOFFSET = 50
root = tk.Tk()
root.state('zoomed')
root.configure(background='#8585ad')
main_frame = tk.Frame(root,background='blue')
frame_1 = tk.Frame(main_frame,background='red')
frame_2 = tk.Frame(main_frame,background='green')
frame_3 = tk.Frame(main_frame,background='red')
main_frame.pack(fill=tk.BOTH,expand=True,
padx=XOFFSET,pady=YOFFSET)
frame_1.pack(side=tk.LEFT,fill=tk.BOTH,padx=XOFFSET,pady=YOFFSET,expand=True)
frame_2.pack(side=tk.LEFT,fill=tk.Y,pady=YOFFSET,expand=True)
frame_3.pack(side=tk.LEFT,fill=tk.BOTH,padx=XOFFSET,pady=YOFFSET,expand=True)
populate_frame_1()
populate_frame_2()
populate_frame_3()
root.mainloop()
Change
frame3_tab_panel_tab1.grid(
column=13, row=4, columnspan=5, rowspan=14, padx=5, pady=5
)
to
frame3_tab_panel_tab1.grid(
column=13, row=4, columnspan=5, rowspan=14, padx=5, pady=5,
sticky="NSEW"
)
I managed to solve it by replacing the Text() widget with the scrolledtext.ScrolledText() widget. Its strange. No grid was required and if i remove height and width then it messes it up. Why does height and width have such an impact? why does it even exist when you have things like column and row configure along with sticky. Tkinter is quite confusing sometimes with its logic. But anyways, got there in the end.
Here's the code in case anyone encounters a similar issue.
import tkinter as tk
from tkinter import ttk, scrolledtext
root = tk.Tk()
root.state('zoomed')
root.configure(background='#8585ad')
for i in range(0,20):
for x in range(0,20):
root.columnconfigure(i, weight=1)
root.rowconfigure(x, weight=1)
for i in range(0, 20): # 0-19(20 is excluded) so this will loop 10x
for x in range(0, 20):
tk.Label(root, text=f"C-{i}, R-{x}", bg="green", fg="white").grid(column=i, row=x, sticky="NSEW", padx=1, pady=1)
main_frame = tk.Label(root, text="MAIN FRAME", bg="blue", fg="white", anchor="n").grid(column=1, row=1, columnspan=18, rowspan=18, sticky="NSEW")
frame1 = tk.Label(root, text="FRAME 1", bg="red", fg="white", anchor="n").grid(column=2, row=2, columnspan=3, rowspan=16, sticky="NSEW")
frame2 = tk.Label(root, text="FRAME 2", bg="green", fg="white", anchor="n").grid(column=6, row=2, columnspan=6, rowspan=16, sticky="NSEW")
frame3 = tk.Label(root, text=" FRAME 3", bg="red", fg="white", anchor="n").grid(column=13, row=2, columnspan=5, rowspan=16, sticky="NSEW")
for i in range(2, 5): # start at 2 and end after the 3rd loop.
for x in range(3, 18): # to loop 15x and for index to start at 3 so i then put (3,18), 18-3 = 15
tk.Label(root, text=f"Button-{(x-2)}", bg="white", fg="black").grid(column=i, row=x, sticky="EW", padx=5, pady=5)
frame1_header = tk.Label(root, text="User Panel", bg="black", fg="white").grid(column=2, row=2, columnspan=3, sticky="SEW", padx=5, pady=5)
frame2_header = tk.Label(root, text="Editor", bg="black", fg="white").grid(column=6, row=2, columnspan=6, sticky="SEW", padx=5, pady=5)
frame3_header = tk.Label(root, text="Info Panel", bg="black", fg="white").grid(column=13, row=2, columnspan=5, sticky="SEW", padx=5, pady=5)
frame2_text_area = tk.Label(root, text="Text Box", bg="black", fg="white", anchor="center").grid(column=6, row=3, columnspan=4, rowspan=15, sticky="NSEW", padx=5, pady=5)
frame2_list_box = tk.Label(root, text="List Box", bg="grey", fg="white", anchor="center").grid(column=10, row=3, columnspan=2, rowspan=15, sticky="NSEW", padx=5, pady=5)
frame3_tab_panel = ttk.Notebook(root)
frame3_tab_panel.grid(column=13, row=3, columnspan=5, rowspan=15, sticky="NSEW", padx=5, pady=5)
frame3_tab_panel_tab1 = scrolledtext.ScrolledText(root, bd=2, undo=True, wrap="none", width=40, height=10, font=("Times New Roman", 15), background='#1E1E1E', insertbackground='white')
frame3_tab_panel_tab1.config(font=('Consolas bold',10), fg="white")
frame3_tab_panel_tab1.focus()
tab2 = ttk.Frame(root)
tab3 = ttk.Frame(root)
frame3_tab_panel.add(frame3_tab_panel_tab1, text ='Generic Editor')
frame3_tab_panel.add(tab2, text ='Text Compare')
frame3_tab_panel.add(tab3, text ='Script Ref')
root.mainloop()

Opening a new Window and going back

I have created several individuall windows with tkinter and now I want to connect them.
So implementing several "Forward" and "Back" Buttons. This should be simple but it turns out to screw with me alot.
This can be seen as a practical application issue of this question:
Go back and forth between tkinter windows
I implemented the explained logic the best I can but still fail.
My specific Issues are:
When I klick the "Reports"-button the new window opens but: the
original window(cockpit) doesnt disapear and a second window opens
which is just the Original Cockpit window but without any widgets in
it (just the frame?)
Also when I hit the "Back" Button this error Message Appears:
self.ReportSelection_Win.withdraw() AttributeError: 'Event' object
has no attribute 'ReportSelection_Win'
I stripped the following code of most of its functions since they arent neccessary for the issue I think. So most button dont have any function.
from tkinter import *
from tkinter import ttk
#Funktionen für Fenster
def Func_Show_Rep(self):
# Open new Window
ReportSelection_Win = Tk()
self.ReportSelection_Win = Toplevel()
ReportSelection_Win.title("Report auswählen")
#Dropdown Auswahlliste
Reports = [
"Alle Mitarbeiter",
"Alle Projekte",
"Alle Skills"
]
#Widgets
#Labels & Dropdown
Lbl_Headline = Label(ReportSelection_Win, text = "Bitte wählen Sie einen Report")#Create Label
Lbl_Headline.grid(column=0, row=0, padx=10, pady=10) #Show Label
Drop_Reports = ttk.Combobox(ReportSelection_Win)
Drop_Reports.grid(column=0, row=1, padx=10, pady=10)
Drop_Reports['values'] = Reports
#Buttons
Btt_Confirm_RepSelect = Button(ReportSelection_Win, text="Auswählen")
Btt_Confirm_RepSelect.bind("<Button-1>", Select_Report)
Btt_Confirm_RepSelect.grid(column=0, row=2, padx=10, pady=10, sticky=W)
Btt_Back_RepSelect = Button(ReportSelection_Win, text="Zurück")
Btt_Back_RepSelect.bind("<Button-1>", Func_ReportSelection_Back)#Back to Cockpit
Btt_Back_RepSelect.grid(column=0, row=2, padx=10, pady=10, sticky=E)
self.Cockpit_Win.withdraw() #.deiconify() to show again
#Funktionen für Report Fenster
def Func_ReportSelection_Back(self):
self.ReportSelection_Win.withdraw()
self.Cockpit_Win.deiconify()
#Modify the Window [◙Not essential for Issue]
Cockpit_Win.title("Ressourcen Verwaltung")
Cockpit_Win.columnconfigure(1, weight=1)
Lbl_Descr_MA = Label(Cockpit_Win, text = "Mitarbeiter verwalten und anlegen")#Create Label
Lbl_Descr_MA.grid(column=0, row=0, padx=10) #Show Label
Btt_Show_MA = Button(Cockpit_Win, text="Mitarbeiter", width=35)
Btt_Show_MA.bind("<Button-1>",Func_Show_MA)#Button click starts function
Btt_Show_MA.grid(column=1, row=0, padx=10, pady=7, sticky=E)
Lbl_Descr_Pro = Label(Cockpit_Win, text = "Projekte Verwalten und anlegen.")#Create Label
Lbl_Descr_Pro.grid(column=0, row=1, padx=10) #Show Label
Btt_Show_Pro = Button(Cockpit_Win, text="Projekte", width=35)
Btt_Show_Pro.bind("<Button-1>",Func_Show_Pro)#Button click starts function
Btt_Show_Pro.grid(column=1, row=1, padx=10, pady=7, sticky=E)
Lbl_Descr_Rep = Label(Cockpit_Win, text = "Report auswählen und ausgeben")#Create Label
Lbl_Descr_Rep.grid(column=0, row=2, padx=10) #Show Label
Btt_Show_Rep = Button(Cockpit_Win, text="Reports", width=35)
Btt_Show_Rep.bind("<Button-1>",Func_Show_Rep)#Button click starts function
Btt_Show_Rep.grid(column=1, row=2, padx=10, pady=7, sticky=E)
Btt_Cock_Abort = Button(Cockpit_Win, text="Abbrechen", width=35)
Btt_Cock_Abort.bind("<Button-1>",Func_Cock_Abort)#Button click starts function
Btt_Cock_Abort.grid(column=1, row=3, padx=10, pady=7, sticky=E)
Cockpit_Win.geometry('350x170') #Window size
#Make the windows stay (loop)
Cockpit_Win.mainloop()
I reduced your code to almost minimal working case.
from tkinter import *
from tkinter import ttk
#Funktionen für Fenster
def Func_Show_Rep(even = None):
global Cockpit_Win
Cockpit_Win.withdraw()#.deiconify() to show again
ReportSelection_Win = Toplevel()
Show_Rep(ReportSelection_Win, Cockpit_Win)
class Show_Rep():
# Hide old Window
def __init__(self, master, Cockpit_Win):
# Open new Window
self.ReportSelection_Win =master
self.ReportSelection_Win.title("Report auswählen")
#Dropdown Auswahlliste
Reports = [
"Alle Mitarbeiter",
"Alle Projekte",
"Alle Skills"
]
#Widgets
#Labels & Dropdown
Lbl_Headline = Label(self.ReportSelection_Win, text = "Bitte wählen Sie einen Report")#Create Label
Lbl_Headline.grid(column=0, row=0, padx=10, pady=10) #Show Label
Drop_Reports = ttk.Combobox(self.ReportSelection_Win)
Drop_Reports.grid(column=0, row=1, padx=10, pady=10)
Drop_Reports['values'] = Reports
#Buttons
Btt_Back_RepSelect = Button(self.ReportSelection_Win, text="Zurück")
Btt_Back_RepSelect.bind("<Button-1>", self.Func_ReportSelection_Back)#Back to Cockpit
Btt_Back_RepSelect.grid(column=0, row=2, padx=10, pady=10, sticky=E)
#Funktionen für Report Fenster
def Func_ReportSelection_Back(self, event = None):
self.ReportSelection_Win.withdraw()
Cockpit_Win.deiconify()
Cockpit_Win = Tk()
#Modify the Window [◙Not essential for Issue]
Cockpit_Win.title("Ressourcen Verwaltung")
Cockpit_Win.columnconfigure(1, weight=1)
Lbl_Descr_Rep = Label(Cockpit_Win, text = "Report auswählen und ausgeben")#Create Label
Lbl_Descr_Rep.grid(column=0, row=2, padx=10) #Show Label
Btt_Show_Rep = Button(Cockpit_Win, text="Reports", width=35)
Btt_Show_Rep.bind("<Button-1>",Func_Show_Rep)#Button click starts function
Btt_Show_Rep.grid(column=1, row=2, padx=10, pady=7, sticky=E)
Cockpit_Win.geometry('350x170') #Window size
#Make the windows stay (loop)
Cockpit_Win.mainloop()
Explanation:
I crated class that writes your reports to window.
And function that hides your main_window, makes Topwindow

How to reposition widgets in tkinter without disturbing adjacent widgets?

I have a button in column 5, and have several Labels at column 1, 2, 3 and 4 (each at row 0). When I use pady for my button in column 5 , other labels also come down making it harder to achieve the desired layout.
I don't know of any other way of repositioning widgets in the y-direction except pady.
Code
from tkinter import *
from tkinter import ttk
root = Tk()
root.geometry("1000x500")
root.title("Stock Manager")
root.resizable(False, False)
Label(root, text="Image", font=20).grid(column=0, row=0, pady=5, padx=50)
Label(root, text="Product No.", font=20).grid(column=1, row=0, pady=5, padx=40)
prodnumempty = Label(root, text="00547", font=16).grid(column=1, row=1)
Label(root, text="Description", font=20).grid(column=2, row=0, pady=5, padx=40)
Label(root, text="Quantity", font=20).grid(column=3, row=0, pady=5, padx=40)
Label(root, text="Price", font=20).grid(column=4, row=0, pady=5, padx=40)
historybtn = ttk.Button(root, text="See Product History").grid(column=5, row=0)
root.mainloop()
I want the See Product History button to be at the bottom while other labels should remain fixed at their position.
One approach is to have all the labels in a frame, gridded on the left, and the button gridded on th eright, in a lower row:
Something like this:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.geometry("1000x500")
root.title("Stock Manager")
root.resizable(False, False)
left_frame = tk.Frame(root, width=900, height=500)
tk.Label(left_frame, text="Image", font=20).grid(column=0, row=0, pady=5, padx=50)
tk.Label(left_frame, text="Product No.", font=20).grid(column=1, row=0, pady=5, padx=40)
prodnumempty = tk.Label(left_frame, text="00547", font=16).grid(column=1, row=1)
tk.Label(left_frame, text="Description", font=20).grid(column=2, row=0, pady=5, padx=40)
tk.Label(left_frame, text="Quantity", font=20).grid(column=3, row=0, pady=5, padx=40)
tk.Label(left_frame, text="Price", font=20).grid(column=4, row=0, pady=5, padx=40)
left_frame.grid(column=2, row=0)
historybtn = ttk.Button(root, text="See Product History").grid(column=5, row=1)
root.mainloop()

Tkinter listbox entry pagination

Recently, I tried to find a way to paginate through listbox entries that runs functions that opens frames with forms, tabs or else, but I didn't find it.
Clearly, I wanna create a control panel application which has a side panel which can switch between pages/frames that hold widgets that user will interact with.
this is the code which I wrote to try to achieve this manner:
import tkinter as tk
from tkinter import ttk
class MainWindow() :
def __init__(self,root):
# menu left
self.menu_upper_frame = tk.Frame(root, bg="#dfdfdf")
self.menu_title_label = tk.Label(self.menu_upper_frame, text="menu title", bg="#dfdfdf")
self.menu_title_label.pack()
self.menu_left_container = tk.Frame(root, width=150, bg="#ababab")
self.menu_left_upper = tk.Frame(self.menu_left_container, width=150, height=150, bg="red")
self.menu_left_upper.pack(side="top", fill="both", expand=True)
# create a listbox of items
self.Lb1 = tk.Listbox(self.menu_left_upper,bg ="red", borderwidth=0, highlightthickness=0 )
self.Lb1.insert(1, "Python")
self.Lb1.insert(2, "Perl")
self.Lb1.insert(3, "C")
self.Lb1.insert(4, "PHP")
self.Lb1.insert(5, "JSP")
self.Lb1.insert(6, "Ruby")
self.Lb1.bind("<<ListboxSelect>>", self.OnClick ) #return selected item
self.Lb1.pack(fill="both", expand=True, pady=50 )
# right area
self.inner_title_frame = tk.Frame(root, bg="#dfdfdf")
self.inner_title_label = tk.Label(self.inner_title_frame, text="inner title", bg="#dfdfdf")
self.inner_title_label.pack()
self.canvas_area = tk.Canvas(root, width=500, height=400, background="#ffffff")
self.canvas_area.grid(row=1, column=1)
# status bar
self.status_frame = tk.Frame(root)
self.status = tk.Label(self.status_frame, text="this is the status bar")
self.status.pack(fill="both", expand=True)
self.menu_upper_frame.grid(row=0, column=0, rowspan=2, sticky="nsew")
self.menu_left_container.grid(row=1, column=0, rowspan=2, sticky="nsew")
self.inner_title_frame.grid(row=0, column=1, sticky="ew")
self.canvas_area.grid(row=1, column=1, sticky="nsew")
self.status_frame.grid(row=2, column=0, columnspan=2, sticky="ew")
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(1, weight=1)
def OnClick(self,event):
widget = event.widget
selection = widget.curselection()
value = widget.get(selection)
# print ("selection: ",selection, ": '%s'"% value)
if value == 'Python':
self.tabtop()
def tabtop(self):
self.tabControl = ttk.Notebook(self.canvas_area, width=400)
self.tab1 = ttk.Frame(self.tabControl)
self.tab2 = ttk.Frame(self.tabControl)
self.tab3 = ttk.Frame(self.tabControl)
self.tab4 = ttk.Frame(self.tabControl)
self.tab5 = ttk.Frame(self.tabControl)
self.tabControl.add(self.tab1, text='Login data' )
self.tabControl.add(self.tab2, text='Permission')
self.tabControl.add(self.tab3, text='Roles')
self.tabControl.add(self.tab4, text='Personal data')
self.tabControl.add(self.tab5, text='Business data')
self.tabControl.pack(expand=1, fill="both")
self.l2 = tk.Label(self.tab2, text="label 2").pack()
self.l3 = tk.Label(self.tab3, text="label 3").pack()
root = tk.Tk()
root.title("Control Panel")
root.style = ttk.Style()
root.style.theme_use("clam")
user = MainWindow(root)
root.mainloop()
If you have an idea to achieve the same manner with a different algorithm please suggest!

Resources