【问题标题】:How to attach delete function in Tkinter GUI如何在 Tkinter GUI 中附加删除功能
【发布时间】:2020-04-12 22:19:25
【问题描述】:

我是 python 新手,正在向这个社区的专家寻求帮助。我正在尝试从我的 Tkinter 小部件 FrameLabel 中删除图像。我遵循了 StackOverflow 上提供的许多解决方案,但不幸的是,我无法在我的代码中实现这些解决方案。我需要帮助来删除我在窗口上上传的图像。


GUI 工作

  • 点击选择
  • 浏览图片
  • 上传图片
  • 它将显示在LabelFrame中,如下所示:
    frame3 = tk.LabelFrame(pw_right, bd=2, text='Uploaded images')
    frame3.pack(side='left', anchor='nw')
    

删除按钮

DelButton = tk.Button(frame1, text ='Delete', command = button.on_click_del_button)
DelButton.grid(row=0, column=4)

删除函数:

def on_click_del_button(self):
    print('Delete button clicked')

    image = self.paths[self.radio_var.get()]

    if os.path.exists(image):
        os.remove(image)
    else:
        print("The file does not exist")

需要帮助的部分:我在定义删除功能时需要帮助,即 button.on_click_del_button 这样当我按删除时。 Tkinter 从窗口中删除选定的图像。

以下是窗口的 GUI:

我遵循了专家 furas 的建议,但 Tkinter 窗口中没有发生任何事情。虽然所有的打印值都在显示。

【问题讨论】:

  • 你真的想从文件系统中删除文件,还是从“上传的图像”标签框中删除相应的单选按钮?或两者?或者是其他东西?请澄清一下。
  • 我想两者都做。从文件系统中删除所选图像对应的单选按钮从“上传的图像”标签框架中

标签: python image opencv user-interface tkinter


【解决方案1】:

您不必加载图像以从磁盘中删除 - 您只需要路径

    image = self.paths[self.radio_var.get()]

你必须使用变量image,而不是字符串"image"

顺便说一句:你不需要lambda 来调用这个函数

command=button.on_click_del_button

如果您不将值作为参数发送,则不需要 path='None', image='None'


def on_click_del_button(self):
    print('Delete button clicked')

    image = self.paths[self.radio_var.get()]

    if os.path.exists(image):
        os.remove(image)
    else:
        print("The file does not exist")

要从窗口中隐藏小部件,您有 widget.pack_foger()widget.grid_forget()。它会隐藏,因此您可以使用widget.pack()widget.grid(...) 再次显示它。

要从窗口和内存中删除小部件 - 这样你就不能再次使用它 - 你有 widget.destroy() 喜欢

 self.radio_handle[0].destroy()

但您必须知道选择了哪个单选按钮012

也许更好地使用路径将元素保留在字典中,而不是列表中

 self.radio_handle[path] = radio_button

以后在on_click_del_button

 self.radio_handle[path].destroy()

您也可以使用path 作为Radiobutton 中的值

 tk.Radiobutton(..., value=path)

编辑:它从窗口中删除图像。

我使用StringVar() 而不是IntVar()

self.radio_var = tk.StringVar()

并将path 指定为 Radiobutton 中的值

Radiobutton(..., value=path)

所以现在它可以返回 path 而不是 numer 并且可以更容易地在字典中查找对象

self.radio_handle = dict()

使用列表和数字可能会出现问题,因为从列表中删除元素后,其他元素会更改列表中的位置,这可能会产生问题。

现在我可以将小部件添加到字典中

    self.radio_handle[path] = (radio_button)

我可以用同样的方式摧毁它

    def on_click_del_button(self):
        print('Delete button clicked')

        path = self.radio_var.get()
        self.radio_handle[path].destroy()        

import os
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox

import cv2
from PIL import Image
from PIL import ImageTk


class Button:

    def __init__(self, root, frame3):
        self.root = root
        self.frame3 = frame3

        self.radio_var = tk.StringVar()
        self.path_selected = '' # or None

        self.paths = []

        self.radio_handle = dict()
        self.check_value = []

    def on_click_select_button(self, fname_label):
        print('select button clicked')
        fileType = [('jpg/png file', ('*.jpg', '*.png'))]
        self.path_selected = filedialog.askopenfilename(filetypes=fileType)
        fname_label['text'] = os.path.basename(self.path_selected)

    def on_click_upload_button(self, path='None', image='None'):
        print('upload button clicked')

        if path == 'None':
            path = self.path_selected
        else:
            cv2.imwrite(path, image)

        if path in self.paths:
            messagebox.showerror('Upload Error', '"'
                                 + path
                                 + '"' + ' is already uploaded.')
        else:
            self.paths.append(path)
            self.create_radio_button(path)

    def on_click_show_button(self, method):
        print('showButton clicked')
        image = cv2.imread(self.paths[self.radio_var.get()])

        file_name = os.path.basename(self.paths[self.radio_var.get()])
        name, ext = os.path.splitext(file_name)
        path = 'images/' + name + '_' + method + ext


    def create_radio_button(self, path):

        image = cv2.imread(path)
        # image = cv2.resize(image,(120,120))
        image = self.scale_to_height(image, 120)
        image_tk = self.to_tk_image(image)

        radio_button = tk.Radiobutton(self.frame3, image=image_tk,
                                      value=path,
                                      variable=self.radio_var)
        self.radio_var.set('')
        self.radio_handle[path] = (radio_button)
        self.check_value.append(self.radio_var)

        radio_button.grid(row=(len(self.radio_handle) - 1) // 3,
                          column=(len(self.radio_handle) - 1) % 3)
        self.root.mainloop()

    def to_tk_image(self, image_bgr):
        image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB)
        image_pil = Image.fromarray(image_rgb)
        image_tk = ImageTk.PhotoImage(image_pil)
        return image_tk

    def on_click_del_button(self):
        print('Delete button clicked')

        path = self.radio_var.get()

        if path:
            self.radio_handle[path].destroy() # remove widget from window
            del self.radio_handle[path] # remove from dictionary 
            self.paths.remove(path) # remove path from list
            self.radio_var.set('')
        else:
            print('Not selected')

        #image = path # self.paths[self.radio_var.get()]

        #if os.path.exists(image):
        #    os.remove(image)
        #else:
        #    print("The file does not exist")


    def scale_to_height(self, img, height):
        scale = height / img.shape[0]
        return cv2.resize(img, dsize=None, fx=scale, fy=scale)

if __name__ == '__main__':
    os.makedirs('images', exist_ok=True)

    root = tk.Tk()
    root.title('Image GUI')
    root.geometry('1280x960')

    pw_left = tk.Frame(root, relief='ridge', borderwidth=4)
    pw_left.pack(side='left', anchor='nw')

    pw_right = tk.Frame(root, relief='ridge', borderwidth=4)
    pw_right.pack(side='left', anchor='nw')

    frame1 = tk.Frame(pw_left, bd=2, relief="ridge")
    frame1.pack()

    frame2 = tk.LabelFrame(pw_left, bd=2, relief="ridge", text='options')
    frame2.pack(anchor='nw')

    frame3 = tk.LabelFrame(pw_right, bd=2, text='Uploaded images')
    frame3.pack(side='left', anchor='nw')

    button = Button(root, frame3)

    # add label
    label = tk.Label(frame1, text='File:')
    label.grid(row=0, column=0)

    # label to show file name
    file_name_label = tk.Label(frame1, text='-----not selected-----', width=20, bg='white')
    file_name_label.grid(row=0, column=1)

    # file select button
    select_button = tk.Button(frame1, text='select',
                              command=lambda: button.on_click_select_button(file_name_label))
    select_button.grid(row=0, column=2)

    # upload button
    uploadButton = tk.Button(frame1, text='Upload',
                             command=lambda: button.on_click_upload_button())
    uploadButton.grid(row=0, column=3)

    DelButton = tk.Button(frame1, text='Delete', command=button.on_click_del_button)
    DelButton.grid(row=0, column=4)

    root.mainloop()

【讨论】:

  • 嗨@furas,感谢您的支持。但是,当我尝试按照上述说明进行操作时,图像并没有从框架中删除。它正在终端中打印打印输出值,但 GUI 中没有发生任何事情。
  • 嗨@furas,我已经按照你的建议修改了代码。但仍然面临这个问题。图像没有从框架中删除,但在打印中,它正在显示如上图所示的输出。
  • 此代码仅从磁盘中删除。 os.remove()os.path.exists()(您使用的)用于在磁盘上删除,而不是在窗口中删除。如果您使用pack() 放置小部件,则使用pack_forget()destroy() 将其删除。如果您使用了.grid(),则使用grid_forget()destroy() 将其删除。
  • 我想我用过pack()。到处。不知道在哪里添加“pack_forget()”或“destroy()”。你能帮我解决这个问题吗?非常感谢。以前您的代码内容丰富且解释清楚。
  • 我添加了从窗口中删除小部件、从列表中删除小部件以及来自self.paths的路径的完整代码
猜你喜欢
  • 1970-01-01
  • 2015-02-05
  • 1970-01-01
  • 1970-01-01
  • 2021-01-13
  • 2020-08-26
  • 2011-07-20
  • 1970-01-01
  • 2020-11-03
相关资源
最近更新 更多