Scrollbars Tkinter - python

I have two listboxes one next to the other and I want each of them to have horizontal and vertical scrollbars. I have managed to create them, but when I press the arraws on the scrollbars, nothing happens, and I cannot see the entire content.
This is the code I have so far:
from Tkinter import *
root = Tk()
frame4 = Frame(root)
frame4.grid(row=2,columnspan=2,sticky=E+W)
l5 = Label(frame4, text='Output:').grid(row=0,columnspan=2)
frame5 = Frame(frame4)
frame5.grid(row=1,column=0,sticky=E+W)
l6 = Label(frame5, text='Algo1:').pack()
yscroll1 = Scrollbar(frame5, orient=VERTICAL)
xscroll1 = Scrollbar(frame5, orient=HORIZONTAL)
output_algo = Listbox(frame5,height=5, width=40)
output_algo.config (yscrollcommand=xscroll1.set)
output_algo.config (yscrollcommand=yscroll1.set)
yscroll1.config (command=output_algo.yview)
xscroll1.config (command=output_algo.yview)
yscroll1.pack(side=RIGHT, fill=Y,expand=0)
xscroll1.pack(side=BOTTOM, fill=X,expand=0)
output_algo.pack(side=LEFT,fill=BOTH,expand=1)
frame6 = Frame(frame4)
frame6.grid(row=1,column=1,sticky=E+W)
l7 = Label(frame6, text='Algo2:').pack()
yscroll2 = Scrollbar(frame6, orient=VERTICAL)
xscroll2 = Scrollbar(frame6, orient=HORIZONTAL)
output_opt = Listbox(frame6,height=5, width=40)
output_opt.config (yscrollcommand=xscroll2.set)
output_opt.config (yscrollcommand=yscroll2.set)
yscroll2.config (command=output_opt.yview)
xscroll2.config (command=output_opt.yview)
yscroll2.pack(side=RIGHT, fill=Y,expand=0)
xscroll2.pack(side=BOTTOM, fill=X,expand=0)
output_opt.pack(side=LEFT,fill=BOTH,expand=1)
root.mainloop()
How can I change it for the scrollbars to work?
Also, I read that using grid in the case of scrollbars is better than pack. If I were to modify my code to use grid would I have to create a frame which contains only the listbox and the scrollbar?

Likely copy and paste was not your friend:
output_algo.config (yscrollcommand=xscroll1.set)
should be
output_algo.config (xscrollcommand=xscroll1.set)
and
xscroll1.config (command=output_algo.yview)
should be
xscroll1.config (command=output_algo.xview)
And of course you'll need to do the same for the other Listbox :)

You can't scroll empty Listbox.
I added some elements to listbox and I could scroll up and down.
for item in range(30):
output_algo.insert(END, str(item)*item)
output_opt.insert(END, str(item)*item)
root.mainloop()
There is some problem with scrolling left to right but I saw mistake in xscroll1.config()

Related

How to put Scrollbar inside a Listbox in Tkinter?

how can i move the scrollbar inside a listbox? See the photo attached i used a red arrow for explain, here is my code:
from tkinter import *
window = Tk()
window.geometry('500x500')
window.config(bg='#3c3f41')
window.state('zoomed')
frame_listbox = Frame(window,bg='#3c3f41')
frame_listbox.pack(side=LEFT)
listbox = Listbox(frame_listbox,font=('Helvetica',30))
listbox.pack(padx=400)
scrollbar = Scrollbar(window)
scrollbar.pack(side=RIGHT,fill=Y)
scrollbar.config(command=listbox.yview)
listbox.config(yscrollcommand=scrollbar.set)
window.mainloop()
I tried to put a scrollbar inside a Listbox, i expect to understand if it's possible or not
It is recommended to put the scrollbar just to the right of the listbox instead of inside it. To achieve it:
make the scrollbar child of frame_listbox instead of window
move option padx=400 from scrollbar.pack(...) to frame_listbox.pack(...)
pack listbox to the LEFT side
from tkinter import *
window = Tk()
window.geometry('500x500')
window.config(bg='#3c3f41')
window.state('zoomed')
frame_listbox = Frame(window,bg='#3c3f41')
frame_listbox.pack(side=LEFT,padx=400) # added padx=400
listbox = Listbox(frame_listbox,font=('Helvetica',30))
listbox.pack(side=LEFT) # removed padx=400 and added side=LEFT
scrollbar = Scrollbar(frame_listbox) # changed parent to frame_listbox
scrollbar.pack(side=RIGHT,fill=Y)
scrollbar.config(command=listbox.yview)
listbox.config(yscrollcommand=scrollbar.set)
window.mainloop()
Does this will Help? By using grid instead place.
import tkinter as tk
root = tk.Tk()
root.title("Listbox Operations")
# create the listbox (note that size is in characters)
listbox1 = tk.Listbox(root, width=50, height=6)
listbox1.grid(row=0, column=0)
# create a vertical scrollbar to the right of the listbox
yscroll = tk.Scrollbar(command=listbox1.yview, orient=tk.VERTICAL)
yscroll.grid(row=0, column=1, sticky=tk.N+tk.S)
listbox1.configure(yscrollcommand=yscroll.set)
for i in range(1, 50):
listbox1.insert(tk.END, i)
root.mainloop()
Result:

How to display widgets on a frame that is mounted on canvas in Tkinter?

I created a main root with two frames.
-One frame is for program toolbar.
-Other frame is for canvas where data will be displayed and a scrollbar widget.
-Inside of the canvas is a third smaller frame which will be used for scrolling trough data.
However, when I try to define new widgets and place them on that third smaller frame, nothing happens. I'm defining new widgets inside of a function call of a button command. I have also tried declaring everything as global variables but without luck.
Hint: I tried placing the code from the function to the top level of the code and it works. Also, if I try to mount these widgets on the toolbar frame it also works. It seems that the only thing I can't do is to mount these new widgets on the small frame that is inside the canvas.
I used a simple for loop to create labels just for testing.
Could anyone tell what I am doing wrong?
from tkinter import *
from tkinter import ttk
#Creating main window
root = Tk()
root.resizable(width=False, height=False)
#Defining Background
toolbar = Frame(root, width=613, height=114)
toolbar.grid(row=0, column=0)
background_frame = Frame(root, width=615, height=560)
background_frame.grid(row=1, column=0)
background = Canvas(background_frame, width=615, height=560)
background.pack(side=LEFT, fill=BOTH, expand=1)
scroll_bar = ttk.Scrollbar(background_frame, orient=VERTICAL, command=background.yview)
scroll_bar.pack(side=RIGHT, fill=Y)
background.configure(yscrollcommand=scroll_bar.set)
background.bind('<Configure>', lambda e:background.configure(scrollregion = background.bbox('all')))
second_frame = Frame(background)
background.create_window(150,100, window=second_frame, anchor='nw')
def confirm1():
for x in range(100):
Label(second_frame, text = x ).grid(row=x, column=1)
show_labels = Button(toolbar, text= "Show labels", fg="black", command=confirm1)
show_labels.grid(row=0, column=2)
root.mainloop()
Picture of the app so far
I surely can't reproduce the issue with your current code, but looking at the previous edit it is pretty clear what your problem is.
(taken from your previous edit)
def confirm1():
global background_image1
background.delete('all') # <--- this line of code
for x in range(100):
Label(second_frame, text = x ).grid(row=x, column=1)
Here you delete all your items from your canvas:
background.delete('all')
hence no item appears.
You should instead delete only those items that you want to remove by passing the id or tags to delete method. You can delete multiple items together at once by giving the same tags.
Another option would be to recreate the frame item again on canvas using create_window (Do note: your frame is not deleted/destroyed, it's only removed from canvas)

Python tkinter set text widget to bottom of window using grid

I am totally new to using tkinter and am playing around with grid currently. I have set my window to be 1000x500 and have an image at the top left like this...
window = Tk()
window.geometry("1000x500") #Width x Height
logo = PhotoImage(file="logo.gif")
Label (window, image=logo, bg="#f0f0f0") .grid(row=0, column=0)
T = Text(window, height=2, width=30)
T.insert(END, "Just a text Widget\nin two lines\n")
T.grid(row=2, column=0)
I would like the text widget to be placed at the bottom of the window, I have tried setting the row to something larger but it doesn't have any effect.
Where am I going wrong?
Apparently,The easiest way is to use .pack() instead of .grid().But if you really want to use .grid().You need to set the rowconfigure() to set the weight of row,And sticky="s" or sticky=S to make it in the bottom.
Your code can be:
from tkinter import *
window = Tk()
# window.geometry("1000x500") #Width x Height
logo = PhotoImage(file="xxx")
Label (window, image=logo, bg="#f0f0f0") .grid(row=0, column=0)
T = Text(window, height=2, width=30)
T.insert(END, "Just a text Widget\nin two lines\n")
T.grid(row=1, column=0, sticky=S)
window.grid_rowconfigure(1,weight=1)
window.mainloop()
Remember,if you want to always make it in the bottom and only use .gird(),you need to set the row weight of the text.So I suggest you put all the widget(except the Text widget in the bottom) in a Frame.And use .grid() in the Frame.The Frame and the Text use .pack().

tkinter: dynamically add checkboxes to grid and read values individually

I would like to dynamically add checkboxes to a tkinter grid and then have the user check some of them and afterwards see, which checkboxes were checked.
Here's the code:
top = tkinter.Tk()
var2 = tkinter.IntVar()
main()
top.mainloop()
# in main
for feat in feats:
counter += 1
tkinter.Checkbutton(top, text=str(merkmal) + " ist " +
str(label), command=lambda: testResult(),
variable=var2).grid(row=counter, sticky="W")
# callback
def testResult():
print(var2)
Two problems:
a) I need a vertical and horizontal scrollbar on my grid
I have looked at other posts and seen that I need to add a canvas and then add the scrollbar to the canvas but I havent gotten it to work. Here's my attempt:
w = tkinter.Canvas(top)
scrollbar = tkinter.Scrollbar(top, orient="vertical",command=w.yview)
scrollbar.grid(row=0,column=1,sticky='ns')
w.config(yscrollcommand=scrollbar.set, xscrollcommand=scrollbar.set)
w.grid(row=0,column=0,sticky='nsew')
and then addind the checkboxes to w instead of top. The vertical scrollbar shows, but I cant scroll.
b) When I check one of the boxes, all of them get checked. How can I make it so that each checkbox can be checked individually?
I am new to tkinter and really don't have to learn too much into it, just need this to work somehow.
Thanks for any help!
EDIT
canvas = tkinter.Canvas(top, bg='#FFFF12', width=300, height=900, scrollregion=(0, 0, 900, 900))
hbar = tkinter.Scrollbar(top, orient="horizontal")
hbar.pack(side="bottom", fill="x")
hbar.config(command=canvas.xview)
vbar = tkinter.Scrollbar(top, orient="vertical")
vbar.pack(side="right", fill="y")
vbar.config(command=canvas.yview)
canvas.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set)
canvas.pack(side="left", expand=True, fill="both")
It shows the scrollbar, the vertical scrollbar moves a bit, but the content doesnt move. When I attach everything to a frame, then the scrollbar doesnt move either.

How do you keep a widget in view while scrolling?

I am using Tix to automatically create a scroll bar as the content changes. I want to keep a button or two in the user's view while they scroll through the contents of the application.
I haven't seen this question for Tkinter/Tix yet so I thought I'd ask.
The following code will create a sample of the problem where the button is at a fixed point in the window, and is subject to being scrolled.
from Tkinter import *
import Tix
class some_GUI:
def __init__(self, root):
sw= Tix.ScrolledWindow(root, scrollbar=Tix.AUTO)
sw.pack(fill=Tix.BOTH, expand=1)
frame1 = Frame(sw.window)
frame1.grid(row = 0, column = 1)
frame2 = Frame(sw.window)
frame2.grid(row = 0, column = 2)
def quit():
root.quit()
for i in range(0,300):
label1 = Label(frame1, text = "foo")
label1.grid(row = i, column = 0)
button = Button(frame2, text = "Quit", command = quit)
button.pack()
root = Tix.Tk()
display = some_GUI(root)
root.mainloop()
I want the button(s) to be in "frame2" and centered vertically relative to the application's window. I tried using winfo_height/winfo_width to find the frame's height/ width to work with update, but these values didn't change with the addition of the labels and button.
Attempted/possible solutions:
I put frame2 in sw.subwidgets_all[1] by doing the following:
frame1.pack(side = LEFT)
frame2 = Frame(sw.subwidgets_all()[1])
frame2.pack(side = RIGHT)
button = Button(frame2, text = "Quit", command = quit)
button.pack(side = RIGHT)
This allows the fixed position relative to the application, but the window resizes relative to the button's parent instead of frame1. Another drawback is that the horizontal scrollbar is only relative to frame1.
Find the midpoint of the scrollbar and update the position of the buttons relative to those coordinates using place(maybe?) not sure how to accomplish this, and seeing SO solutions in general I think this might be an inefficient way of doing this.
EDIT: Although this isn't exactly what I had in mind, the following code works as per falsetru's suggestion in the comments:
from Tkinter import *
import Tix
class some_GUI:
def __init__(self, root):
def quit():
root.quit()
frame2 = Frame(root)
frame2.pack(side = RIGHT)
button = Button(frame2, text = "Quit", command = quit)
button.pack()
frame1 = Frame(root)
frame1.pack(side = LEFT)
sw= Tix.ScrolledWindow(frame1, scrollbar=Tix.AUTO)
sw.pack(fill=Tix.BOTH, expand=1)
for widget in sw.subwidgets_all():
print widget
for i in range(0,300):
label1 = Label(sw.window, text = "foo")
label1.grid(row = i, column = i)
print root.winfo_toplevel()
for widget in sw.subwidgets_all():
print widget
root = Tix.Tk()
display = some_GUI(root)
root.mainloop()
You can put the button out of ScrollWindows:
import Tix
from Tkinter import *
def build_ui(root):
sw = Tix.ScrolledWindow(root, scrollbar=Tix.AUTO)
sw.pack(side=LEFT, fill=Tix.BOTH, expand=1)
for i in range(300):
label1 = Label(sw.window, text="foo")
label1.grid(row=i, column=0)
button = Button(root, text="Quit", command=root.quit)
button.pack(side=RIGHT)
root = Tix.Tk()
build_ui(root)
root.mainloop()
The second option you mentioned could be the one that satisfies your situation, however that is computationally expensive as you will need to delete the button(s) and redraw them over and over relatively to the scrollbar up/down motion. Not only this is ugly by design but it can be an obstacle for any further scalability of your application or even lead to unexpected bugs if your application runs some serious operations.
The only realistic solution I see for your problem is to fix the button(s) on (for example the bottom of) the upper canvas (or whatever region you want to set) and outside the scrollable region as #falsetru commented you.

Categories

Resources