Python: Why doesn't my scrollbar show up using Tkinter? - python

Here is a snipet of my code:
dialog_canvas = Canvas(dialog_frame, scrollregion = (0, 0, 450, 265), bg = 'white')
dialog_canvas.pack(expand = YES, fill = BOTH, side = LEFT)
yscroll = ttk.Scrollbar(root, orient = VERTICAL, command = dialog_canvas.yview)
dialog_canvas.config(yscrollcommand = yscroll.set)
yscroll.grid(row = 1, column = 1, sticky = 'ns')

Related

How to reduce excess distance between a label and another label through tkinter grid

I am making an F1 drivers' application, which gathers API data. The application has designated labels for where specific API content needs to be placed.
What's happening is that whenever I put anything beside a designated label through .grid, the distance between whatever I put and the label is too big. A perfect example of this is in the bottom_left_frame. I've tried different ways (i.e, sticky, padding), but no luck. One way that seems to work is .configure(), but I don't think it's a scalable solution, and I want to place my objects through .grid()
Here's the code. Would appreciate the help!
#import necessary modules
from tkinter import *
from tkinter import ttk
from PIL import ImageTk, Image
from tkinter import messagebox
import requests
import json
root = Tk()
root.title("F1 Desktop Application")
root.geometry("500x600")
root.configure(bg="white")
#NEED TO UNDERSTAND PRECEDENCE BETWEEN WIDTH, HEIGHT SETTING, VS SPANS. STICKY MAKES PERFECT SENSE
top_frame = LabelFrame(root, width = 300, height = 125)
top_frame.grid(row = 0, column = 0, columnspan = 2)
top_frame.rowconfigure(0, minsize = 75)
top_frame.columnconfigure(0, minsize = 300)
header_label = Label(top_frame, text = "F1 2022 Drivers App", font = ("Arial bold",14), bg = "white")
header_label.grid(row = 0, column = 0)
entry= Entry(top_frame)
entry.grid(row = 1, column = 0)
#search_button = Button(top_frame, text = "search")
#search_button.grid(row = 1, column = 1)
left_frame = LabelFrame(root, width = 250, height = 225, borderwidth = 0, highlightthickness = 2)
left_frame.grid(row = 1, column = 0, sticky = NW, padx = 10, pady = 15)
#left_frame.grid_propagate(False)
left_frame.rowconfigure(0, minsize = 100)
left_frame.columnconfigure(0, minsize = 200)
#left_frame_content = LabelFrame(, width = 125, height = 70)
#left_frame_content.grid(row = 1, column = 1, sticky = W)
basic_info = Label(left_frame, text = "Basic Info ", font = ("Arial bold",14))
basic_info.grid(row = 0, column = 0)
full_name = Label(left_frame, text = "Full Name :")
full_name.grid(row = 1, column = 0, sticky = W)
driver_code = Label(left_frame, text = "Driver Code : ")
driver_code.grid(row = 2, column = 0, sticky = W)
nationality = Label(left_frame, text = "Nationality : ")
nationality.grid(row = 3, column = 0, sticky = W)
bottom_left_frame = LabelFrame(root, width = 250, height = 225)
bottom_left_frame.grid(row = 2, column = 0, sticky = N, padx = 10)
bottom_left_frame.rowconfigure(0, minsize = 25)
bottom_left_frame.columnconfigure(0, minsize = 200)
F1_career = Label(bottom_left_frame, text = "F1 Career ", font = ("Arial bold",14))
F1_career.grid(row = 0, column = 0)
wins = Label(bottom_left_frame, text = "Wins :")
wins.grid(row = 1, column = 0, sticky = W)
wins.configure(text = "Wins :" + " 7")
poles = Label(bottom_left_frame, text = "Poles :")
poles.grid(row = 2, column = 0, sticky = W)
test = Label(bottom_left_frame, text = "test")
test.grid(row = 2, column = 1)
podiums = Label(bottom_left_frame, text = "Podiums :")
podiums.grid(row = 3, column = 0, sticky = W)
drivers_championships = Label(bottom_left_frame, text = "Championships :")
drivers_championships.grid(row = 4, column = 0, sticky = W)
bottom_right_frame = LabelFrame(root, width = 250, height = 225)
bottom_right_frame.grid(row = 2, column = 1, sticky = W)
bottom_left_frame.rowconfigure(0, minsize = 50)
bottom_left_frame.columnconfigure(0, minsize = 150)
root.mainloop()

Create event log list from tkinter button presses

This is my first venture into tkinter programming, so far I have the following code that increases or decreases a number by pressing either button. As you may notice I have started adding an update definition that I'd like to update a results table with the label value each time a button is pressed. I've recently found the lambda expression to add two commands to each button press but can't find an example to build the list:
import tkinter as tk
window = tk.Tk()
def increase():
value = int(lbl_value["text"])
lbl_value["text"] = f"{value + 1}"
def decrease():
value = int(lbl_value["text"])
lbl_value["text"] = f"{value - 1}"
def update():
result_table = []
window.rowconfigure(0, minsize = 100, weight = 1)
window.columnconfigure([0,1,2], minsize = 100, weight = 1)
btn_decrease = tk.Button(master = window, text = "-", command = lambda:[decrease(), update()], bg = 'red', fg = 'white')
btn_decrease.grid(row = 0, column = 0, sticky = "nsew")
lbl_value = tk.Label(master = window, text = "0")
lbl_value.grid(row = 0, column = 1)
btn_increase = tk.Button(master = window, text = "+", command = lambda:[increase(), update()], bg = 'green', fg = 'white')
btn_increase.grid(row = 0, column = 2, sticky = "nsew")
window.mainloop()
, bg = 'black', fg = 'white')
btn_decrease.grid(row = 0, column = 0, sticky = "nsew")
lbl_value = tk.Label(master = window, text = "0")
lbl_value.grid(row = 0, column = 1)
btn_increase = tk.Button(master = window, text = "+", command = increase, bg = 'red', fg = 'white')
btn_increase.grid(row = 0, column = 2, sticky = "nsew")
window.mainloop()
I'd like to add a graph of the count to the display ultimately. Any help greatly appreciated.
Matt

Adding scrollbar widget to Tkinter GUI results in errors

I have written the following code to get the user input. But I am not able to add a scrollbar to it. I want to place a vertical scrollbar because I am not able to view all the input labels on my screen.
I first tried:
v = Scrollbar(root, orient='vertical')
v.config(command=root.yview)
It gave me the following error:
File "/Users/aaditya/Desktop/Blender_software/Blender_algo_exp/testing.py", line 235, in <module>
label1.grid(row = 1, column = 0, padx = 10, pady = 10)
File "/opt/anaconda3/envs/blender_env/lib/python3.9/tkinter/__init__.py", line 2486, in grid_configure
self.tk.call(
_tkinter.TclError: cannot use geometry manager grid inside . which already has slaves managed by pack
After that I tried the following:
myscroll = Scrollbar(root)
myscroll.pack(side = RIGHT, fill = Y)
Which resulted in the following error:
AttributeError: '_tkinter.tkapp' object has no attribute 'yview'
How can I fix this?
This is my entire code:
# Driver code
if __name__ == "__main__" :
root = Tk()
# v = Scrollbar(root, orient='vertical')
# v.config(command=root.yview)
# myscroll = Scrollbar(root)
# myscroll.pack(side = RIGHT, fill = Y)
root.configure(background = 'light gray')
root.geometry("700x700")
root.title("Blender Software")
label1 = Label(root, text = "Total Quantity: ",
fg = 'black', bg = 'white')
label2 = Label(root, text = "Percentage of Solid Scrap : ",
fg = 'black', bg = 'white')
label3 = Label(root, text = "Cr min : ",
fg = 'black', bg = 'white')
label4 = Label(root, text = "Cr max : ",
fg = 'black', bg = 'white')
label1.grid(row = 1, column = 0, padx = 10, pady = 10)
label2.grid(row = 2, column = 0, padx = 10, pady = 10)
label3.grid(row = 3, column = 0, padx = 10, pady = 10)
label4.grid(row = 4, column = 0, padx = 10, pady = 10)
# Create a entry box
# for filling or typing the information.
total_quantity = Entry(root)
per_solid_scrap = Entry(root)
Cr_min_input = Entry(root)
Cr_max_input = Entry(root)
# grid method is used for placing
# the widgets at respective positions
# in table like structure .
total_quantity.grid(row = 1, column = 1, padx = 10, pady = 10)
per_solid_scrap.grid(row = 2, column = 1, padx = 10, pady = 10)
Cr_min_input.grid(row = 3, column = 1, padx = 10, pady = 10)
Cr_max_input.grid(row = 4, column = 1, padx = 10, pady = 10)
button1 = Button(root, text = "Submit", bg = "red",
fg = "black", command = calculate_op)
button1.grid(row = 21, column = 1, pady = 10)
# Start the GUI
root.mainloop()
Pack and grid cannot be used at the same time. So since you called the pack for the scrollbar, you cannot manage the following widgets by grid anymore. An easy fix is to place the scrollbar with grid function instead. Apart from that, try using a function or class to make your code less lengthy because now it seems hard to read and purposeless.

How to prevent the widgets inside text from moving beyond the boundary? Tkinter

I have a Text widget in which there are a stack of widgets inserted as a window. Whenever I scroll, the widgets move beyond the Text boundaries until their end crosses over. Here is a sample code that produces a similar symptom.
from tkinter import *
root = Tk()
inst_frame = Frame(root, highlightthickness = 1, highlightbackground = 'black', bg = 'white')
inst_frame.pack(padx = 10, pady = (0,10), side = 'bottom', anchor = 'w')
lab = Label(inst_frame, text = 'Stack of widgets', bg = 'RoyalBlue', font = ('Roboto', 12), fg = 'white')
lab.pack(side = 'top', anchor = 'nw', fill = 'x', pady = (0,10))
disp_inst_frame = Frame(inst_frame, bg = 'white')
disp_inst_frame.pack(side = 'bottom', fill = 'both')
inst_text_frame = Frame(disp_inst_frame, width = 820, height = 200, bg = 'white')
inst_text_frame.pack(side = 'left', expand = False, fill = 'x')
inst_text_frame.pack_propagate(False)
inst_text = Text(inst_text_frame, font = ('Roboto', 12), wrap = 'word', bd = 0)
inst_vsb = Scrollbar(disp_inst_frame, command = inst_text.yview)
inst_text.configure(yscrollcommand = inst_vsb.set)
inst_text.pack(padx = 10, pady = (0, 10), fill = 'x')
inst_vsb.pack(side = 'right', fill = 'y', padx = (0, 10), pady = (0, 10))
for _ in range(0, 5): #Inserts blank frames
sample_frame = Frame(inst_frame, height = 100, width = 500, bg = 'black')
inst_text.window_create(END, window = sample_frame)
inst_text.insert(END, '\n'*5)
root.mainloop()
Here one can notice that the sample_frames that were inserted move beyond the bounds when scrolled.
Any help would be greatly appreciated.
Use:
sample_frame = Frame(inst_text, height = 100, width = 500, bg = 'black') # inst_text instead of inst_frame

Why canvas not scrolling with scrollbar and auto resizing when adding widgets?

When i put widgets inside my canvas, the widgets bypass the canvas size. But when I scroll, the canvas won't move.
On top of that, the canvas auto re-sizes when I add more widgets. I thought the canvas isn't supposed to re-size because I already added a scroll bar?
Here's my code:
from tkinter import *
from tkinter import ttk
import mysql.connector
class CanvasScroll:
def on_resize(self,event):
self.canvas.config(width = 1185, height = 530)
def add_crew(self):
crewFrame = CrewFrame()
def callback_list(self):
index = self.notebook.index(self.notebook.select()) + 1
self.tmpframe = Try2(self.contentframe, index)
def __init__(self, master):
self.canvas = Canvas(master, width = 1185, height = 530, scrollregion = (0, 0, 1216, 700), bg = 'white', confine = True)
self.canvas.grid(row = 2, column = 0, sticky = 'news')
self.xscroll = ttk.Scrollbar(master, orient = HORIZONTAL, command = self.canvas.xview)
self.xscroll.grid(row = 3, column = 0, sticky = 'we')
self.yscroll = ttk.Scrollbar(master, orient = VERTICAL, command = self.canvas.yview)
self.yscroll.grid(row = 2, column = 1, sticky = 'ns')
self.canvas.config(xscrollcommand = self.xscroll.set, yscrollcommand = self.yscroll.set)
self.canvas.bind("<Configure>", self.on_resize)
self.option = ttk.Frame(master, height = 150, width = 1206)
self.option.grid(row = 0, column = 0, sticky = 'we', columnspan = 5)
self.addicon = PhotoImage(file = 'C:\\Users\\rain\\Desktop\\Fyosh!\\logo\\add.gif').subsample(2,2)
self.btnAdd = ttk.Button(self.option, image = self.addicon, text = 'Add Crew', compound = TOP, command = self.add_crew)
self.btnAdd.grid(row = 0, column = 0, padx = 50, pady = 5)
self.updateicon = PhotoImage(file = 'C:\\Users\\rain\\Desktop\\Fyosh!\\logo\\update.gif').subsample(2,2)
self.btnUpdate = ttk.Button(self.option, image = self.updateicon, text = 'Update Crew', compound = TOP)
self.btnUpdate.grid(row = 0, column = 1, padx = 50)
self.deleteicon = PhotoImage(file = 'C:\\Users\\rain\\Desktop\\Fyosh!\\logo\\delete.gif').subsample(2,2)
self.btnDelete = ttk.Button(self.option, image = self.deleteicon, text = 'Delete Crew', compound = TOP)
self.btnDelete.grid(row = 0, column = 2, padx = 50)
self.reloadicon = PhotoImage(file = 'C:\\Users\\rain\\Desktop\\Fyosh!\\logo\\Refresh.png').subsample(7,7)
self.reloadbtn = ttk.Button(self.option, image = self.reloadicon, command = self.callback_list, text = 'Load List', compound = TOP)
self.reloadbtn.grid(row = 0, column = 3, padx = 50)
self.tabframe = ttk.Frame(master, height = 20)
self.tabframe.grid(row = 1, sticky = 'we')
self.notebook = ttk.Notebook(self.tabframe)
self.notebook.grid(row = 0, column = 0, sticky = 'we')
db = mysql.connector.connect(user = 'root', password = '', host = 'localhost', database = 'fat2x_payroll')
cursor = db.cursor()
ships = ("SELECT * from tbl_shiplist")
try:
cursor.execute(ships)
result = cursor.fetchall()
self.tab = {}
for row in result:
self.tab[row[0]] = {
"shipname": ttk.Frame(self.notebook)
}
self.notebook.add(self.tab[row[0]]["shipname"], text = row[1])
db.close()
except:
messagebox.showinfo("alert", "ship list error")
self.canvas.label = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 0)
self.canvas.label1 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 1)
self.canvas.label2 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 2)
self.canvas.label3 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 3)
self.canvas.label4 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 4)
self.canvas.label5 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 5)
self.canvas.label6 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 6)
self.canvas.label7 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 7)
self.canvas.label8 = ttk.Label(self.canvas, text = "hahahahahha").grid(column = 8)
def start():
master = Tk()
master.geometry("1206x690+10+10")
master.resizable(0,0)
master.title("Crew Panel")
canvasScroll = CanvasScroll(master)
if __name__ == "__main__":
start()
The canvas can only scroll objects that are embedded on the canvas. In the case of widgets, that means that you've called the create_window method of the canvas for the widgets you want to be affected by the scrollbar.
If you want to use grid to organize widgets, and you want those widgets to be in a scrollable container, the usual method is to put those widgets inside a frame, and then add the frame to the canvas with create_window. You can see an example of this technique in this answer: https://stackoverflow.com/a/3092341/7432
As for the auto-resize, this behavior is completely unrelated to using a scrollbar. If you use grid or pack on a widget, the parent will always resize unless you've turned geometry propagation off. It doesn't matter if it's a Canvas or a Frame or a Toplevel, or any other class of widget.

Categories