我是 wxPython 的新手,正在开发一个带有 GUI 的基本程序,让用户标记图像。现在,当用户单击“导入”按钮时,他们可以选择一个目录。然后,代码使用 matplotlib 在 for 循环中显示该目录中的每个图像。但是,我不知道如何在 for 循环中访问用户输入。这就是该函数现在的样子:
import matplotlib.pyplot as plt
import io
import os
import wx
#This function is appended to an "Import" menu item in the frame's menu bar
def OnClick(self, event):
dlg = wx.DirDialog(self, "Specify folder:", style=wx.DD_DEFAULT_STYLE)
results = []
if dlg.ShowModal() == wx.ID_OK:
folder = dlg.GetPath()
for image in os.listdir(folder):
im = plt.imread(image)
plt.imshow(im)
buf = io.BytesIO()
plt.savefig(buf,format='png')
buf.seek(0)
self.Image = wx.Image(buf, wx.BITMAP_TYPE_ANY)
self.Image = wx.StaticBitmap(self, wx.ID_ANY, wx.Bitmap(self.Image))
self.sizer = wx.BoxSizer(wx.HORIZONTAL)
self.sizer.Add(self.Image,1,wx.ALIGN_CENTRE)
self.SetSizer(self.sizer)
#Getting the input works but it's obviously not part of the GUI
#Ideally, I would like to create a text box after each image is displayed
#Then, once the input is submitted, return to the top of the loop
label = input('Enter label for image:').lower()
results.append([image, label])
现在,作为占位符,我正在使用
input()
在终端中获取用户输入。效果很好,但我宁愿让该条目成为 wxPython GUI 的一部分。我想知道是否有人知道一种在 for 循环中创建文本条目、获取输入、然后删除/清除该输入并获取新输入的方法。
我尝试过:
ipt = wx.TextEntryDialog()
ipt.ShowModal()
result = ipt.GetValue()
ipt.Destroy()
但该框从未出现。
你几乎找到了解决方案!问题在于你正在循环中创建和显示对话框,但之后没有为对话框处理事件。你需要为每个图像创建一个包含图像和文本框的新小部件,然后处理每个文本框的事件。
这是一个修改后的代码版本,它可以做到这一点:
import matplotlib.pyplot as plt
import io
import os
import wx
class ImageLabeler(wx.Frame):
def __init__(self, parent, title):
super().__init__(parent, title=title, size=(800, 600))
self.panel = wx.Panel(self)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.panel.SetSizer(self.sizer)
def OnClick(self, event):
dlg = wx.DirDialog(self, "Specify folder:", style=wx.DD_DEFAULT_STYLE)
if dlg.ShowModal() == wx.ID_OK:
folder = dlg.GetPath()
for image in os.listdir(folder):
self.add_image_and_label(image)
def add_image_and_label(self, image_path):
im = plt.imread(image_path)
plt.imshow(im)
buf = io.BytesIO()
plt.savefig(buf, format='png')
buf.seek(0)
image = wx.Image(buf, wx.BITMAP_TYPE_ANY)
bitmap = wx.StaticBitmap(self.panel, wx.ID_ANY, wx.Bitmap(image))
label_text = wx.StaticText(self.panel, label="Label:")
text_ctrl = wx.TextCtrl(self.panel)
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add(bitmap, 1, wx.ALIGN_CENTER)
hbox.Add(label_text, 0, wx.ALL, 5)
hbox.Add(text_ctrl, 1, wx.ALL, 5)
self.sizer.Add(hbox, 0, wx.ALL, 5)
self.sizer.Fit(self)
# 为每个文本框绑定一个事件处理函数
text_ctrl.Bind(wx.EVT_TEXT_ENTER, self.on_label_entered)
def on_label_entered(self, event):
# 获取输入的标签和对应的图像文件名
text_ctrl = event.GetEventObject()
label = text_ctrl.GetValue()
# 在这里你可以处理标签,例如将其保存到一个列表中
print(f"Label entered: {label}")
app = wx.App()
frame = ImageLabeler(None, 'Image Labeler')
frame.Show()
app.MainLoop()
代码解释:
-
ImageLabeler
类: -
我们创建了一个名为
ImageLabeler
的自定义框架类来容纳我们的应用程序逻辑。 -
它包含一个面板 (
self.panel
) 和一个垂直布局管理器 (self.sizer
) 来组织图像和标签。 -
OnClick
方法: - 该方法与之前相同,它打开一个目录对话框并迭代选定文件夹中的图像。
-
对于每个图像,它调用
add_image_and_label
方法。 -
add_image_and_label
方法: -
该方法加载图像,创建一个
wx.StaticBitmap
来显示它,并创建一个wx.TextCtrl
用于输入标签。 -
它使用
wx.BoxSizer
将图像、标签和文本框水平排列。 -
最后,它将这个水平布局添加到主垂直布局 (
self.sizer
) 中。 -
on_label_entered
方法: -
这是绑定到每个文本框
wx.EVT_TEXT_ENTER
事件的新事件处理函数。当用户在文本框中按下 Enter 键时,将调用此函数。 - 在此函数中,你可以获取输入的标签值并将其与相应的图像相关联。
这个修改后的代码将在窗口中显示图像和标签输入框。你可以在
on_label_entered
方法中添加代码来处理用户输入的标签。