Scrollbar in Tkinter not moveable - python-3.x

I'm in the beginning stages of building a program where I can take items from a TreeView and move them into a listbox. I have added scrollbars to both the Treeview and listbox so that as they get longer, I can scroll to see the contents. Currently, I have populated the Treeview with more items than can fit in the window. I have the ability to scroll the Treeview with the mouse wheel, but when I click and drag the box on the scrollbar, the scrollbar will not move. I'm using Python 3.7. I could use some help figuring out what's going on.
import tkinter as tk
from tkinter import ttk
import l5x
root = tk.Tk()
root.geometry("600x400")
root.resizable(False, False)
root.title("TreeView Example")
tree_frame = ttk.Frame(root)
list_frame = ttk.Frame(root)
tree = ttk.Treeview(tree_frame)
tree_scroll = ttk.Scrollbar(tree_frame,orient="vertical",command=tree.yview())
tree.configure(yscrollcommand=tree_scroll.set)
listbox = tk.Listbox(tree_frame)
list_scroll = ttk.Scrollbar(tree_frame,orient="vertical",command=listbox.yview())
listbox.configure(yscrollcommand=list_scroll.set)
tree_frame.columnconfigure(0, weight=1)
tree_frame.columnconfigure(1, weight=1)
tree_frame.columnconfigure(2, weight=1)
tree_frame.columnconfigure(3, weight=1)
for i in range(0,20):
tree.insert('','end',i,text="blah")
tree_frame.grid(row=0,column=0,sticky="NSEW")
tree.grid(row=0,column=0,sticky="NSEW")
tree_scroll.grid(row=0,column=1,sticky="NS")
listbox.grid(row=0,column=2,sticky="NSEW")
list_scroll.grid(row=0,column=3,sticky="NS")
root.mainloop()

The command attribute requires you pass a reference to a callable function. Instead, you're calling the yview() method and giving the results to the command attribute.
Your scrollbar definition needs to look like this:
tree_scroll = ttk.Scrollbar(tree_frame,orient="vertical",command=tree.yview)
list_scroll = ttk.Scrollbar(tree_frame,orient="vertical",command=listbox.yview)

Related

Tkinter - How to understand when the cursor is placed over a text widget?

I would very like to do something when the mouse cursor is placed over a TK Text widget (without clicking). How can I get this event?
Tkinter fires the <Enter> event with the cursor enters a widget, and <Leave> when it leaves.
import tkinter as tk
def handle_enter(event):
event.widget.insert("end", "Cursor has entered the chat\n")
def handle_leave(event):
event.widget.insert("end", "Cursor has left the chat\n")
root = tk.Tk()
text = tk.Text(root)
text.pack(fill="both", expand=True)
text.bind("<Enter>", handle_enter)
text.bind("<Leave>", handle_leave)
root.mainloop()
Try the following code. It is a quick snippet:
#Import the tkinter library
from tkinter import *
from tkinter.tix import *
#Create an instance of tkinter frame
win = Tk()
#Set the geometry
win.geometry("400x200")
#Create a tooltip
tip= Balloon(win)
#Create a Button widget
my_button=Button(win, text= "Python", font=('Poppins', 20))
my_button.pack(pady=20)
#Bind the tooltip with button
tip.bind_widget(my_button,balloonmsg="Python is an interpreted, high-level
and general-purpose programming language")
win.mainloop()

Tkinter widget positioning inside frame

I am trying to position my buttons using the grid manager, by altering the column and row arguments of the .grid() function. However, whenever I input values > 1, there seems to be no change in position of my widgets. Why is this?
import tkinter as tk
window = tk.Tk()
window.geometry("500x500")
window.rowconfigure(0,weight=1)
window.columnconfigure(0,weight=1)
f1 = tk.Frame(window,bg="black")
f1.grid(row=0,column=0,sticky="nsew")
btn1 = tk.Button(f1,text="button")
btn1.grid(row=0,column=0,padx=5,pady=5)
lbl = tk.Label(f1,text="label")
lbl.grid(row=3,column=3)
window.mainloop()

How to use .grid with a scrollbar in a tkinter window?

I have a tkinter window with several images that use grid. I tried to grid a scrollbar to the right side of the window but don't know what options to use because "side = right", "fill = Y" cannot be used inside grid. Any suggestions?
Grid is row / column oriented. So each widget needs its row and column in the geometry manager set. Here is a demo that answers the question posed.
# create a widget and scrollbar
import tkinter as tk
root = tk.Tk()
text = tk.Text(root)
vs = tk.Scrollbar(root, command=text.yview)
text.configure(yscrollcommand=vs.set)
# set the row, column and expansion for each widget
text.grid(row=0, column=0, sticky='news')
vs.grid(row=0, column=1, sticky='news')
# now make the grid manager expand to fill the available space in root.
# making 0, 0 expand to use all the spare space and 0,1 be fixed
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
If you are managing a set of images on label widgets then put them in a frame to separate out the geometry management of those. You might want to consider if you should
put them into a canvas instead which has quite good scrolling support.

Why the tkinter window does not open when using the method "grid()"?

from tkinter import *
# ==================================================Settings=======================================================
root = Tk()
root.title("Video Youtube Downloader") # set up the title and size.
root.configure(background='black') # set up background.
root.minsize(800, 500)
root.maxsize(800, 500)
# ==================================================Frames=======================================================
top = Frame(root, width=800, height=50, bg='yellow').pack(side=TOP)
bottom = Frame(root, width=800, height=50, bg='red').pack(side=BOTTOM)
left = Frame(root, width=550, height=450, bg='black').pack(side=LEFT)
right = Frame(root, width=250, height=450, bg='blue').pack(side=RIGHT)
# ==================================================Buttons=======================================================
btn_clear_url = Button(right, text="Clear Url", font=('arial', 10, 'bold')).grid(row=1, columns=1)
I am trying to add buttons to the right Frame, but for some reason when I run the program the IDE shows that it is running but there is
no window. When I delete .grid(row=1, columns=1) the window appears.
How can I fix this bug, and add btn_clear_url button to the right Frame?
First of all, you need to invoke Tk's mainloop at the end of your code (you can see here why).
Another problem is chaining method calls like that. You're actually assigning return value of the last call to the variable, which is None in case of grid() and pack() - therefore, all your variables end up having None as the value. You need to separate widget instantiating call and grid or pack call and put each on its own line.
Other than that, you're setting both minsize and maxsize to the very same size - if you're really just trying to make your window not resizable, set the size with:
root.geometry('800x500') # for instance
...and after that configure resizable attribute:
root.resizable(width=False, height=False)
Also, I suggest you get rid of from tkinter import *, since you don't know what names that imports. It can replace names you imported earlier, and it makes it very difficult to tell where names in your program are supposed to come from. Use import tkinter as tk instead.
When you place widget in a tk window you cannot use grid and pack at the same time in the same window, so you use should use pack () instead of grid()
The problem starts with this line of code:
right = Frame(root, width=250, height=450, bg='blue').pack(side=RIGHT)
With that, right is set to None because .pack(side=RIGHT) returns None.
Next, you do this:
btn_clear_url = Button(right, ...)).grid(row=1, columns=1)
Because right is None, it's the same as Button(root, ...). Since you are already using pack for a widget in root, you can't also use grid.
The solution -- and best practice -- is to separate widget creation from widget layout:
top = Frame(root, width=800, height=50, bg='yellow')
bottom = Frame(root, width=800, height=50, bg='red')
left = Frame(root, width=550, height=450, bg='black')
right = Frame(root, width=250, height=450, bg='blue')
top.pack(side=TOP)
bottom.pack(side=BOTTOM)
left.pack(side=LEFT)
right.pack(side=RIGHT)
With the above, right will be properly set to the frame instance, and adding a widget to right and using grid will no longer fail.

Scrollbar on canvas

I'm currently trying to implement a scrollbar on a canvas, since I learned that I can't do it instantly on a frame. I can make it appear, but I cannot actually make it work. I'm still a beginner when it comes to python and tkinter and the previous posts in this matter haven't helped me that much. Here's my code(I'm open to advice on anything else I've done that's considered bad practice as well):
from tkinter import *
class myApp():
def __init__(self,root):
myApp.f2=Frame(root)
myApp.f2.pack()
myApp.canv=Canvas(self.f2)
myApp.canv.pack()
myApp.f1=Frame(self.canv)
myApp.f1.pack(side=LEFT, fill=BOTH, expand=TRUE)
myApp.scroll=Scrollbar(self.f1,orient=VERTICAL,
command=myApp.canv.yview)
myApp.scroll.grid(row=0,column=6)
myApp.canv.config(yscrollcommand=myApp.scroll.set)
I have to use grid for the rest of the widgets, that I haven't included here.
i don't really understand how the bind works, but here's the code i use for a scrollbar in a Toplevel, it's not from me but i don't remember where i found it (i think it's on stackoverflow, you should search more, i'm sure you will find something). it should work but you can scroll the bar only if you hover it with the mouse though
Toplevel = tk.Toplevel(self)
#create canvas to make a scrollbar
canvas = tk.Canvas(Toplevel, borderwidth=0)
#create frame which will contains your widgets
frame = tk.Frame(canvas)
#create and pack your vsb to the Toplevel and link it to the canvas yview
vsb = tk.Scrollbar(Toplevel, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)
vsb.pack(side="right", fill="y")
canvas.pack(side="left", fill="both", expand=True)
canvas.create_window((5,5), window=frame, anchor="nw")
#i don't understand this line
frame.bind("<Configure>", lambda event, canvas=canvas: canvas.configure(scrollregion=canvas.bbox("all")))
#add your widgets to the frame
...
PS : Don't use from tkinter import * you can(and will) have name collisions, use import tkinter or import tkinter as tk
Edit : this question is my source.

Resources