Problem using .pack() and .place() in tkinter python - python

I want to create a scrollable frame and add some widgets but I have a problem, when I use entry.place() it doesn't show any entry but if I use pack() it works perfectly, any solution?
from tkinter import *
from tkinter import ttk
root = Tk()
root.title("Entry Widgets")
mainframe = Frame(root)
mainframe.pack(fill = "both", expand = True)
canvas = Canvas(mainframe)
canvas.pack(side = "left", fill = "both", expand = True)
scrollbar = Scrollbar(mainframe, orient = "vertical", command = canvas.yview)
scrollbar.pack(side = "right", fill = "y")
canvas.configure(yscrollcommand = scrollbar.set)
frame = Frame(canvas)
frame.pack(fill = "both", expand = True)
y=0
for i in range(50):
entry = Entry(frame)
entry.place(x=0,y=y)
y = entry.winfo_y() + entry.winfo_height() + 5
canvas.create_window((0, 0), window = frame, anchor = 'nw')
frame.update_idletasks()
canvas.configure(scrollregion = canvas.bbox("all"))
root.mainloop()

Edited:
I want to create a scrollable frame and add some widgets but I have a
problem, when I use entry.place() it doesn't show any entry.
You cannot used pack() and place() when doing looping for Entry widget.
Just use grid() for second frame.
In case, you want to use ttk module.
Code:
from tkinter import *
from tkinter import ttk
root = Tk()
root.title("Entry Widgets")
mainframe = ttk.Frame(root)
mainframe.pack(fill = "both", expand = True)
canvas = Canvas(mainframe)
canvas.pack(side = "left", fill = "both", expand = True)
scrollbar = ttk.Scrollbar(canvas, orient = "vertical", command = canvas.yview)
scrollbar.pack(side = "right", fill = "y")
canvas.configure(yscrollcommand = scrollbar.set)
frame = ttk.Frame(root)
frame.pack(fill = "both", expand = True)
for i in range(50):
entry = Entry(frame, width=50)
entry.grid(column=0,row=i+10)
canvas.create_window((0, 0), window = frame, anchor = 'nw')
frame.update_idletasks()
canvas.configure(scrollregion = canvas.bbox("all"))
root.mainloop()
Screenshot:

Related

Scrollbar of my app is working not correctly when content is large what must I do?

from tkinter import *
#Root
root = Tk()
root.title('A WINDOW')
#Frame
main_frame = Frame(root)
main_frame.pack(fill=BOTH, expand = True)
#Canvas
main_canvas = Canvas(main_frame)
main_canvas.pack(side = LEFT, fill = BOTH, expand = True)
#Scrollbar
scrollbar = Scrollbar(main_frame, orient = VERTICAL, command = main_canvas.yview)
scrollbar.pack(side = RIGHT, fill = 'y')
#Configure the Canvas
main_canvas.configure(yscrollcommand=scrollbar.set)
#Frame#2
Frame2 = Frame(main_canvas)
main_canvas.create_window((0, 0), window = Frame2, anchor = 'nw')
main_canvas.bind('<Configure>', lambda e :main_canvas.configure(scrollregion=main_canvas.bbox('all')))
for i in range(2000):
Button(Frame2, text = str(i)).grid(row = i, column = 0)
root.mainloop()
and when I execute the program, it works until the 1080th one then scrollbar moves but buttons don't go down anymore I hope you understood me and have an idea about what must I do...
This is a slight modification of your code. It demonstrates the limitation of the window object in tk.Canvas with a maximum height of 32768. It can be shown by changing variable offset to some arbitrary value and scrolling to the end of canvas. The last button will still be visible even though its position is 32768+offset.
Function bookmark finds frame2 in the window object and finds all objects in frame2 then changes background color. This makes it easy to confirm first and last buttons are visible.
import tkinter as tk
root = tk.Tk()
frame = tk.LabelFrame(root, labelanchor = tk.S, text = '0|0')
frame.grid(row = 0, column = 0, sticky = tk.NSEW)
for a in [root, frame]:
a.rowconfigure(0, weight = 1)
a.columnconfigure(0, weight = 1)
main_canvas = tk.Canvas(frame)
main_canvas.grid(row = 0, column = 0, sticky = tk.NSEW)
scrollbar = tk.Scrollbar(frame, orient = tk.VERTICAL, command = main_canvas.yview)
scrollbar.grid(row = 0, column = 1, sticky = tk.NS)
main_canvas.configure(yscrollcommand = scrollbar.set)
def location(event):
x, y = main_canvas.canvasx(event.x), main_canvas.canvasy(event.y)
frame['text'] = f'{x} | {y}'
# bind mouse
main_canvas.bind('<Motion>', location)
frame2 = tk.Frame(main_canvas)
# frame is positioned at offset
offset = 0
main_canvas.create_window(0, offset, window = frame2, anchor = tk.NW)
def bookends(x):
# Find reference to frame2
C = main_canvas.winfo_children()[0]
# find all objects in frame2
D = C.winfo_children()
print(len(D))
# change colors of first and last buttons
D[0]['background'] = 'red'
D[x]['background'] = 'red'
for i in range(2000):
tk.Button(
frame2,
text = str(i),
font = '{Courier New} 6',
padx=0, pady=0).grid(
row = i, column = 0, ipadx = 0, ipady = 0)
bookends(1999)
# main_canvas['scrollregion'] = f'0 0 40 {32768+offset}'
main_canvas.bind('<Configure>', lambda e :main_canvas.configure(scrollregion=main_canvas.bbox('all')))
root.mainloop()

Clearing a tkinter root.subform from within a separate function

I have several larger tkinter / python program which I would like to incorporate into one program which would clear a frame when another program is called; each program currently being inside a function (I probably should use classes eventually when I understand them) and each of these function being displayed on a form being cleared of widgets from the previous if any do exist.
The code below is just a small trial for me to understand how to do this, but it's not working.
When I invoke the widget.destroy() function, it removes the frame (DisplayFrame) and does not clear the widgets inside it and hence not displaying the new widgets.
here is the current trial code:
#!/usr/bin/env python3
import tkinter as tk
from tkinter import *
from tkinter import ttk
#import pandas as pd
import MultiTempsP3
import datetime, time
from tkinter import messagebox
import sqlite3
from tkinter import colorchooser
from configparser import ConfigParser
import os
import csv
if os.environ.get('DISPLAY','') == "":
print('no display found.Using :0.0')
os.environ.__setitem__('DISPLAY',':0.0')
root = tk.Tk()
root.title("Kombucha Program")
root.geometry("1400x800")
root.minsize(width=900, height=600)
#root.maxsize(width=1400, height = 900)
root.grid_rowconfigure(3, weight=1)
root.grid_columnconfigure(2, weight=1)
root.configure( bg = '#000080' )
DisplayFrame = tk.Frame(root, width=1200, height = 630, bg = 'yellow') #0059b3')
DisplayFrame.grid(column=0,row=1, sticky = N, in_ = root)
rightFrame = tk.Frame(root, width = 120, height = 390, bg = 'white') # #000080
rightFrame.grid(column = 1, row = 0, pady = 10, padx = 10)
lblFrame = tk.Frame(root, height = 70, width = 670, bg = 'black')
lblFrame.grid(column = 0, row = 0, sticky =N, in_ = root)
##'W' stands for West = WrightFrmae (west fframe on the right of screen
#WrightFrame = tk.Frame(rightFrame, width = 70, height = 300, bg = 'green') # #000080
#WrightFrame.grid(column = 0, row = 1)
WidgetFrame = tk.Frame(root, height = 300, width = 120, bg = 'red') # #000080
WidgetFrame.grid(column=0,row=2, pady = 30)
fromTemp = MultiTempsP3.temps("65cd6bd")
lblTemp = Label(rightFrame, text=fromTemp).grid(row=1,column=0,pady=0 )
#lblTemp.pack()
def clearDisplayFrame():
for widgets in DisplayFrame.winfo_children():
widgets.destroy()
###***### - This section is in the right top little frame = rightFrame
state = "yes" ## delete this row and use below state=GPIO when on an RPi
#state = GPIO.input(17)
if state:
state_17="GPIO_17 (HeatPad) is On "
else:
state_17="GPIO_17 (HeatPad) is Off "
lblHeatPad = Label(rightFrame, text=state).grid(row=3,column=0,pady=0 ) #shows as text in the window
#lblHeatPad.pack() #organizes widgets in blocks before placing them in the parent.
###***### End of rightFrame widgets
def func_quit():
root.destroy()
def openData():
clearDisplayFrame()
print("I am inside openData()")
lbltrial=tk.Label(DisplayFrame,text="trial").grid(row=3, column=2)
def func_Temps():
clearDisplayFrame()
print("I am inside func_Temps()")
#DisplayFrame = tk.Frame(root, width=1200, height = 630, bg = 'yellow') #0059b3')
#DisplayFrame.grid(column=0,row=1, sticky = N, in_ = root)
lblSomething = tk.Label(DisplayFrame, text = "Open Temps").grid(row=2,column=2)
###***### This section is top of left = lblFrame
exitButton = tk.Button(lblFrame, text="Quit the Program", width = 12, command=root.destroy, bg= "magenta")
exitButton.grid(row = 0, column = 0, columnspan = 1, pady = 5, padx = 5)
dataButton = Button(lblFrame, text="Open Dates Window", command=openData).grid(row=0, column=1) ## the open refers to the above function
tempsButton= Button(lblFrame, text="Open Temps Info", command=func_Temps).grid(row=0, column=2)
###***### End of top left widget in lblFrame
mainloop()
As an answer, here is an approach that uses 2 frame and switches between them in the click of the switch. This is the way usually switching between frame is implemented in procedural programming, AFAIK:
from tkinter import *
root = Tk()
def change(frame):
frame.tkraise() # Raising the passed frame
window1 = Frame(root)
window2 = Frame(root)
window1.grid(row=0,column=0) # Grid in the same location so one will cover/hide the other
window2.grid(row=0,column=0)
# Contents inside your frame...
Label(window1,text='This is page 1',font=(0,21)).pack()
Label(window2,text='This is page 2',font=(0,21)).pack()
# Buttons to switch between frame by passing the frame as an argument
Button(root,text='Page 1',command=lambda: change(window1)).grid(row=1,column=0,stick='w')
Button(root,text='Page 2',command=lambda: change(window2)).grid(row=1,column=0,stick='e')
root.mainloop()
So instead of destroying all the items inside your frame, you should just raise the other frame, as destroyed widgets cannot be brought back.

Create scrollbar in tKinter without displacing widgets to the left (python)

I'm creating a program by learning from youtube tutorials (I'm a complete beginner) and I have come to some difficulties. This time, I'm trying to create a scrollbar, and I want my widgets to stay on the center of my window, not the left (I'm following the Codemy.com tutorial on scrollbars).
Here is the current aspect of my program:
with scrollbar
And here is how I want it to look:
without scrollbar
This is my code right now:
import tkinter as tk
root = tk.Tk()
root.geometry("600x400")
my_canvas = tk.Canvas(root)
my_canvas.pack(side = "left", fill = "both", expand = 1)
my_scrollbar = tk.Scrollbar(root, orient = "vertical", command = my_canvas.yview)
my_scrollbar.pack(side = "right", fill = "y")
my_canvas.configure(yscrollcommand = my_scrollbar.set)
my_canvas.bind("<Configure>", lambda e: my_canvas.configure(scrollregion = my_canvas.bbox("all")))
my_frame = tk.Frame(my_canvas)
for i in range(100):
my_label = tk.Label(my_frame, text = "Label")
my_label.pack()
my_canvas.create_window((0,0), window = my_frame, anchor = "nw")
root.mainloop()
Include width = 600, anchor = "nw" in my_canvas declaration.
my_canvas.create_window((0,0), window = my_frame, width = 600, anchor = "nw")

Why isn't this frame in tkinter centered correctly?

I want this entry bar and other contents I'll add to the frame later to be centred correctly, I received this code that supposedly should work but it isn't.
import tkinter as tk
import math
import time
root = tk.Tk()
root.geometry()
root.attributes("-fullscreen", True)
exit_button = tk.Button(root, text = "Exit", command = root.destroy)
exit_button.place(x=1506, y=0)
frame = tk.Frame(root)
main_entry = tk.Entry(root, width = 100, fg = "black")
main_entry.place(x=50, y=50)
frame.place(relx=.5,rely=.5, anchor='center')
root.mainloop()
As you can see the frame isn't centred so how can I fix this?
In order to achieve widget centering on a fullscreen I've had to use grid manager.
The code below works but the exact positioning requires some fiddling with frame padding.
frame padx = w/2-300 and pady = h/2-45 are arbitrary values found using a bit of trial and error.
import tkinter as tk
root = tk.Tk()
root.attributes( '-fullscreen', True )
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
frame = tk.Frame( root )
main_entry = tk.Entry( frame, width = 100 )
main_entry.grid( row = 0, column = 0, sticky = tk.NSEW )
frame.grid( row = 0, column = 0, padx = w/2-300, pady = h/2-45, sticky = tk.NSEW )
exit_button = tk.Button( frame, text = 'Exit', command = root.destroy )
exit_button.grid( row = 1, column = 0, sticky = tk.NSEW )
tk.mainloop()
Frame automatically changes size to size of objects inside Frame (when you use pack()) but you have nothing inside Frame. You put all widgets directly in root - so Frame has no size (width zero, height zero) and it is not visible.
When I use tk.Frame(root, bg='red', width=100, height=100) then I see small red frame in the center.
You have two problems:
(1) you put Entry in wrong parent - it has to be frame instead of root,
(2) you use place() which doesn't resize Frame to its children and it has size zero - so you don't see it. You would have to set size of Frame manully (ie. tk.Frame(..., width=100, height=100)) or you could use pack() and it will resize it automatically.
I add colors for backgrounds to see widgets. blue for window and red for frame.
import tkinter as tk
root = tk.Tk()
root['bg'] = 'blue'
root.attributes("-fullscreen", True)
exit_button = tk.Button(root, text="Exit", command=root.destroy)
exit_button.place(x=1506, y=0)
frame = tk.Frame(root, bg='red')
frame.place(relx=.5, rely=.5, anchor='center')
main_entry = tk.Entry(frame, width=100, fg="black")
main_entry.pack(padx=50, pady=50) # with external margins 50
root.mainloop()

Tkinter scrollbar not scrollable

I followed some tutorial on attaching a scrollbar to a textbox. However, in the tutorial, the scrollbar is really a "bar". When I tried myself, I can only press the arrows to move up or down, the middle part is not movable. May I know what I did wrong?
import tkinter as tk
root = tk.Tk()
scroll = tk.Scrollbar(root)
scroll.grid(row = 0, column = 1)
message = tk.Text(root, yscrollcommand = scroll.set, height = 25, width = 60)
message.grid(row = 0, column = 0)
for i in range(50):
message.insert(tk.END, f'This is line {i}\n')
scroll.config(command = message.yview)
root.mainloop()
You just have to add sticky='nsew' to Scrollbar widget.
sticky='nsew' will make the Scrollbar widget to expand to fill up the entire cell (at grid position row=0 & column=1) at every side (n-north, s-south, e-east, w-west)
Here is the code:
import tkinter as tk
root = tk.Tk()
scroll = tk.Scrollbar(root)
# add sticky option to the Scrollbar widget
scroll.grid(row = 0, column = 1, sticky='nsew')
message = tk.Text(root, yscrollcommand = scroll.set, height = 25, width = 60)
message.grid(row = 0, column = 0)
for i in range(50):
message.insert(tk.END, f'This is line {i}\n')
scroll.config(command = message.yview)
root.mainloop()

Categories

Resources