I am having an issue with a TkInter interface whereby I cannot get a scrollbar to visually attach itself to a Listbox element - see this image: Problem interface
Here is the code which creates and positions the Listbox & Scrollbar:
lblpd3 = ttk.Label(mainframe,text='',font=("Helvetica", 5))
lblpd3.grid(column=0, row=12, sticky=NW)
scltrn = Scrollbar(mainframe, orient=VERTICAL)
lbltrn = ttk.Label(mainframe,text='Select Transformation',font=("Helvetica", 11, "bold"))
lbltrn.grid(column=0, row=13, sticky=NW)
self.lsttrn = Listbox(mainframe,selectmode=SINGLE,exportselection=0,width=62,height=4,yscrollcommand=scltrn.set,activestyle='none',selectbackground='#4A6984',selectborderwidth=3,highlightcolor='#4A6984',highlightthickness=1)
scltrn.config(command=self.lsttrn.yview)
scltrn.grid(column=0, row=14, sticky=(N,S,E))
for item in self.coord:
self.lsttrn.insert(END, item)
self.lsttrn.grid(column=0, row=14, padx=0, sticky=NW)
self.lsttrn.select_set(0)
Is there a simple hack I could use to push the scrollbar a few pixels to the left - documentation seems to suggest there's no padding element?
You could add your Scrollbar widget and your Listbox widget into their own seperate Frame.
Then add that in as a single 'unit'.
While I dont know your whole program, here's what the logic behind the fix should roughly look like:
# Declare a new Frame to hold your Listbox and Scroll wheel
myFrame = Frame.__init__(self, parent)
# Make sure your Scrollbar is a part of our newly created Frame "myFrame"
scltrn = Scrollbar(myframe, orient=VERTICAL)
# Make sure your Listbox is a part of our newly created Frame "myFrame"
self.lsttrn = Listbox(myFrame,selectmode=SINGLE,exportselection=0,width=62,height=4,yscrollcommand=scltrn.set,activestyle='none',selectbackground='#4A6984',selectborderwidth=3,highlightcolor='#4A6984',highlightthickness=1)
...
#pack the Scrollbar and Listbox together in our Frame IN THIS ORDER
self.lsttrn.pack()
scltrn.pack()
....
# Now grid our Frame containing both the Scrollwheel and Listbox to your GUI
myFrame.grid(column=xxx,row=xxx,padx=xxx,sticky=xxx)
This shouldnt be a copy+paste fix, but hopefully you understand the logic behind creating a Frame to hold your Scrollbar and Listbox, and then gridding that in, rather than both seperately.
Hope this helps! ~Gunner
At least part of the problem stems from the fact that you are putting the scrollbar and listbox in the same column. They need to be in different columns.
One really simple solution is to use a frame that contains only the listbox and scrollbar. Because you don't have a horizontal scrollbar you can use pack to put the listbox and scrollbar in the frame with just a couple lines of code. You can then place that frame in a single column in its parent.
Related
I have an app that I would like to restyle using Customtkinter. I originally used Tkinter.
However I have a ListBox widget connected to a scrollbar and when I run the code it says that Customtkinter does not have CTkListBox as attribute, or that ListBox is not defined.
I have tried o look for the issue online and it seems that other people have asked to the person who created he module if he could add ListBox widgets (the link below).
https://github.com/TomSchimansky/CustomTkinter/issues/69
He did answer, but as I am new to coding, I do not feel very confident with the code attached.
I hope someone can help.
Thank you
This is my original code:
# create listbox and put it on screen
list1 = Listbox(window, height=6, width=35)
list1.grid(row=2, column=0, rowspan=6, columnspan=2)
#create scrollbar and put it on screen
sb1 = Scrollbar(window)
sb1.grid(row=2, column=2, rowspan=6)
# apply configure methods to make list and scrollbar work together
list1.configure(yscrollcommand = sb1.set)
sb1.configure(command=list1.yview)
# bind method takes two args: type of event and function.
list1.bind("<<ListboxSelect>>", get_selected_row)
I would really appreciate some help with figuring out grid geometry manager.
Here is what I want to build.
I was thinking of using grid but I cannot find any good tutorials that would clearly
explain how to work with it.
There are lots of tutorials but mostly all are either very simple or really outdated.
I am not sure how to build what is shown in the picture using only grid because all
elements are nested inside each other and each element is supposed to hold more elements inside it.
It's not so hard to arrange outermost widgets using grid. I just place Toolbar into 0th row,
then outermost PanedWidow (green) into 1st row, and then Status Bar into 2nd row.
After that I need to arrange things inside green PanedWindow.
I place another PanedWindow (pink) into the right pane of the green PanedWindow and then
stick a Notebook into it's top pane.
Now, I need to add more widgets to these inner panes. For instance. I am going to add
some buttons to the bottom pane of the pink PanedWindow. And that's where I run into problems.
If I try to use pack() to arrange things inside these innermost panes, Python screams at me for
using more than one geometry manager.
But when I think about how to accomplish this with grid, I just can't find a way to subdivide
innermost panes into smaller grids.
Can there be grids inside Widgets which have been acted upon by an outer grid?
When I see widgets that take up the full width or full height of an area I usually use pack since since it's specifically designed to lay objects along a side of an empty cavity. You can use grid but it requires extra code since you have to both add the widget and configure the rows and columns. With pack all you have to do is add the widgets.
For example, it's clear you want a statusbar along the bottom, and a toolbar along the time, and a paned widget in-between. So, start with that, as in the following example:
import tkinter as tk
root = tk.Tk()
root.geometry("600x400")
toolbar = tk.Frame(root, background="#d5e8d4", height=40)
statusbar = tk.Frame(root, background="#e3e3e3", height=20)
main = tk.PanedWindow(root, background="#99fb99")
toolbar.pack(side="top", fill="x")
statusbar.pack(side="bottom", fill="x")
main.pack(side="top", fill="both", expand=True)
root.mainloop()
Note: widths, heights, and colors are added to the frame for illustrative purposes since otherwise, an empty frame would have a size of 1x1. Once you add widgets inside a frame you can remove the width and height options.
You say the right will have a paned window, so add that on the right. We'll use a normal frame on the left.
left_pane = tk.Frame(main, background="#99fb99", width=100)
right_pane = tk.PanedWindow(main, background="#99fb99", width=200)
main.add(left_pane)
main.add(right_pane)
Next, add the two panes to the right. So that I can show colors with as little code as possible I'll use a frame on the top instead of a notebook:
notebook = tk.Frame(right_pane, background="#99ceff", height=70)
bottom_right = tk.Frame(right_pane, background="#ffe6cd", height=50)
right_pane.add(notebook)
right_pane.add(bottom_right)
With all that being said, you can use grid if you want. The trick is to use intermediate frames, since the layout in any widget is independent of the layout in parent or child widgets.
All you need to do is remove the first three calls to pack and replace it with these five lines:
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
toolbar.grid(row=0, column=0, sticky="ew")
main.grid(row=1, column=0, sticky="nsew")
statusbar.grid(row=2, column=0, sticky="ew")
Since the other widgets are children of paned widgets, there's nothing else to do. Any widgets you add to each pane have their own independent layout area, so you can use grid, pack, or place inside each frame.
To illustrate that point, I'll use grid to add several rows and columns of squares:
for row in range(6):
for column in range(30):
f = tk.Frame(bottom_right, background="white",
bd=2, relief="raised", width=10, height=10)
f.grid(row=row, column=column)
I found a post that's around two years old, which might be a little too old for your uses, but it has some information on nesting grids in Tkinter. It recommends using frames to nest the grids, essentially having children within children of a frame. Within these frames, you can place objects.
Im coding my personal text editor. But i have a problem with the 2 widget text and the scrollbar (connect one scrollbar to two text).
What is my idea and logic (at the beginning)?
I want to display 2 text, one for writing text entered by user, and one to display the number of the line. I pack both of them, in the root. Then i create a scrollbar, that will scroll on Y axes the 2 text, so what i want to do (mainly) is to connect 2 widget (text) to one scrollbar.
But it didn't work.
This system absolutely doesn't work, are there any suggest or fix to fix this first idea?
Other ideas that i found.
After the first attempt, i thought that i can pack the 2 texts into 1 container. I tried to create a frame (packed into root) that contains the 2 texts, i did this because i have to connect the scrollbar only to the frame. But it didn't work, moreover it didnt allow me to write the following snippet: command=frame.yview in the scrollbar option, it seems that i cant connect frame to scrollbar.
So:
I will ask u if my reasoning are good, and how to solve. If not what can i do?
Similar question found on Google: (but that i dont undestand)
How to scroll two parallel text widgets with one scrollbar?
Tkinter adding line number to text widget
from tkinter import *
root = Tk()
root.geometry("480x540+100+100")
root.config(cursor='')
line = Text(root, bg="light grey", font="Roman 24", width=4)
line.pack(side=LEFT, fill=BOTH)
text = Text(root, bg="grey", font="Roman 24")
text.pack(side=LEFT, fill=BOTH, expand=True)
scrollbar = Scrollbar(text, orient=VERTICAL, command=(line.yview, text.yview))
text.configure(yscrollcommand=scrollbar.set)
line.configure(yscrollcommand=scrollbar.set)
scrollbar.pack(side=RIGHT, fill=Y)
for n in range(50):
line.insert("{}.0".format(n+1), "{}\n".format(n+1))
text.insert("{}.0".format(n+1), "Line no. {}\n".format(n+1))
if __name__ == '__main__':
root.mainloop()
There's nothing special about a scrollbar - it just calls a function when you move it. The API for this function is well defined. While it normally should call the yview (or xview) method of a scrollable window, there's no requirement that it must.
If you want to control two widgets with a single scrollbar, create a function for your scrollbar that scrolls both windows.
def multiple_yview(*args):
line.yview(*args)
text.yview(*args)
scrollbar = Scrollbar(text, orient=VERTICAL, command=multiple_yview)
You will have a similar problem when you scroll the text widget while entering new lines or moving around with cursor keys. You'll need to configure the yscrollcommand attribute of the text widget to call a function so that it both updates the scrollbar and also scrolls the other window (and maybe also add additional line numbers)
Apologies for the dumb question, as you can probably tell, I am extremely new to Python. I am trying to attach a scroll bar to a list in a frame, I can scroll up/down the list, but I can only attach it to the frame for some reason. When I try to attach it to listbox, the listbox disappears.
Here is the code:
wipLotListBox = Listbox(tab_printFGWO)
wipLotListBox.insert(1,"Test1")
wipLotListBox.insert(2,"Test2")
wipLotListBox.insert(3,"Test3")
wipLotListBox.insert(4,"Test4")
wipLotListBox.insert(5,"Test5")
wipLotListBox.insert(6,"Test6")
scrollBar = ttk.Scrollbar(tab_printFGWO,orient=VERTICAL,command=wipLotListBox.yview)
scrollBar.place(x=700,y=365)
wipLotListBox.config(yscrollcommand=scrollBar.set)
wipLotListBox.place(x=700,y=365)
Here is what it looks like:
place is almost always the wrong choice. Both pack and grid are much better.
Assuming that the scrollbar and listbox are the only two widgets in tab_printFGWO, here's the easiest way to do it:
scrollBar.pack(side="right", fill="y")
wipLotListBox.pack(side="left", fill="both", expand=True)
I know this isn't the first time a question like this is asked, but even after like 2 hours of browsing the Internet I can't get it to work:
So I'm trying to create a Tkinter-Frame, that contains several Buttons (As Example I took 30). But Because I don't have enough space in my program, I need to add an Scrollbar next to it, so that one can scroll through the Buttons.
The Problems I had where, that the inner "moving part" of the bar was as big as the whole scrollbar and couldn't be moved, which I kinda solved by using scollregion=(0,0,1000,1000), but even then the moving of the bar had no effect on the canvas whatsoever.
Here Is the corresponding code that I extracted out of my program:
import Tkinter as tk
root = tk.Tk()
root.rowconfigure(0, weight=1)
root.columnconfigure(0, weight=50)
root.columnconfigure(1, weight=1)
root.minsize(300,400)
root.maxsize(300,400)
#Buttons
buttonFrame = tk.Canvas(root, bg='#bbb')
buttonFrame.grid(row=0, column=0, sticky=tk.N+tk.E+tk.S+tk.W)
buttonFrame.columnconfigure(0, weight=1)
scroll = tk.Scrollbar(root, command=buttonFrame.yview)
scroll.grid(row=0, column=1, sticky=tk.N+tk.E+tk.S+tk.W)
buttonFrame.configure(yscrollcommand=scroll.set)
for i in range(30):
tk.Button(buttonFrame, text=str(i+1)).grid(row=i, column=0, sticky=tk.N+tk.E+tk.S+tk.W)
root.mainloop()
As you (hopefully) see, the slider can't even be moved nor does it change anything on the canvas, even if I squeeze a scrollregion=(bla) somewhere in there.
2 Questions:
a.) What do I need to add (or remove), so that I can scroll through the list of Buttons
b.) Does the fix from a. still work when I make the Scrollbar a child of the buttonFrame instead of the root?
To add widgets to a Canvas you have to use the create_window method, not grid(). Then you have to update the canvas before setting the scrollregion.
for i in range(30):
btn = tk.Button(buttonFrame, text=str(i+1))
buttonFrame.create_window((100,i*50), window=btn)
root.update()
buttonFrame.config(scrollregion=buttonFrame.bbox("all"))
If you try that I suspect it's not what you were looking for, since the create_window method requires absolute positioning (you can't use grid or pack). That's why most people put a Frame in the Canvas, and add their widgets to that instead. Many people have abstracted this faux Frame that is actually a Frame in a Canvas in another Frame, including me.