Here is my problem :
I try to developp an app using customtkinter in python. On the app, I have a scrollable canvas with another canvas as a widget. I would like to get the canvas coordinates of the widget. When the widget is visible on the screen, canvasx(widget.winfo_x()) seems to work perfectly fine. It doesn’t change with the amount scrolled.
The problem is when the widget is no longer visible : canvasx(widget.winfo_x()) returns a value that doesn’t match the one when the widget is visible. It seems to increase with the amount scrolled.
**My goal is to get the widget canvas position when it is invisible, then make it visible by scrolling and then get a position that would be equal to the invisible one and vice-versa. **
I have tried to add or substract the amount scrolled but it doesn’t solve the problem. I noticed that widget.winfo_x() does not change with the scroll when the widget is invisible. I think it might be the reason why canvasx(widget.winfo_x()) is returning incorrect values but I am not sure.
Here is a reproducible code :
import customtkinter as ctk
import tkinter as tk
import matplotlib
class Canvas_composants(ctk.CTkCanvas):
"""The main canvas which is scrollable"""
def __init__(self,master,bg):
super().__init__(master=master,bg=bg)
self.pack(fill="both",expand=True)
# Scrollbar
self.hbar=ctk.CTkScrollbar(self,orientation="horizontal")
self.hbar.pack(side='top',fill='x')
#Configuration scrollbar and canvas
self.configure(xscrollcommand=self.hbar.set)
self.hbar.configure(command=self.xview)
#Configuration of the scrollregion
self.configure(scrollregion=(0,0,50000,50000))
# Bind scroll to mousewheel
self.bind("<MouseWheel>", self.scroll_canvas)
def scroll_canvas(self,event):
"""Function executed when the mousewheel is used"""
if event.delta:
self.xview_scroll(-1 * (event.delta // 120), "units")
class dessin_composant(ctk.CTkCanvas):
"""How to define the object inside the main canvas"""
def __init__(self,master,width,height,bg,x,y):
super().__init__(master,width=width,height=height,bg=bg)
self.x=x
self.y=y
#Positionning the object
self.master.create_window(self.x,self.y, window=self)
#Attributes
self.master = master
self.canvas_hbar=self.master.hbar # The scrollbar of the main canvas
class App(ctk.CTk):
def __init__(self):
super().__init__()
# Executed when closed
self.protocol("WM_DELETE_WINDOW", self.Fermeture)
# Screen resolution
screen_x = int(self.winfo_screenwidth())
screen_y = int(self.winfo_screenheight())
self_X = screen_x
self_Y = screen_y
posX = (screen_x // 2) -(self_X // 2)
posY = (screen_y // 2) -(self_Y // 2)
geo="{}x{}+{}+{}".format(self_X,self_Y,posX,posY)
self.geometry(geo)
#Button
self.frame=ctk.CTkFrame(self)
self.frame.pack(side='left',fill='both')
self.B=ctk.CTkButton(self.frame,text="print",command=self.f1)
self.B.grid(row=0,column=0,pady=100)
#Labels
self.label1=ctk.CTkLabel(self.frame,text="Winfo_x() = ")
self.label1.grid(row=1,column=0)
self.label2=ctk.CTkLabel(self.frame,text="Canvasx(Winfo_x()) = ")
self.label2.grid(row=2,column=0)
self.label3=ctk.CTkLabel(self.frame,text="Canvasx(scroll) = ")
self.label3.grid(row=3,column=0)
#Main canvas
self.c=Canvas_composants( self, "white")
#Object inside canvas
width = 107
height = 190
bg = "black"
self.object=dessin_composant(self.c, width, height, bg,600,350)
def f1(self):
"""Function which prints object position inside the main canvas"""
self.c.delete(self.txt)
obj = self.object
self.off = self.c.hbar.get() # The amount scrolled
self.label1.configure(text=f"Winfo_x() = {obj.winfo_x()} ")
self.label2.configure(text=f"Canvasx(Winfo_x()) = {self.c.canvasx(obj.winfo_x())} ")
self.label3.configure(text=f"Canvasx(scroll) = {self.c.canvasx(self.off[0])} ")
def Fermeture(self):
"""Executed when the window is closed"""
if tk.messagebox.askokcancel("Quit", "Do you really want to quit ? "):
matplotlib.use('module://matplotlib_inline.backend_inline')
self.quit()
self.destroy()
if __name__ == "__main__":
Fenetre = App()
Fenetre.mainloop()
In the above app, if you click on the print button, the values of widget.winfo_x(), canvasx(widget.winfo_x()), and canvasx(scroll) will be printed. Thus, you can observe that canvasx(winfo_x()) changes when the widget is invisible.
Any help would be appreciated
Thank you !