I want to have a horizontal scrollbar for a canvas in tkinter. My canvas has both buttons and lines. When I use canvas inbuilt scrollbar it only scrolls the lines not the buttons. So for the buttons I tried using this function which shifts the position of buttons whenever the scrollbar is moved. But now the problem is that buttons and lines move with a different speed according to the width of the scrollbar. The scrollbar gives relative coordinates for its ends but I need absolute coordinates otherwise it disturbs the dragging feature of the buttons and lines. I have been stuck on this for a week now and can't figure out anything useful. Tried almost everything on stackoverflow.
Toplevel1.hbar = ttk.Scrollbar(panel_2, orient="horizontal")
self.SystemCanvas.configure(scrollregion = (0, 0, 1000, 1000),
xscrollcommand = Toplevel1.hbar.set)
Toplevel1.hbar['command'] = self.SystemCanvas.xview
Toplevel1.hbar.bind('<B1-Motion>', lambda e:hscrollBarMove(e,
Toplevel1.hbar, self.SystemCanvas))
Toplevel1.hbar.pack(side = "bottom", fill = "x")
def hscrollBarMove(event, hbar, systemcanvas):
for instance in systemcanvas.winfo_children():
if isinstance(instance, tk.Button) or isinstance(instance, tk.Menu):
try:
instance.place(relx = - hbar.get()[0])
except:
pass
Buttons and lines come dynamically.
Please someone help me :(
My canvas has both buttons and lines. When I use canvas inbuilt scrollbar it only scrolls the lines not the buttons.
Yes, that is correct. The canvas can only scroll canvas objects -- objects created with the various create_* methods (create_line, create_window, etc). It won't scroll items added to the canvas with place, pack, or grid.
If you want to put buttons on a canvas and have them be scrollable, use create_window to add them to the canvas.
Related
I have a question regarding placed buttons on a frame!
I created a canvas and placed a frame inside this canvas! Inside the canvas I place rectangles and oder stuff, drawn by tkinters canvas.create_rectangle, whereas I place certain widgets like buttons inside the frame. (Result: There are togehter in one window)
window_canvas = Canvas(root, borderwidth=0, background="grey", width = window_canvas_size[0], height = window_canvas_size[1], highlightthickness=0)
window_frame = Frame(window_canvas, background='white', borderwidth=0, width = canvas_size[0], height = canvas_size[1])
Now I made the window_canvas scrollable via:
def OnMousewheelConfigureProcessCanvas(self, event):
window_canvas.yview_scroll(int(-1*(event.delta/120)), "units")
window_canvas.bind("<MouseWheel>", m.OnMousewheelConfigureProcessCanvas)
The buttons are scrollable with the window_canvas, when I place the cursor outside of them, no problem.
However, when I hover with my mouse cursor above a button, the "scrollability" just doesn't work anymore. The window_canvas doesn't react to the mouse wheel this time.
I dont want to create a new window (via canvas.create_window) for every button. I have quite a few of them on screen, so I tried to keep it simple by placing one frame for all inside a canvas!
Looking forward to your solutions!
Thanks!
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)
Hi I can't seem to find the cause of a weird issue I am having in Tkinter\Python
When using the following code to create a scrolling window on a canvas
myFrame = Frame(ob)
ob.create_window((0, 0), window=myFrame, anchor='nw')
scroll = Scrollbar(sub, orient="vertical", command=ob.yview)
ob.configure(yscrollcommand=scroll.set)
scroll.grid(row=0, column=1, sticky=N+S)
# add check boxes for clients to buttons
for row in clients:
v = IntVar()
item = Checkbutton(myFrame, text=row[1], variable=v)
item.va = v
item.grid(sticky='w')
clientlist[str(row[0])] = v
ob.configure(scrollregion=ob.bbox('all'))
It creates the windows inside of the canvas and also creates the items inside of it. It even creates the scrollbar next to the canvas just fine.
The issue is that when I scroll down it allows me to scroll forever. It also scrolls upwards just past the top most item in the canvas window and then disables the scroll function.
Any insight on this as it seems I must not be setting the scroll region correctly is my guess but I am not sure what is wrong with it.
On python tkinter, I am using 2 different frames on a Toplevel window, one on the right and another on the left.
The frame which is on right side is not scrollable. I have created a canvas on top of the frame on that frame and one more frame on top of that canvas. I have made that canvas scrollable and pasted the widgets on that canvas but it's not scrollable. I am attaching the code of the scrollable part.
w1 = Canvas(frame2, width=600, height=300,background="white", scrollregion=(1500,1500,3000,3000))
scr_h1 = ttk.Scrollbar(frame2,orient=HORIZONTAL)
scr_h1.pack(side=BOTTOM,fill=X)
scr_h1.config(command=w1.xview)
scr_v1 = ttk.Scrollbar(frame2,orient=VERTICAL)
scr_v1.pack(side=RIGHT,fill=Y)
scr_v1.config(command=w1.yview)
w1.config(xscrollcommand=scr_h1.set,yscrollcommand=scr_v1.set)
w1.pack(fill=BOTH,expand=True)
This code works for me running Python 3.4 - a tkinter window pops up with a red oval (for testing), and the scrollbar allows you to navigate the frame. If you are using Python 2, change tkinter to Tkinter (capital T).
from tkinter import *
root = Tk()
frame2 = Frame(root)
frame2.pack(side=RIGHT)
w1 = Canvas(frame2, width=600, height=300,background="white", scrollregion=(0,0,3000,3000))
scr_h1 = Scrollbar(frame2,orient=HORIZONTAL)
scr_h1.pack(side=BOTTOM,fill=X)
scr_h1.config(command=w1.xview)
scr_v1 = Scrollbar(frame2,orient=VERTICAL)
scr_v1.pack(side=RIGHT,fill=Y)
scr_v1.config(command=w1.yview)
w1.config(xscrollcommand=scr_h1.set,yscrollcommand=scr_v1.set)
w1.pack(fill=BOTH,expand=True)
# inserted to see if it's actually scrolling
w1.create_oval(0,0,50,50,fill='red')
root.mainloop()
Two Possible Issues
Why were you using a ttk ScrollBar? The simple tkinter scroll bar will suffice for your code. When things aren't working, it might help to go back to the simpler model.
Why your starting scroll region was 1500 - any object placed on the canvas in the first 1500 units in either direction were not visible, with this setting, which may have given you the illusion that the scrollbar was not working. See http://effbot.org/zone/tkinter-scrollbar-patterns.htm for more information on using scroll bars.
It should not matter that there are two frames or their orientation, though you may run into problems if you try to mix managers (grid,pack,etc.). These problems are more along the lines of stalled programs, not stationary scrollbars.
I just came across a strange behavior of Tkinter when debugging my program. If a Frame object is created before a Canvas object and later inserted into that Canvas, it can't be displayed. However if the creation order is inverted (firstly Canvas and then Frame), contents in the Frame is displayed correctly.
For example, the following code works well:
from Tkinter import *
app = Frame()
canvas = Canvas(app)
frame = Frame(app)
Label(frame, text = 'aaaa').pack()
Label(frame, text = 'bbbb').pack()
canvas.create_window(0, 0, anchor = NW, window = frame)
canvas.grid()
app.grid()
app.mainloop()
But if the initialization order is inverted, like:
frame = Frame(app)
canvas = Canvas(app)
you get nothing but a blank window.
Is this a intentionally designed behavior (If so, why?), or I just found a bug in Tkinter?
It is a feature. Widgets have a stacking order that defaults to the order that they were created. You can adjust this stacking order with the lift and lower methods.
For example, you can create the frame first and then the canvas, so that the canvas has a higher stacking order. As you observe, you don't see the frame because it is behind the canvas. To make it visible, you can lift it:
frame.lift(canvas)
Doing so will give the same visual effect as if you had created the canvas first.
This technique can be useful to hide and show widgets. For example, you can create a notebook-like widget by stacking several frames on top of each other, and then using lift to bring the one you want to be visible to the top of the order.