Reputation: 3512
I want to keep some text on a scrollable tkinter canvas static, or anchored. It should not move with the scrollbars.
How can I do this?
from tkinter import *
root=Tk()
frame=Frame(root,width=300,height=300)
frame.grid(row=0,column=0)
canvas=Canvas(frame,bg='#FFFFFF',width=300,height=300,scrollregion=(0,0,500,500))
hbar=Scrollbar(frame,orient=HORIZONTAL)
hbar.pack(side=BOTTOM,fill=X)
hbar.config(command=canvas.xview)
vbar=Scrollbar(frame,orient=VERTICAL)
vbar.pack(side=RIGHT,fill=Y)
vbar.config(command=canvas.yview)
canvas.config(width=300,height=300)
canvas.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set)
canvas.pack(side=LEFT,expand=True,fill=BOTH)
canvas.create_text(10, 10, text='Static Text # 1', anchor = NW, fill = 'red')
canvas.create_text(10, 100, text='Static Text # 2', anchor = NW, fill = 'red')
canvas.create_text(150, 10, text='Scrollable Text # 1', anchor = NW)
canvas.create_text(150, 100, text='Scrollable Text # 2', anchor = NW)
root.mainloop()
Upvotes: 0
Views: 622
Reputation: 19174
If you do not need the text box to be transparent, the easiest thing to do is to not put the text on the canvas but to place a Label over the canvas.
import tkinter as tk
root = tk.Tk()
c = tk.Canvas(root)
c.place(x=0, y=0)
r = c.create_rectangle(100, 100, 200, 200, outline='red',
fill='yellow', width=10)
ct = c.create_text(110, 150, text='canvas text', anchor='w')
lt = tk.Label(c, text='label text')
lt.place(x=110, y=110)
If you do want the transparency, then you must intercept move commands between the canvas and scrollbars so as to also move the 'static' items to the canvas coordinates that correspond to the original screen (window) coordinates. This is complicated by the fact that Scrollbar.set expects two fractions, so a canvas calls x/yscrollcommand with two fractions. Similarly, moving the scrollbar slider causes the scrollbar to call its command (canvas x/yview) with a fraction, which I suspect is the upper or left fraction. In the other hand, clicking the scrollbar buttons calls x/yview with a number and units.
I think what I would do is create a list of tuples of static item id, and the 4 canvas.bbox coordinates of the item. Next replace canvas.xscrollcommand
, canvas.yscrollcommand
, hbar.set
, and vbar.set
with wrappers named, for instance, xscroll
, yscroll
, xset
, and yset
. In each wrapper, call the wrapped function. Then call a new static_set
function that uses canvas.canvasx/y(screenx/y, gridspacing=1) to convert screen coords to the new canvas coordinates and canvas.coords(item id, *canvas coords) to place the item.
I leave you to work out the details. If you are not familiar with the NMT Tkinter reference, learn to use it. This is the source of the info above.
Code Edits: Don't use name t
for both labels. Change parent of lt
from root
to canvas c
, as suggested by mcu.
Upvotes: 1