mcu
mcu

Reputation: 3512

Static Text on Scrollable Canvas

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

Answers (1)

Terry Jan Reedy
Terry Jan Reedy

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

Related Questions