用wxPython打造Python图形界面(中)

2019年04月24日 由 sunlei 发表 80603 0


上一篇文章,我们进行了以下几个部分,在这一篇我们接着往下进行。

前文回顾:用wxPython打造Python图形界面(上)

本文目录:

  • 绝对定位

  • 分级器(动态分级)

  • 添加一个事件

  • 创建工作应用程序

  • 设计用户界面

  • 创建用户界面


绝对定位

当你为小部件的位置提供精确的坐标时,使用的技术称为绝对定位。大多数GUI工具包都提供了这种功能,但实际上并不推荐使用这种功能。

随着应用程序变得越来越复杂,要跟踪所有小部件的位置以及是否必须移动小部件就变得非常困难。重置所有这些位置将成为一场噩梦。

幸运的是,所有现代GUI工具包都为此提供了一个解决方案,这是你接下来要学习的内容。

分级器(动态分级)

wxPython工具包包括用于创建动态布局的sizer。它们为你管理小部件的位置,并在你调整应用程序窗口大小时对其进行调整。其他GUI工具包将sizer称为布局,PyQt就是这样做的。

以下是你将看到最常用的几种主要sizer类型:

  • BoxSizer

  • GridSizer

  • FlexGridSizer


加上wx.BoxSizer的例子,看看我们是否可以让它更好地工作:
import wx
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title='Hello World')
panel = wx.Panel(self)
my_sizer = wx.BoxSizer(wx.VERTICAL)
self.text_ctrl = wx.TextCtrl(panel)
my_sizer.Add(self.text_ctrl, 0, wx.ALL | wx.EXPAND, 5)
my_btn = wx.Button(panel, label='Press Me')
my_sizer.Add(my_btn, 0, wx.ALL | wx.CENTER, 5)
panel.SetSizer(my_sizer)
self.Show()

if __name__ == '__main__':
app = wx.App()
frame = MyFrame()
app.MainLoop()

 

这里创建一个wx.boxsizer实例。拳击手,并将其传递给wx.vertical,这是将小部件添加到sizer的方向。

在本例中,小部件将垂直添加,这意味着它们将依次从上到下逐个添加。你还可以将BoxSizer的方向设置为wx.HORIZONTAL。当你这样做时,小部件将从左到右添加。

要将小部件添加到sizer,你将使用. add()。它最多接受5个参数

  • 窗口(小部件)

  • 比例

  • 旗帜

  • 边境

  • 用户数据


window参数是要添加的小部件,而proportion设置相对于sizer中其他小部件的空间大小。默认情况下,它是零,它告诉wxpython将小部件保留在其默认比例。

第三个参数是flag。如果你希望传递多个标志,只要用管道字符分隔它们:。wxpython工具包使用添加使用一系列按位ORS的标志。

在本例中,将添加带有wx.all和wx.expand标志的文本控件。wx.all标志告诉wxpython要在小部件的所有边上添加边框,而wx.expand使小部件在sizer中尽可能地展开。

最后,你还有border参数,它告诉wxpython你想要在小部件周围有多少像素的border。只有当你想对小部件进行复杂的调整时,才使用userdata参数,实际上在实践中很少看到它。

向sizer添加按钮的步骤完全相同。但是,为了让事情变得更有趣,我打开了wx.center的wx.expand标志,以便按钮在屏幕上居中。

当你运行这个版本的代码时,你的应用程序应该如下所示:



添加一个事件

虽然你的应用程序在视觉上看起来更有趣,但它仍然没什么用。例如,如果你按下按钮,什么都不会发生。

所以让我们给按钮一个任务:
import wx
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title='Hello World')
panel = wx.Panel(self)
my_sizer = wx.BoxSizer(wx.VERTICAL)
self.text_ctrl = wx.TextCtrl(panel)
my_sizer.Add(self.text_ctrl, 0, wx.ALL | wx.EXPAND, 5)
my_btn = wx.Button(panel, label='Press Me')
my_btn.Bind(wx.EVT_BUTTON, self.on_press)
my_sizer.Add(my_btn, 0, wx.ALL | wx.CENTER, 5)
panel.SetSizer(my_sizer)
self.Show()

def on_press(self, event):
value = self.text_ctrl.GetValue()
if not value:
print("You didn't enter anything!")
else:
print(f'You typed: "{value}"')

if __name__ == '__main__':
app = wx.App()
frame = MyFrame()
app.MainLoop()

wxPython中的小部件允许你将事件绑定附加到它们,以便它们能够响应特定类型的事件。

注意:上面的代码块使用f-string。

当用户按下按钮时,你希望该按钮执行某些操作。你可以通过调用按钮的. bind()方法来实现这一点,. bind()获取你希望绑定到的事件、事件发生时要调用的处理程序、一个可选源和几个可选id。

在本例中,将button对象绑定到wx.evt_button事件,并告诉它在触发该事件时调用on_press()。

当用户执行所绑定的事件时,事件将被“触发”。在本例中,你设置的事件是按钮按下事件wx.EVT_BUTTON。

.on_press()接受第二个可以调用event的参数。这是惯例。如果你愿意,你可以叫它别的名字。然而,这里的event参数指的是这样一个事实:当调用这个方法时,它的第二个参数应该是某种类型的event对象。

在.on_press()中,你可以通过调用文本控件的GetValue()方法来获取文本控件的内容。然后根据文本控件的内容将字符串打印到stdout。

现在你已经掌握了基本知识,让我们学习如何创建一个做一些有用的事情的应用程序!

创建工作应用程序

创建新东西的第一步是弄清楚你想要创建什么。在这种情况下,我冒昧地为你做了这个决定。你将学习如何创建一个MP3标签编辑器!创建新东西的下一步是找出哪些包可以帮助你完成任务。

如果你做一个谷歌搜索Python mp3标签,你会发现你有几个选项:

  • mp3-tagger

  • eyeD3

  • mutagen


我试用了其中的一些,认为eyeD3有一个很好的API,你可以使用它而不会被MP3的ID3规范所困扰。你可以使用pip安装eyeD3,如下所示:
$ pip install eyed3

在macOS上安装这个包时,可能需要使用brew安装libmagic。Windows和Linux用户安装eyeD3应该没有任何问题。

设计用户界面

当涉及到设计一个界面的时候,最好能大致勾勒出你认为用户界面应该是什么样的。

你需要具备以下能力:

  • 打开一个或多个MP3文件

  • 显示当前MP3标签

  • 编辑MP3标签


大多数用户界面使用菜单或按钮来打开文件或文件夹。你可以使用文件菜单执行此操作。由于你可能希望看到多个MP3文件的标记,因此需要找到一个小部件,它可以以一种良好的方式完成这一任务。

用列和行组成的表格是理想的,因为这样你就可以为MP3标记列。wxPython工具包有几个小部件可以实现这一点,前两个小部件如下:

  • grid.Grid

  • ListCtrl


在这种情况下,你应该使用wx.listcrl,因为网格小部件过于复杂,坦率地说,它也相当复杂。最后,你需要一个按钮来编辑选定的MP3标签。

现在你知道你想要什么了,你可以把它画出来:



上面的插图让我们了解了应用程序的外观。现在你知道你想做什么了,是时候编码了!

创建用户界面

在编写新应用程序时,有许多不同的方法。例如,你是否需要遵循模型-视图-控制器设计模式?你是怎么划分等级的?每个文件一个类?有很多这样的问题,随着你对GUI设计有了更多的经验,你将知道如何回答它们。

在你的例子中,你只需要两个类:

  • A wx.Panel class

  • A wx.Frame class


你也可以创建控制器类型模块,但是对于这样的事情,你实际上并不需要它。也可以将每个类放到它自己的模块中,但是为了保持紧凑,你需要为所有代码创建一个Python文件。

让我们从导入和面板类开始:
import eyed3

import glob

import wx

class Mp3Panel(wx.Panel):

def __init__(self, parent):

super().__init__(parent)

main_sizer = wx.BoxSizer(wx.VERTICAL)

self.row_obj_dict = {}

self.list_ctrl = wx.ListCtrl(

self, size=(-1, 100),

style=wx.LC_REPORT | wx.BORDER_SUNKEN

)

self.list_ctrl.InsertColumn(0, 'Artist', width=140)

self.list_ctrl.InsertColumn(1, 'Album', width=140)

self.list_ctrl.InsertColumn(2, 'Title', width=200)

main_sizer.Add(self.list_ctrl, 0, wx.ALL | wx.EXPAND, 5)

edit_button = wx.Button(self, label='Edit')

edit_button.Bind(wx.EVT_BUTTON, self.on_edit)

main_sizer.Add(edit_button, 0, wx.ALL | wx.CENTER, 5)

self.SetSizer(main_sizer)

def on_edit(self, event):

print('in on_edit')

def update_mp3_listing(self, folder_path):

print(folder_path)

在这里,你为你的用户界面导入了eyed3包、Python的glob包和wx包。接下来,将子类wx.pane子类化并创建用户界面。你需要一个字典来存储有关mp3的数据,可以将其命名为row_obj_dict。

然后创建一个wx.listcrl并将其设置为具有凹陷边框(wx.border_u sunken)的报告模式(wx.lc_ report)。根据传入的样式标志,列表控件可以采用其他几种形式,但报表标志最受欢迎。

要使ListCtrl具有正确的标题,需要为每个列标题调用. insertcolumn()。然后提供列的索引、标签以及列的宽度(以像素为单位)。

最后一步是添加编辑按钮、事件处理程序和方法。你可以创建到事件的绑定,并将其调用的方法暂时保留为空。

现在你应该为框架编写代码:
class Mp3Frame(wx.Frame):   

def __init__(self):

super().__init__(parent=None,

title='Mp3 Tag Editor')

self.panel = Mp3Panel(self)

self.Show()


if __name__ == '__main__':

app = wx.App(False)

frame = Mp3Frame()

app.MainLoop()

这个类比第一个类简单得多,你只需设置框架的标题并实例化panel类Mp3Panel。当你完成所有操作后,你的用户界面应该如下所示:

 



用户界面看起来几乎正确,但是没有文件菜单。这使得向应用程序添加mp3并编辑它们的标记是不可能的!

 

下一篇我们来解决这个问题。
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消