前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用wxPython打造Python图形界面

用wxPython打造Python图形界面

作者头像
AiTechYun
发布2019-05-13 16:47:19
1.7K0
发布2019-05-13 16:47:19
举报
文章被收录于专栏:ATYUN订阅号ATYUN订阅号

制作一个功能应用程序

使应用程序工作的第一步是更新应用程序,使它具有一个文件菜单,因为这样你就可以将MP3文件添加到创建中。菜单几乎总是添加到wx.frame中。这就是你需要修改的类。

注意:有些应用程序已经不再在其应用程序中使用菜单。第一个这样做的是Microsoft Office,他们添加了Ribbon Bar。wxPython工具包有一个自定义小部件,你可以使用它在wx.lib.ag .ribbon中创建ribbon。

另一种最近已经删除菜单的应用程序是web浏览器,比如谷歌Chrome和Mozilla Firefox。现在他们只使用工具栏。

让我们学习如何添加菜单栏到我们的应用程序:

代码语言:javascript
复制
 1 class Mp3Frame(wx.Frame):
 2
 3    def __init__(self):
 4
 5        wx.Frame.__init__(self, parent=None,
 6
 7                          title='Mp3 Tag Editor')
 8
 9        self.panel = Mp3Panel(self)
10
11        self.create_menu()
12
13        self.Show()
14
15    def create_menu(self):
16
17        menu_bar = wx.MenuBar()
18
19        file_menu = wx.Menu()
20
21        open_folder_menu_item = file_menu.Append(
22
23            wx.ID_ANY, 'Open Folder',
24
25            'Open a folder with MP3s'
26
27        )
28
29        menu_bar.Append(file_menu, '&File')
30
31        self.Bind(
32
33            event=wx.EVT_MENU,
34
35            handler=self.on_open_folder,
36
37            source=open_folder_menu_item,
38
39        )
40
41        self.SetMenuBar(menu_bar)
42
43    def on_open_folder(self, event):
44
45        title = "Choose a directory:"
46
47        dlg = wx.DirDialog(self, title,
48
49                           style=wx.DD_DEFAULT_STYLE)
50
51        if dlg.ShowModal() == wx.ID_OK:
52
53            self.panel.update_mp3_listing(dlg.GetPath())
54
55        dlg.Destroy()

在这里,可以在类的构造函数中添加对.create_menu()的调用。然后在.create_menu()本身中你将创建一个wx.menubar实例和一个wx.menu实例。

要将菜单项添加到菜单中,你可以调用菜单实例的.Append(),并将以下内容传递给它:

  • 一个惟一的标识符
  • 新菜单项的标签
  • 一个帮助字符串

接下来,需要将菜单添加到菜单栏,因此需要调用菜单栏的. append()。它接受menu实例和menu的标签。这个标签有点奇怪,因为你将它命名为&File而不是File。&符号告诉wxPython创建一个Alt+F的键盘快捷方式,只使用键盘就可以打开文件菜单。

注意:如果要向应用程序添加键盘快捷方式,则需要使用wx.acceleratotable的实例来创建它们。

要创建事件绑定,需要调用self.Bind(),它将框架绑定到wx.EVT_MENU。当你为菜单事件使用self.Bind()时,你不仅需要告诉wxPython使用哪个处理程序,还需要告诉wxPython将处理程序绑定到哪个源。

最后,你必须调用框架的. setmenubar()并将menubar实例传递给它,以便向用户显示它。

现在你已经把菜单添加到你的框架中,让我们来看看菜单项的事件处理程序,它再次复制如下:

代码语言:javascript
复制
 1 def on_open_folder(self, event):
 2
 3    title = "Choose a directory:"
 4
 5    dlg = wx.DirDialog(self, title, style=wx.DD_DEFAULT_STYLE)
 6
 7    if dlg.ShowModal() == wx.ID_OK:
 8
 9        self.panel.update_mp3_listing(dlg.GetPath())
10
11    dlg.Destroy()

因为你希望用户选择一个包含MP3的文件夹,所以你需要使用Wxpython的wx.dirdialog。wx.dir对话框允许用户只打开目录。

你可以设置对话框的标题和各种样式标志。要显示对话框,需要调用. showmodal()。这将导致对话框以模态显示,这意味着当对话框显示时,用户将无法与主应用程序交互。

如果用户按下对话框的OK按钮,你可以通过对话框的. getpath()获得用户的路径选择。你将希望将该路径传递给panel类,在这里可以通过调用panel的.update_mp3_listing()来实现。

最后,需要关闭对话框。要关闭对话框,推荐的方法是调用它的. destroy()。

对话框确实有一个. close()方法,但它基本上只是隐藏了对话框,并且当你关闭应用程序时它不会自我销毁,这可能会导致一些奇怪的问题,比如你的应用程序现在正在正确地关闭。在对话框中调用. destroy()可以更简单地避免这个问题。

现在让我们更新Mp3Panel类。你可以从更新.update_mp3_listing()开始:

代码语言:javascript
复制
 1 def update_mp3_listing(self, folder_path):
 2
 3    self.current_folder_path = folder_path
 4
 5    self.list_ctrl.ClearAll()
 6
 7    self.list_ctrl.InsertColumn(0, 'Artist', width=140)
 8
 9    self.list_ctrl.InsertColumn(1, 'Album', width=140)
10
11    self.list_ctrl.InsertColumn(2, 'Title', width=200)
12
13    self.list_ctrl.InsertColumn(3, 'Year', width=200)
14
15    mp3s = glob.glob(folder_path + '/*.mp3')
16
17    mp3_objects = []
18
19    index = 0
20
21    for mp3 in mp3s:
22
23        mp3_object = eyed3.load(mp3)
24
25        self.list_ctrl.InsertItem(index,
26
27            mp3_object.tag.artist)
28
29        self.list_ctrl.SetItem(index, 1,
30
31            mp3_object.tag.album)
32
33        self.list_ctrl.SetItem(index, 2,
34
35            mp3_object.tag.title)
36
37        mp3_objects.append(mp3_object)
38
39        self.row_obj_dict[index] = mp3_object
40
41        index += 1

在这里,将当前目录设置为指定的文件夹,然后清除list控件。这使列表控件像一个新的,只显示你当前正在处理的mp3。这也意味着你需要重新插入所有列。

接下来,你将使用传入的文件夹,并使用Python的glob模块搜索MP3文件。

然后你可以循环播放mp3,把它们变成eyed3对象。你可以通过调用eyed3的.load()来实现这一点。假设MP3已经具有适当的标记,然后可以将MP3的艺术家、专辑和标题添加到列表控件中。

有趣的是,向列表控件对象添加新行的方法是对第一列调用. insertitem(),对所有后续列调用SetItem()。

最后一步是将MP3对象保存到Python字典row_obj_dict中。

现在需要更新.on_edit()事件处理程序,以便编辑MP3的标签:

代码语言:javascript
复制
 1 def on_edit(self, event):
 2
 3    selection = self.list_ctrl.GetFocusedItem()
 4
 5    if selection >= 0:
 6
 7        mp3 = self.row_obj_dict[selection]
 8
 9        dlg = EditDialog(mp3)
10
11        dlg.ShowModal()
12
13        self.update_mp3_listing(self.current_folder_path)
14
15        dlg.Destroy()

你需要做的第一件事是通过调用列表控件的. getfocuseditem()获得用户的选择。

如果用户没有在列表控件中选择任何内容,它将返回-1。假设用户确实选择了一些内容,你将希望从字典中提取MP3对象并打开MP3标记编辑器对话框。这将是一个自定义对话框,你将使用它来编辑MP3文件的艺术家、专辑和标题标记。

像往常一样,以模态显示对话框。当对话框关闭时,.on_edit()中的最后两行将开始执行。这两行代码将更新list控件,以便显示用户刚刚编辑并销毁对话框的当前MP3标记信息。

创建编辑对话框

最后一个难题是创建一个MP3标签编辑对话框。为了简单,我们将跳过这个界面的草图,因为它是一系列包含标签和文本控件的行。文本控件中应预先填充现有的标记信息。可以通过创建wx.staticText的实例为文本控件创建标签。

当需要创建自定义对话框时,wx.dialog类是你的朋友。你可以使用它来设计编辑器:

代码语言:javascript
复制
 1 class EditDialog(wx.Dialog):
 2
 3    def __init__(self, mp3):
 4
 5        title = f'Editing "{mp3.tag.title}"'
 6
 7        super().__init__(parent=None, title=title)       
 8
 9        self.mp3 = mp3       
10
11        self.main_sizer = wx.BoxSizer(wx.VERTICAL)       
12
13        self.artist = wx.TextCtrl(
14
15            self, value=self.mp3.tag.artist)
16
17        self.add_widgets('Artist', self.artist)       
18
19        self.album = wx.TextCtrl(
20
21            self, value=self.mp3.tag.album)
22
23        self.add_widgets('Album', self.album)       
24
25        self.title = wx.TextCtrl(
26
27            self, value=self.mp3.tag.title)
28
29        self.add_widgets('Title', self.title)       
30
31        btn_sizer = wx.BoxSizer()
32
33        save_btn = wx.Button(self, label='Save')
34
35        save_btn.Bind(wx.EVT_BUTTON, self.on_save)       
36
37        btn_sizer.Add(save_btn, 0, wx.ALL, 5)
38
39        btn_sizer.Add(wx.Button(
40
41            self, id=wx.ID_CANCEL), 0, wx.ALL, 5)
42
43        self.main_sizer.Add(btn_sizer, 0, wx.CENTER)       
44
45        self.SetSizer(self.main_sizer)

在这里,首先要对wx.dialog进行子分类,并根据正在编辑的MP3的标题为其提供自定义标题。

接下来,你可以创建要使用的sizer和小部件。为了使事情更简单,你可以创建一个名为.add_widgets()的帮助器方法,用于将wx.staticText widgets作为带有文本控件实例的行添加。这里唯一的其他小部件是保存按钮。

接下来我们来编写add_widgets方法:

代码语言:javascript
复制
 1 def add_widgets(self, label_text, text_ctrl):
 2
 3        row_sizer = wx.BoxSizer(wx.HORIZONTAL)
 4
 5        label = wx.StaticText(self, label=label_text,
 6
 7                              size=(50, -1))
 8
 9        row_sizer.Add(label, 0, wx.ALL, 5)
10
11        row_sizer.Add(text_ctrl, 1, wx.ALL | wx.EXPAND, 5)
12
13        self.main_sizer.Add(row_sizer, 0, wx.EXPAND)
14

add_widgets()接受标签的文本和文本控件实例。然后,它创建一个水平方向的BoxSizer。

接下来,你将使用传入的文本为其label参数创建wx.staticText的实例。你还可以将其大小设置为50像素宽,默认高度设置为-1。因为你希望标签位于文本控件之前,所以你将首先向BoxSizer添加StaticText小部件,然后添加文本控件。

最后,要将水平大小调整器添加到顶层垂直大小调整器。通过将sizer彼此嵌套,可以设计复杂的应用程序。

现在,你需要创建on_save()事件处理程序,以便保存更改:

代码语言:javascript
复制
 1 def on_save(self, event):
 2
 3      self.mp3.tag.artist = self.artist.GetValue()
 4
 5      self.mp3.tag.album = self.album.GetValue()
 6
 7      self.mp3.tag.title = self.title.GetValue()
 8
 9      self.mp3.tag.save()
10
11      self.Close()

在这里,你将标记设置为文本控件的内容,然后调用eyed3对象的.save()。最后,调用对话框的.close()。在这里调用.close()而不是.destroy()的原因是你已经在panel子类的.on-edit()中调用了.destroy()。

现在你的应用程序完成了!

结论

在本文中,你了解了很多关于wxpython的知识。你已经熟悉了使用wxpython创建GUI应用程序的基础知识。

你现在了解更多关于以下内容的信息:

  • 如何使用Wxpython的一些小部件
  • Wxpython中的事件如何工作
  • 绝对定位与sizer测量的比较
  • 如何创建框架应用程序

最后,你学习了如何创建一个工作的应用程序,MP3标签编辑器。你可以使用本文中学到的内容来继续增强这个应用程序,或者自己创建一个出色的应用程序。

wxpython gui工具包是一个可靠的、充满了有趣的小部件,可以用来构建跨平台的应用程序。不要让自己的想象力受限,大胆尝试。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-04-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 ATYUN订阅号 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档