Tkinter scrollbar not scrollable - python

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()

Related

Tkinter Scrollbar - Problem allways maximized

I have a problem that I could not solve, thanks to many of you I was able to order the tree with the scrollbar, the problem now is that the scrollbar is always maximized, it does not calculate the amount of data that is inside.
frame = customtkinter.CTkFrame(self.wind, corner_radius=5)
frame.pack(expand="true")
button_llegue = customtkinter.CTkButton(master=frame, corner_radius=8,fg_color="IndianRed3",hover_color="IndianRed4", text='Llegue',command=self.add_fecha)
button_llegue.grid(row = 0, column = 0,pady=(20,10),padx=(15,15))
button_sali = customtkinter.CTkButton(master=frame, corner_radius=8,fg_color="PaleGreen3",hover_color="PaleGreen4", text='Me Voy',command=self.add_fecha)
button_sali.grid(row = 0, column = 1,pady=(20,10),padx=(15,15))
self.tree = ttk.Treeview(master=frame,height = 10, selectmode="browse")
self.tree.grid(row = 1,column=0,pady=(10,20),columnspan=2,sticky="NWSE",padx=(15,15))
self.tree.heading('#0', text = 'Ultimos registros', anchor = CENTER)
scrollbar = ttk.Scrollbar(frame,orient='vertical',command=self.tree.yview)
scrollbar.grid(row = 1, column=0, sticky="NSE",pady=(10,20),columnspan=2,padx=(0,15))
self.get_fechas()
Using command=self.tree.yview you send information from scrollbar to treeview - and it will scroll treeview when you will move scrollbar.
But you need also
self.tree.config(yscrollcommand=scrollbar.set)
to send information from treeview to scrollbar - and it will change size and position of scrollbar when you will add elements to treeview or when you will scroll treeview directly (using mouse wheel).
Minimal working code
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
tree = ttk.Treeview(root, selectmode="browse")
tree.pack(side='left', fill='both', expand=True)
scrollbar = tk.Scrollbar(root, orient='vertical', command=tree.yview)
scrollbar.pack(side='right', fill='y')
tree.config(yscrollcommand=scrollbar.set)
for x in range(1, 21):
print(tree.insert('', 'end', text=str(x)))
root.mainloop()

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")

How to print the value entered in entry widget into canvas

I want to read an input from entry widget and display it in canvas on clicking the button.I created a canvas and I tried this code
entryval= Tkinter.Entry(framename)
entryval.pack()
button = Tkinter.Button(entryframe, text ="Enter",command=print)
button.pack()
def print()
print entryval.get
But result is displaying only in terminal.not in canvas.
Please help.Thanks in advance
Here's a quick demo I made to help printing text to canvas:
from Tkinter import *
window = Tk()
def printVal():
canvas = Canvas(window, width = 100, height = 100)
canvas.grid(row = 0, column = 0, columnspan = 2)
string = entryval.get()
canvas.create_text(50,50, text = string)
entryval = Entry(window)
entryval.grid(row = 1, column = 0)
button = Button(window, text = "Print", command = printVal)
button.grid(row = 1, column = 1)
window.mainloop()

Categories

Resources