gpt4 book ai didi

tkinter: make a scrollable canvas react to item deletion(Tkinter:使可滚动画布对项目删除做出反应)

转载 作者:bug小助手 更新时间:2023-10-25 19:14:48 33 4
gpt4 key购买 nike



I am trying to make a reactive scrollable list of items.

我正在尝试制作一个被动的可滚动的项目列表。


currently I have a canvas, scrollbar and item container defined as follows:

目前,我有一个画布、滚动条和项目容器,定义如下:


        self.scroll_bar = tk.Scrollbar(self.container, orient=tk.VERTICAL)
self.scroll_bar.pack(side=tk.RIGHT, fill=tk.Y)

self.canvas = tk.Canvas(self.container, yscrollcommand=self.scroll_bar.set)
self.canvas.pack(fill=tk.BOTH, expand=True)
self.scroll_bar.config(command=self.canvas.yview)

self.item_container = tk.Frame(self.canvas)
self.canvas.create_window((0, 0), window=self.item_container, anchor=tk.NW)

when items (tk.Frames) are added or removed from item_container it calls the update_canvas_scroll_region method:

在Item_Container中添加或删除项(tk.Frames)时,它会调用UPDATE_Canvas_Sscroll_Region方法:


    def update_canvas_scrollregion(self):
self.item_container.update_idletasks()
self.canvas.config(scrollregion=self.canvas.bbox("all"))

this works fine for adding items but doesn't update properly when items are removed, I think its because the canvas.bbox("all") doesn't shrink to fit when items are deleted.

这对于添加项目很有效,但在删除项目时不会正确更新,我认为这是因为canvar.bbox(“all”)在删除项目时不会缩小到合适的大小。


full code: https://github.com/harrisabdullah/tk_scrollable_list

完整代码:https://github.com/harrisabdullah/tk_scrollable_list


更多回答

No, the issue is not canvas.bbox('all'). The problem is that when you delete the image or frame with ImageEditUI.delete() there is no link with ScrollableList.delete_item() and thus the scrollable region does not get adjusted.

不,问题不是canvar.bbox(‘all’)。问题是,当您使用ImageEditUI.ete()删除图像或帧时,没有与ScrollableList.Delete_Item()的链接,因此不会调整可滚动区域。

If you print child after deleting, you will see that they were not deleted. Probably because of the references to them from the class. I managed to delete them by name.

如果您在删除后打印子项,您将看到它们没有被删除。可能是因为类中对它们的引用。我设法删除了他们的名字。

优秀答案推荐

I took the liberty to change the class ImageEditUI into ImageFrame as that is what the class is doing, it makes a frame containing the image, input field and a delete button.
The ScrollableList is the main UI and in order to make the link with ImageFrame it creates the instance in the __init__ (self.image_frame = ImageFrame()).

我擅自将ImageEditUI类更改为ImageFrame,因为这就是该类正在做的事情,它创建了一个包含图像、输入字段和一个删除按钮的框架。ScrollableList是主用户界面,为了与ImageFrame建立链接,它在__init__(self.Image_Frame=ImageFrame())中创建了实例。


To make the link with the delete button (made in ImageFrame) bind this button to the function delete_item of ScrollableList and pass this function the newly created image_frame. Deleting the frame is done by a call to ImageFrame.delete_item

要创建带有删除按钮的链接(在ImageFrame中制作),请将该按钮绑定到ScrollableList的函数DELETE_ITEM,并将新创建的IMAGE_FRAME传递给该函数。删除帧是通过调用ImageFrame.Delete_Item完成的


A working example is shown below.

下面显示了一个工作示例。


from functools import partial
import tkinter as tk
from PIL import Image, ImageTk


class ScrollableList:
def __init__(self):
self.item_container = None
self.canvas = None
self.scroll_bar = None
self.container = None
self.image_frame = ImageFrame()

def start(self, root):
self.container = tk.Frame(root)
self.container.pack(fill=tk.BOTH, expand=True)

self.scroll_bar = tk.Scrollbar(self.container, orient=tk.VERTICAL)
self.scroll_bar.pack(side=tk.RIGHT, fill=tk.Y)

self.canvas = tk.Canvas(self.container, yscrollcommand=self.scroll_bar.set)
self.canvas.pack(fill=tk.BOTH, expand=True)
self.scroll_bar.config(command=self.canvas.yview)

self.item_container = tk.Frame(self.canvas)
self.canvas.create_window((0, 0), window=self.item_container, anchor=tk.NW)
self.canvas.bind_all("<MouseWheel>", self.on_mousewheel)

def update_canvas_scrollregion(self):
self.item_container.update_idletasks()
self.canvas.config(scrollregion=self.canvas.bbox("all"))

def on_mousewheel(self, event):
self.canvas.yview_scroll(event.delta, "units")

def add_item(self, image_path):
image_frame, delete_button = self.image_frame.add_item(
self.item_container, image_path
)
# link the delete button from the image_frame to the delete_item function of ImageContainer
delete_button.configure(
command=partial(self.delete_item, image_frame=image_frame)
)
self.update_canvas_scrollregion()

def delete_item(self, image_frame):
self.image_frame.delete_item(image_frame)
self.update_canvas_scrollregion()


class ImageFrame:
def __init__(self):
pass

def add_item(self, container, image_path):
PIL_image = Image.open(image_path)
PIL_image.thumbnail((800, 800))
image = ImageTk.PhotoImage(PIL_image)
image_frame = tk.Frame(container)
image_frame.pack()

image_label = tk.Label(image_frame, image=image)
image_label.image = image
image_label.pack(padx=5, pady=5)

label = tk.Label(image_frame, text="entre words in image: ")
label.pack()

input = tk.Entry(image_frame, width=50)
input.pack()

delete_button = tk.Button(image_frame, text="Delete")
delete_button.pack()

return image_frame, delete_button

def delete_item(self, container):
for child in container.winfo_children():
child.destroy()
container.destroy()

def export(self):
pass


def main():
scrollable_list = ScrollableList()
root = tk.Tk()
scrollable_list.start(root)
scrollable_list.add_item("pic3.jpg")
scrollable_list.add_item("pic4.jpg")
scrollable_list.add_item("pic5.jpg")
scrollable_list.add_item("pic6.jpg")
root.mainloop()


if __name__ == "__main__":
main()

更多回答

One suggestion instead of have a method start, I would move all this to the __init__(self, root). Then start the app by calling scrollable_list = ScrollableList(root) in main.

一个建议是,我将把所有这些都移到__init__(self,根),而不是让方法开始。然后在Main中调用Scrollable_List=ScrollableList(根)来启动应用程序。

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com