There are many graphical user interface (GUI) toolkits that you can use with the Python programming language. The big three are Tkinter, wxPython, and PyQt. Each of these toolkits will work with Windows, macOS, and Linux, with PyQt having the additional capability of working on mobile.
您可以将许多图形用户界面(GUI)工具包与Python编程语言一起使用。 前三个是Tkinter,wxPython和PyQt。 这些工具箱均可以在Windows,macOS和Linux上使用,而PyQt具有在移动设备上工作的附加功能。
A graphical user interface is an application that has buttons, windows, and lots of other widgets that the user can use to interact with your application. A good example would be a web browser. It has buttons, tabs, and a main window where all the content loads.
图形用户界面是具有按钮,窗口和许多其他小部件的应用程序,用户可以使用这些小部件与您的应用程序进行交互。 一个很好的例子是网络浏览器。 它具有按钮,选项卡,以及一个加载所有内容的主窗口。
In this article, you’ll learn how to build a graphical user interface with Python using the wxPython GUI toolkit.
在本文中,您将学习如何使用wxPython GUI工具包通过Python构建图形用户界面。
Here are the topics covered:
这里是涉及的主题:
Let’s start learning!
让我们开始学习!
Free Bonus: Click here to get access to a chapter from Python Tricks: The Book that shows you Python’s best practices with simple examples you can apply instantly to write more beautiful + Pythonic code.
免费红利: 单击此处可访问Python技巧的一章:该书通过简单的示例向您展示了Python的最佳实践,您可以立即应用这些示例编写更精美的Pythonic代码。
The wxPython GUI toolkit is a Python wrapper around a C++ library called wxWidgets. The initial release of wxPython was in 1998, so wxPython has been around quite a long time. wxPython’s primary difference from other toolkits, such as PyQt or Tkinter, is that wxPython uses the actual widgets on the native platform whenever possible. This makes wxPython applications look native to the operating system that it is running on.
wxPython GUI工具包是一个名为wxWidgets的C ++库的Python包装器。 wxPython的最初版本是在1998年,因此wxPython已经存在了很长时间。 wxPython与其他工具包(例如PyQt或Tkinter)的主要区别在于,wxPython会尽可能在本机平台上使用实际的小部件。 这使得wxPython应用程序看起来对运行它的操作系统而言是本机的。
PyQt and Tkinter both draw their widgets themselves, which is why they don’t always match the native widgets, although PyQt is very close.
PyQt和Tkinter都自己绘制窗口小部件,这就是为什么它们并不总是与本地窗口小部件匹配的原因,尽管PyQt非常接近。
This is not to say that wxPython does not support custom widgets. In fact, the wxPython toolkit has many custom widgets included with it, along with dozens upon dozens of core widgets. The wxPython downloads page has a section called Extra Files that is worth checking out.
这并不是说wxPython不支持自定义窗口小部件。 实际上,wxPython工具箱包含许多自定义小部件,以及数十个核心小部件。 wxPython 下载页面上有一个名为Extra Files的部分,值得一试。
Here, there is a download of the wxPython Demo package. This is a nice little application that demonstrates the vast majority of the widgets that are included with wxPython. The demo allows a developer to view the code in one tab and run it in a second tab. You can even edit and re-run the code in the demo to see how your changes affect the application.
在这里,有wxPython演示包的下载。 这是一个很好的小应用程序,它演示了wxPython随附的绝大多数小部件。 该演示使开发人员可以在一个选项卡中查看代码并在第二个选项卡中运行它。 您甚至可以在演示中编辑并重新运行代码,以查看您的更改如何影响应用程序。
You will be using the latest wxPython for this article, which is wxPython 4, also known as the Phoenix release. The wxPython 3 and wxPython 2 versions are built only for Python 2. When Robin Dunn, the primary maintainer of wxPython, created the wxPython 4 release, he deprecated a lot of aliases and cleaned up a lot of code to make wxPython more Pythonic and easier to maintain.
您将在本文中使用最新的wxPython,即wxPython 4 (也称为Phoenix版本)。 wxPython 3和wxPython 2版本仅针对Python 2构建。 wxPython的主要维护者Robin Dunn创建了wxPython 4版本时,他弃用了许多别名并清理了许多代码,以使wxPython更具Pythonic且更易于维护。
You will want to consult the following links if you are migrating from an older version of wxPython to wxPython 4 (Phoenix):
如果要从旧版本的wxPython迁移到wxPython 4(Phoenix),则需要参考以下链接:
The wxPython 4 package is compatible with both Python 2.7 and Python 3.
wxPython 4软件包与Python 2.7和Python 3兼容。
You can now use pip
to install wxPython 4, which was not possible in the legacy versions of wxPython. You can do the following to install it on your machine:
现在,您可以使用pip
安装wxPython 4,这在wxPython的旧版本中是不可能的。 您可以执行以下操作将其安装在计算机上:
$ pip install wxpython
$ pip install wxpython
Note: On Mac OS X you will need a compiler installed such as XCode for the install to complete successfully. Linux may also require you to install some dependencies before the pip
installer will work correctly.
注意:在Mac OS X上,您需要安装编译器(如XCode)才能成功完成安装。 Linux可能还要求您安装一些依赖项,然后pip
安装程序才能正常运行。
For example, I needed to install freeglut3-dev, libgstreamer-plugins-base0.10-dev, and libwebkitgtk-3.0-dev on Xubuntu to get it to install.
例如,我需要在Xubuntu上安装freeglut3-dev , libgstreamer-plugins-base0.10-dev和libwebkitgtk-3.0-dev才能进行安装。
Fortunately, the error messages that pip
displays are helpful in figuring out what is missing, and you can use the prerequisites section on the wxPython Github page to help you find the information you need if you want to install wxPython on Linux.
幸运的是, pip
显示的错误消息有助于找出丢失的内容,如果您想在Linux上安装wxPython,可以使用wxPython Github页面上的前提条件部分来查找所需的信息。
There are some Python wheels available for the most popular Linux versions that you can find in the Extras Linux section with both GTK2 and GTK3 versions. To install one of these wheels, you would use the following command:
在适用于GTK2和GTK3版本的Extras Linux部分中,可以找到一些适用于最受欢迎的Linux版本的Python轮子。 要安装这些轮子之一,请使用以下命令:
Be sure you have modified the command above to match your version of Linux.
确保已修改上面的命令以匹配您的Linux版本。
As was mentioned in the introduction, a graphical user interface (GUI) is an interface that is drawn on the screen for the user to interact with.
如引言中所述,图形用户界面(GUI)是在屏幕上绘制的供用户进行交互的界面。
User interfaces have some common components:
用户界面具有一些通用组件:
All of these items are known generically as widgets. There are many other common widgets and many custom widgets that wxPython supports. A developer will take the widgets and arrange them logically on a window for the user to interact with.
所有这些项目通常称为小部件 。 wxPython支持许多其他常见的小部件和许多自定义小部件。 开发人员将获取这些小部件,并将它们按逻辑排列在一个窗口上,以便用户与之交互。
A graphical user interface works by waiting for the user to do something. The something is called an event. Events happen when the user types something while your application is in focus or when the user uses their mouse to press a button or other widget.
图形用户界面通过等待用户做某事来工作。 这种事情称为事件 。 当用户在应用程序处于焦点状态时键入某些内容时,或者当用户使用鼠标按下按钮或其他小部件时,就会发生事件。
Underneath the covers, the GUI toolkit is running an infinite loop that is called an event loop. The event loop just waits for events to occur and then acts on those events according to what the developer has coded the application to do. When the application doesn’t catch an event, it effectively ignores that it even happened.
在后台,GUI工具包正在运行一个称为事件循环的无限循环 。 事件循环只是等待事件发生,然后根据开发人员对应用程序进行编码的方式对这些事件进行操作。 当应用程序未捕获事件时,它实际上忽略了事件的发生。
When you are programming a graphical user interface, you will want to keep in mind that you will need to hook up each of the widgets to event handlers so that your application will do something.
在编写图形用户界面时,请记住,您需要将每个小部件都连接到事件处理程序,以便您的应用程序可以执行某些操作。
There is a special consideration that you need to keep in mind when working with event loops: they can be blocked. When you block an event loop, the GUI will become unresponsive and appear to freeze to the user.
使用事件循环时,需要特别注意:它们可以被阻塞。 当您阻止事件循环时,GUI将变得无响应,并且似乎冻结给用户。
Any process that you launch in a GUI that will take longer than a quarter second should probably be launched as a separate thread or process. This will prevent your GUI from freezing and give the user a better user experience.
您在GUI中启动将花费四分之一秒以上的任何进程,应该将其作为单独的线程或进程启动。 这将防止您的GUI冻结,并为用户提供更好的用户体验。
The wxPython framework has special thread-safe methods that you can use to communicate back to your application to let it know that the thread is finished or to give it an update.
wxPython框架具有特殊的线程安全方法,可用于与应用程序进行通信,以使其知道线程已完成或对其进行更新。
Let’s create a skeleton application to demonstrate how events work.
让我们创建一个框架应用程序来演示事件如何工作。
An application skeleton in a GUI context is a user interface with widgets that don’t have any event handlers. These are useful for prototyping. You basically just create the GUI and present it to your stakeholders for sign-off before spending a lot of time on the backend logic.
GUI上下文中的应用程序框架是带有小部件的用户界面,这些小部件没有任何事件处理程序。 这些对于原型制作很有用。 您基本上只是创建GUI,然后将其呈现给您的利益相关者以供签署,然后再在后端逻辑上花费大量时间。
Let’s start by creating a Hello World
application with wxPython:
让我们首先使用wxPython创建一个Hello World
应用程序:
import import wx
wx
app app = = wxwx .. AppApp ()
()
frame frame = = wxwx .. FrameFrame (( parentparent == NoneNone , , titletitle == 'Hello World''Hello World' )
)
frameframe .. ShowShow ()
()
appapp .. MainLoopMainLoop ()
()
Note: Mac users may get the following message: This program needs access to the screen. Please run with a Framework build of python, and only when you are logged in on the main display of your Mac. If you see this message and you are not running in a virtualenv, then you need to run your application with pythonw instead of python. If you are running wxPython from within a virtualenv, then see the wxPython wiki for the solution.
注意: Mac用户可能会收到以下消息:该程序需要访问屏幕。 请仅在登录Mac主显示屏时使用Python的Framework构建版本运行。 如果看到此消息,并且您没有在virtualenv中运行,则需要使用pythonw而不是python运行应用程序。 如果您是从virtualenv内部运行wxPython,请参阅wxPython Wiki获取解决方案。
In this example, you have two parts: wx.App
and the wx.Frame
. The wx.App
is wxPython’s application object and is required for running your GUI. The wx.App
starts something called a .MainLoop()
. This is the event loop that you learned about in the previous section.
在此示例中,您分为两部分: wx.App
和wx.Frame
。 wx.App
是wxPython的应用程序对象,是运行GUI所必需的。 wx.App
启动一个名为.MainLoop()
东西。 这是您在上一节中了解的事件循环。
The other piece of the puzzle is wx.Frame
, which will create a window for the user to interact with. In this case, you told wxPython that the frame has no parent and that its title is Hello World
. Here is what it looks like when you run the code:
另一个难题是wx.Frame
,它将为用户创建一个与之交互的窗口。 在这种情况下,您告诉wxPython该框架没有父框架,其标题是Hello World
。 这是运行代码时的样子:
Note: The application will look different when you run it on Mac or Windows.
注意:在Mac或Windows上运行时,该应用程序看起来会有所不同。
By default, a wx.Frame
will include minimize, maximize, and exit buttons along the top. You won’t normally create an application in this manner though. Most wxPython code will require you to subclass the wx.Frame
and other widgets so that you can get the full power of the toolkit.
默认情况下, wx.Frame
将在顶部包括最小化,最大化和退出按钮。 但是,您通常不会以这种方式创建应用程序。 大多数wxPython代码将要求您将wx.Frame
和其他小部件作为子类,以便获得该工具包的全部功能。
Let’s take a moment and rewrite your code as a class:
让我们花点时间将您的代码重写为一个类:
You can use this code as a template for your application. However, this application doesn’t do very much, so let’s take a moment to learn a little about some of the other widgets you could add.
您可以将此代码用作应用程序的模板。 但是,该应用程序的功能不是很多,因此让我们花一点时间来学习一些您可以添加的其他小部件。
The wxPython toolkit has more than one hundred widgets to choose from. This allows you to create rich applications, but it can also be daunting trying to figure out which widget to use. This is why the wxPython Demo is helpful, as it has a search filter that you can use to help you find the widgets that might apply to your project.
wxPython工具箱有一百多种小部件可供选择。 这使您可以创建功能丰富的应用程序,但是尝试弄清楚要使用哪个窗口小部件也可能令人生畏。 这就是wxPython演示之所以有用的原因,因为它具有一个搜索过滤器,可用于帮助您找到可能适用于您的项目的小部件。
Most GUI applications allow the user to enter some text and press a button. Let’s go ahead and add those widgets:
大多数GUI应用程序允许用户输入一些文本并按下按钮。 让我们继续添加这些小部件:
import import wx
wx
class class MyFrameMyFrame (( wxwx .. FrameFrame ):
):
def def __init____init__ (( selfself ):
):
supersuper ()() .. __init____init__ (( parentparent == NoneNone , , titletitle == 'Hello World''Hello World' )
)
panel panel = = wxwx .. PanelPanel (( selfself )
)
selfself .. text_ctrl text_ctrl = = wxwx .. TextCtrlTextCtrl (( panelpanel , , pospos == (( 55 , , 55 ))
))
my_btn my_btn = = wxwx .. ButtonButton (( panelpanel , , labellabel == 'Press Me''Press Me' , , pospos == (( 55 , , 5555 ))
))
selfself .. ShowShow ()
()
if if __name__ __name__ == == '__main__''__main__' :
:
app app = = wxwx .. AppApp ()
()
frame frame = = MyFrameMyFrame ()
()
appapp .. MainLoopMainLoop ()
()
When you run this code, your application should look like this:
运行此代码时,您的应用程序应如下所示:
The first widget you need to add is something called wx.Panel
. This widget is not required, but recommended. On Windows, you are actually required to use a Panel so that the background color of the frame is the right shade of gray. Tab traversal is disabled without a Panel on Windows.
您需要添加的第一wx.Panel
部件是wx.Panel
。 此小部件不是必需的,但建议使用。 在Windows上,实际上需要使用“面板”,以便框架的背景色为灰色的正确阴影。 如果没有Windows上的面板,则无法遍历选项卡遍历。
When you add the panel widget to a frame and the panel is the sole child of the frame, it will automatically expand to fill the frame with itself.
当您将面板小部件添加到框架中并且面板是框架的唯一子代时,它将自动扩展以将其自身填充到框架中。
The next step is to add a wx.TextCtrl
to the panel. The first argument for almost all widgets is which parent the widget should go onto. In this case, you want the text control and the button to be on top of the panel, so it is the parent you specify.
下一步是将wx.TextCtrl
添加到面板。 几乎所有小部件的第一个参数是小部件应转到哪个父级。 在这种情况下,您希望文本控件和按钮位于面板顶部,因此它是您指定的父级。
You also need to tell wxPython where to place the widget, which you can do by passing in a position via the pos
parameter. In wxPython, the origin location is (0,0) which is the upper left corner of the parent. So for the text control, you tell wxPython that you want to position its top left corner 5 pixels from the left (x) and 5 pixels from the top (y).
您还需要告诉wxPython小部件的放置位置,您可以通过pos
参数传入一个位置来完成。 在wxPython中,原点位置是(0,0),即父级的左上角。 因此,对于文本控件,您告诉wxPython您想将其左上角的位置从左(x)移至5个像素,从顶部(y)移至5个像素。
Then you add your button to the panel and give it a label. To prevent the widgets from overlapping, you need to set the y-coordinate to 55 for the button’s position.
然后,将按钮添加到面板中并为其添加标签。 为了防止小部件重叠,您需要将按钮位置的y坐标设置为55。
When you provide exact coordinates for your widget’s position, the technique that you used is called absolute positioning. Most GUI toolkits provide this capability, but it’s not actually recommended.
当您为小部件的位置提供精确的坐标时,您使用的技术称为绝对定位 。 大多数GUI工具箱都提供此功能,但实际上不建议这样做。
As your application becomes more complex, it becomes difficult to keep track of all the widget locations and if you have to move the widgets around. Resetting all those positions becomes a nightmare.
随着您的应用程序变得越来越复杂,跟踪所有窗口小部件的位置以及是否必须移动窗口小部件都变得很困难。 重置所有这些职位成为噩梦。
Fortunately all modern GUI toolkits provide a solution for this, which is what you will learn about next.
幸运的是,所有现代GUI工具包都为此提供了一个解决方案,这是您接下来将要学习的内容。
The wxPython toolkit includes sizers, which are used for creating dynamic layouts. They manage the placement of your widgets for you and will adjust them when you resize the application window. Other GUI toolkits will refer to sizers as layouts, which is what PyQt does.
wxPython工具箱包含sizer ,用于创建动态布局。 它们为您管理小部件的放置,并在您调整应用程序窗口的大小时对其进行调整。 其他GUI工具箱会将大小调整器称为布局,这是PyQt所做的。
Here are the primary types of sizers that you will see used most often:
以下是您最常使用的上浆机的主要类型:
wx.BoxSizer
wx.GridSizer
wx.FlexGridSizer
wx.BoxSizer
wx.GridSizer
wx.FlexGridSizer
Let’s add a wx.BoxSizer
to your example and see if we can make it work a bit more nicely:
让我们在示例中添加一个wx.BoxSizer
,看看是否可以使其工作得更好:
Here you create an instance of a wx.BoxSizer
and pass it wx.VERTICAL
, which is the orientation that widgets are added to the sizer.
在这里,您将创建一个wx.BoxSizer
实例,并将其传递wx.VERTICAL
,这是将小部件添加到sizer的方向。
In this case, the widgets will be added vertically, which means they will be added one at a time from top to bottom. You may also set a BoxSizer’s orientation to wx.HORIZONTAL
. When you do that, the widgets would be added from left to right.
在这种情况下,小部件将被垂直添加,这意味着它们将从顶部到底部一次被添加。 您也可以将BoxSizer的方向设置为wx.HORIZONTAL
。 当您这样做时,将从左到右添加小部件。
To add a widget to a sizer, you will use .Add()
. It accepts up to five arguments:
要将小部件添加到sizer,您将使用.Add()
。 它最多接受五个参数:
window
(the widget)proportion
flag
border
userData
window
(小部件) proportion
flag
border
userData
The window
argument is the widget to be added while proportion
sets how much space relative to other widgets in the sizer this particular widget should take. By default, it is zero, which tells wxPython to leave the widget at its default proportion.
window
参数是要添加的window
小部件,而proportion
设置此特定窗口小部件应占用的大小相对于其他窗口小部件的空间。 默认情况下,它为零,这告诉wxPython将小部件保留为其默认比例。
The third argument is flag
. You can actually pass in multiple flags if you wish as long as you separate them with a pipe character: |
. The wxPython toolkit uses |
to add flags using a series of bitwise ORs.
第三个参数是flag
。 实际上,你可以通过在多个标志,如果你愿意,只要你有一个管道字符分隔它们: |
。 wxPython工具箱使用|
使用一系列按位OR来添加标志。
In this example, you add the text control with the wx.ALL
and wx.EXPAND
flags. The wx.ALL
flag tells wxPython that you want to add a border on all sides of the widget while wx.EXPAND
makes the widgets expand as much as they can within the sizer.
在本示例中,您将添加带有wx.ALL
和wx.EXPAND
标志的文本控件。 wx.ALL
标志告诉wxPython您想在小部件的所有侧面上添加边框,而wx.EXPAND
使小部件在sizer中最大程度地扩展。
Finally, you have the border
parameter, which tells wxPython how many pixels of border you want around the widget. The userData
parameter is only used when you want to do something complex with your sizing of the widget and is actually quite rare to see in practice.
最后,您具有border
参数,该参数告诉wxPython您希望小部件周围多少个边框像素。 仅当您要对小部件的大小进行复杂的操作时才使用userData
参数,而实际上在实践中很少见到。
Adding the button to the sizer follows the exact same steps. However, to make things a bit more interesting, I went ahead and switched out the wx.EXPAND
flag for wx.CENTER
so that the button would be centered on-screen.
将按钮添加到sizer中的步骤完全相同。 然而,为了使事情更有趣,我继续交换了wx.EXPAND
标志wx.CENTER
使该按钮会在屏幕上居中。
When you run this version of the code, your application should look like the following:
当您运行此版本的代码时,您的应用程序应如下所示:
If you’d like to learn more about sizers, the wxPython documentation has a nice page on the topic.
如果您想了解有关sizer的更多信息, wxPython文档中有一个关于该主题的漂亮页面。
While your application looks more interesting visually, it still doesn’t really do anything. For example, if you press the button, nothing really happens.
尽管您的应用程序在外观上看起来更有趣,但实际上并没有执行任何操作。 例如,如果您按下按钮,则什么也没有发生。
Let’s give the button a job:
让我们给按钮做个工作:
import import wx
wx
class class MyFrameMyFrame (( wxwx .. FrameFrame ):
):
def def __init____init__ (( selfself ):
):
supersuper ()() .. __init____init__ (( parentparent == NoneNone , , titletitle == 'Hello World''Hello World' )
)
panel panel = = wxwx .. PanelPanel (( selfself )
)
my_sizer my_sizer = = wxwx .. BoxSizerBoxSizer (( wxwx .. VERTICALVERTICAL )
)
selfself .. text_ctrl text_ctrl = = wxwx .. TextCtrlTextCtrl (( panelpanel )
)
my_sizermy_sizer .. AddAdd (( selfself .. text_ctrltext_ctrl , , 00 , , wxwx .. ALL ALL | | wxwx .. EXPANDEXPAND , , 55 )
)
my_btn my_btn = = wxwx .. ButtonButton (( panelpanel , , labellabel == 'Press Me''Press Me' )
)
my_btnmy_btn .. BindBind (( wxwx .. EVT_BUTTONEVT_BUTTON , , selfself .. on_presson_press )
)
my_sizermy_sizer .. AddAdd (( my_btnmy_btn , , 00 , , wxwx .. ALL ALL | | wxwx .. CENTERCENTER , , 55 )
)
panelpanel .. SetSizerSetSizer (( my_sizermy_sizer )
)
selfself .. ShowShow ()
()
def def on_presson_press (( selfself , , eventevent ):
):
value value = = selfself .. text_ctrltext_ctrl .. GetValueGetValue ()
()
if if not not valuevalue :
:
printprint (( "You didn't enter anything!""You didn't enter anything!" )
)
elseelse :
:
printprint (( ff 'You typed: "'You typed: " {value}{value} "'"' )
)
if if __name__ __name__ == == '__main__''__main__' :
:
app app = = wxwx .. AppApp ()
()
frame frame = = MyFrameMyFrame ()
()
appapp .. MainLoopMainLoop ()
()
The widgets in wxPython allow you to attach event bindings to them so that they can respond to certain types of events.
wxPython中的小部件允许您将事件绑定附加到它们,以便它们可以响应某些类型的事件。
Note: The code block above uses f-strings. You can read all about them in Python 3’s f-Strings: An Improved String Formatting Syntax (Guide).
注意:上面的代码块使用f字符串。 您可以在Python 3的f字符串:改进的字符串格式语法(指南)中阅读有关它们的全部信息。
You want the button to do something when the user presses it. You can accomplish this by calling the button’s .Bind()
method. .Bind()
takes the event you want to bind to, the handler to call when the event happens, an optional source, and a couple of optional ids.
您希望按钮在用户按下时执行某些操作。 您可以通过调用按钮的.Bind()
方法来完成此操作。 .Bind()
接收要绑定的事件,事件发生时调用的处理程序,可选的源以及几个可选的id。
In this example, you bind your button object to the wx.EVT_BUTTON
event and tell it to call on_press()
when that event gets fired.
在此示例中,将按钮对象绑定到wx.EVT_BUTTON
事件,并在触发该事件时告诉它调用on_press()
。
An event gets “fired” when the user does the event you have bound to. In this case, the event that you set up is the button press event, wx.EVT_BUTTON
.
当用户执行您绑定的事件时,事件将被“触发”。 在这种情况下,您设置的事件是按钮按下事件wx.EVT_BUTTON
。
.on_press()
accepts a second argument that you can call event
. This is by convention. You could call it something else if you wanted to. However, the event parameter here refers to the fact that when this method is called, its second argument should be an event object of some sort.
.on_press()
接受可以调用event
的第二个参数。 这是按照惯例。 如果需要,可以将其命名为其他名称。 但是,这里的事件参数是指这样的事实:调用此方法时,其第二个参数应该是某种事件对象。
Within .on_press()
, you can get the text control’s contents by calling its GetValue()
method. You then print a string to stdout depending on what the contents of the text control is.
在.on_press()
,可以通过调用文本控件的GetValue()
方法来获取其内容。 然后,根据文本控件的内容将字符串输出到stdout。
Now that you have the basics out of the way, let’s learn how to create an application that does something useful!
现在您已经掌握了基础知识,让我们学习如何创建一个有用的应用程序!
The first step when creating something new is to figure out what you want to create. In this case, I have taken the liberty of making that decision for you. You will learn how to create a MP3 tag editor! The next step when creating something new is to find out what packages can help you accomplish your task.
创建新内容的第一步是弄清楚您要创建的内容。 在这种情况下,我可以自由地为您做出决定。 您将学习如何创建MP3标签编辑器! 创建新内容时的下一步是找出哪些软件包可以帮助您完成任务。
If you do a Google search for Python mp3 tagging
, you will find you have several options:
如果您在Google搜索中搜索Python mp3 tagging
,则会发现您有以下几种选择:
mp3-tagger
eyeD3
mutagen
mp3-tagger
eyeD3
mutagen
I tried out a couple of these and decided that eyeD3 had a nice API that you could use without getting bogged down with the MP3’s ID3 specification. You can install eyeD3 using pip
, like this:
我尝试了其中的几个,并决定eyeD3有一个不错的API,您可以使用它而不会陷入MP3的ID3规范的泥潭。 您可以使用pip
安装eyeD3 ,如下所示:
When installing this package on macOS, you may need to install libmagic
using brew
. Windows and Linux users shouldn’t have any issues installing eyeD3.
在macOS上安装此软件包时,可能需要使用brew
安装libmagic
。 Windows和Linux用户在安装eyeD3时应该没有任何问题。
When it comes to designing an interface, it’s always nice to just kind of sketch out how you think the user interface should look.
在设计界面时,总是最好的一点就是勾勒出用户界面的外观。
You will need to be able to do the following:
您将需要执行以下操作:
Most user interfaces use a menu or a button for opening files or folders. You can go with a File menu for this. Since you will probably want to see tags for multiple MP3 files, you will need to find a widget that can do this in a nice manner.
大多数用户界面使用菜单或按钮来打开文件或文件夹。 您可以为此使用“文件”菜单。 由于您可能希望查看多个MP3文件的标签,因此需要找到一个可以很好地执行此操作的小部件。
Something that is tabular with columns and rows would be ideal because then you can have labeled columns for the MP3 tags. The wxPython toolkit has a few widgets that would work for this, with the top two being the following:
用列和行制成表格的内容将是理想的,因为这样您就可以为MP3标签添加带标签的列。 wxPython工具箱具有一些可用于此目的的小部件,其中前两个是:
wx.grid.Grid
wx.ListCtrl
wx.grid.Grid
wx.ListCtrl
You should use wx.ListCtrl
in this case as the Grid
widget is overkill, and frankly it is also quite a bit more complex. Finally, you need a button to use to edit a selected MP3’s tag.
在这种情况下,您应该使用wx.ListCtrl
,因为Grid
小部件过大,坦白地说,它也要复杂得多。 最后,您需要一个按钮来编辑选定的MP3标签。
Now that you know what you want, you can draw it up:
现在,您知道想要什么了,可以草拟一下:
The illustration above gives us an idea of how the application should look. Now that you know what you want to do, it’s time to code!
上面的插图使我们对应用程序的外观有所了解。 既然您知道要做什么,就该编写代码了!
There are many different approaches when it comes to writing a new application. For example, do you need to follow the Model-View-Controller design pattern? How do you split up the classes? One class per file? There are many such questions, and as you get more experienced with GUI design, you’ll know how you want to answer them.
编写新应用程序时,有许多不同的方法。 例如,您需要遵循Model-View-Controller设计模式吗? 您如何划分课程? 每个文件一类? 这样的问题很多,而且随着您对GUI设计的经验越来越丰富,您将知道如何回答这些问题。
In your case, you really only need two classes:
就您而言,您实际上只需要两个类:
wx.Panel
classwx.Frame
classwx.Panel
类 wx.Frame
类 You could argue for creating a controller type module as well, but for something like this, you really do not need it. A case could also be made for putting each class into its own module, but to keep it compact, you will create a single Python file for all of your code.
您也可以为创建一个控制器类型的模块而争论,但是对于这样的事情,您确实不需要它。 也可以将每个类放入其自己的模块中,但为了使其紧凑,您将为所有代码创建一个Python文件。
Let’s start with imports and the panel class:
让我们从导入和面板类开始:
import import eyed3
eyed3
import import glob
glob
import import wx
wx
class class Mp3PanelMp3Panel (( wxwx .. PanelPanel ):
):
def def __init____init__ (( selfself , , parentparent ):
):
supersuper ()() .. __init____init__ (( parentparent )
)
main_sizer main_sizer = = wxwx .. BoxSizerBoxSizer (( wxwx .. VERTICALVERTICAL )
)
selfself .. row_obj_dict row_obj_dict = = {}
{}
selfself .. list_ctrl list_ctrl = = wxwx .. ListCtrlListCtrl (
(
selfself , , sizesize == (( -- 11 , , 100100 ),
),
stylestyle == wxwx .. LC_REPORT LC_REPORT | | wxwx .. BORDER_SUNKEN
BORDER_SUNKEN
)
)
selfself .. list_ctrllist_ctrl .. InsertColumnInsertColumn (( 00 , , 'Artist''Artist' , , widthwidth == 140140 )
)
selfself .. list_ctrllist_ctrl .. InsertColumnInsertColumn (( 11 , , 'Album''Album' , , widthwidth == 140140 )
)
selfself .. list_ctrllist_ctrl .. InsertColumnInsertColumn (( 22 , , 'Title''Title' , , widthwidth == 200200 )
)
main_sizermain_sizer .. AddAdd (( selfself .. list_ctrllist_ctrl , , 00 , , wxwx .. ALL ALL | | wxwx .. EXPANDEXPAND , , 55 )
)
edit_button edit_button = = wxwx .. ButtonButton (( selfself , , labellabel == 'Edit''Edit' )
)
edit_buttonedit_button .. BindBind (( wxwx .. EVT_BUTTONEVT_BUTTON , , selfself .. on_editon_edit )
)
main_sizermain_sizer .. AddAdd (( edit_buttonedit_button , , 00 , , wxwx .. ALL ALL | | wxwx .. CENTERCENTER , , 55 )
)
selfself .. SetSizerSetSizer (( main_sizermain_sizer )
)
def def on_editon_edit (( selfself , , eventevent ):
):
printprint (( 'in on_edit''in on_edit' )
)
def def update_mp3_listingupdate_mp3_listing (( selfself , , folder_pathfolder_path ):
):
printprint (( folder_pathfolder_path )
)
Here, you import the eyed3
package, Python’s glob
package, and the wx
package for your user interface. Next, you subclass wx.Panel
and create your user interface. You need a dictionary for storing data about your MP3s, which you can name row_obj_dict
.
在这里,您为用户界面导入eyed3
包,Python的glob
包和wx
包。 接下来,子类化wx.Panel
并创建用户界面。 您需要一个字典来存储有关MP3的数据,您可以将其命名为row_obj_dict
。
Then you create a wx.ListCtrl
and set it to report mode (wx.LC_REPORT
) with a sunken border (wx.BORDER_SUNKEN
). The list control can take on a few other forms depending on the style flag that you pass in, but the report flag is the most popular.
然后创建一个wx.ListCtrl
并将其设置为报告模式( wx.LC_REPORT
采用了下沉式边框() wx.BORDER_SUNKEN
)。 列表控件可以采用其他几种形式,具体取决于您传入的样式标志,但是报告标志是最流行的。
To make the ListCtrl
have the correct headers, you will need to call .InsertColumn()
for each column header. You then supply the index of the column, its label, and how wide in pixels the column should be.
若要使ListCtrl
具有正确的标题,您将需要为每个列标题调用.InsertColumn()
。 然后,您可以提供列的索引,其标签以及该列应有的像素宽度。
The last step is to add your Edit
button, an event handler, and a method. You can create the binding to the event and leave the method that it calls empty for now.
最后一步是添加“ Edit
按钮,事件处理程序和方法。 您可以创建与事件的绑定,并暂时将其调用的方法保留为空。
Now you should write the code for the frame:
现在,您应该为框架编写代码:
This class is much simpler than the first one in that all you need to do is set the title of the frame and instantiate the panel class, Mp3Panel
. When you are all done, your user interface should look like this:
该类比第一个类简单得多,因为您所需要做的就是设置框架的标题并实例化面板类Mp3Panel
。 完成后,您的用户界面应如下所示:
The user interface looks almost right, but you don’t have a File menu. This makes it impossible to add MP3s to the application and edit their tags!
用户界面看起来几乎正确,但是您没有“文件”菜单。 这样就不可能将MP3添加到应用程序中并编辑其标签!
Let’s fix that now.
让我们现在修复它。
The first step in making your application work is to update the application so that it has a File menu because then you can add MP3 files to your creation. Menus are almost always added to the wx.Frame
class, so that is the class you need to modify.
使应用程序正常工作的第一步是更新应用程序,使其具有“文件”菜单,因为这样您便可以将MP3文件添加到创建的文件中。 菜单几乎总是添加到wx.Frame
类中,因此这是您需要修改的类。
Note: Some applications have moved away from having menus in their applications. One of the first to do so was Microsoft Office when they added the Ribbon Bar. The wxPython toolkit has a custom widget that you can use to create ribbons in wx.lib.agw.ribbon
.
注意:一些应用程序已远离其应用程序中的菜单。 当他们添加功能区栏时,第一个这样做的公司就是Microsoft Office。 wxPython工具箱具有一个自定义窗口小部件,可用于在wx.lib.agw.ribbon
创建功能wx.lib.agw.ribbon
。
The other type of application that has dropped menus of late are web browsers, such as Google Chrome and Mozilla Firefox. They just use toolbars nowadays.
最近删除菜单的另一种应用程序是Web浏览器,例如Google Chrome和Mozilla Firefox。 如今,他们只使用工具栏。
Let’s learn how to add a menu bar to our application:
让我们学习如何向我们的应用程序添加菜单栏:
class class Mp3FrameMp3Frame (( wxwx .. FrameFrame ):
):
def def __init____init__ (( selfself ):
):
wxwx .. FrameFrame .. __init____init__ (( selfself , , parentparent == NoneNone ,
,
titletitle == 'Mp3 Tag Editor''Mp3 Tag Editor' )
)
selfself .. panel panel = = Mp3PanelMp3Panel (( selfself )
)
selfself .. create_menucreate_menu ()
()
selfself .. ShowShow ()
()
def def create_menucreate_menu (( selfself ):
):
menu_bar menu_bar = = wxwx .. MenuBarMenuBar ()
()
file_menu file_menu = = wxwx .. MenuMenu ()
()
open_folder_menu_item open_folder_menu_item = = file_menufile_menu .. AppendAppend (
(
wxwx .. ID_ANYID_ANY , , 'Open Folder''Open Folder' ,
,
'Open a folder with MP3s'
'Open a folder with MP3s'
)
)
menu_barmenu_bar .. AppendAppend (( file_menufile_menu , , '&File''&File' )
)
selfself .. BindBind (
(
eventevent == wxwx .. EVT_MENUEVT_MENU ,
,
handlerhandler == selfself .. on_open_folderon_open_folder ,
,
sourcesource == open_folder_menu_itemopen_folder_menu_item ,
,
)
)
selfself .. SetMenuBarSetMenuBar (( menu_barmenu_bar )
)
def def on_open_folderon_open_folder (( selfself , , eventevent ):
):
title title = = "Choose a directory:"
"Choose a directory:"
dlg dlg = = wxwx .. DirDialogDirDialog (( selfself , , titletitle ,
,
stylestyle == wxwx .. DD_DEFAULT_STYLEDD_DEFAULT_STYLE )
)
if if dlgdlg .. ShowModalShowModal () () == == wxwx .. ID_OKID_OK :
:
selfself .. panelpanel .. update_mp3_listingupdate_mp3_listing (( dlgdlg .. GetPathGetPath ())
())
dlgdlg .. DestroyDestroy ()
()
Here, you add a call to .create_menu()
within the class’s constructor. Then in .create_menu()
itself, you will create a wx.MenuBar
instance and a wx.Menu
instance.
在这里,您可以在类的构造函数中添加对.create_menu()
的调用。 然后,在.create_menu()
本身中,将创建一个wx.MenuBar
实例和一个wx.Menu
实例。
To add a menu item to a menu, you call the menu instance’s .Append()
and pass it the following:
要将菜单项添加到菜单,请调用菜单实例的.Append()
并将以下内容传递给它:
Next, you need to add the menu to the menubar, so you will need to call the menubar’s .Append()
. It takes the menu instance and the label for menu. This label is a bit odd in that you called it &File
instead of File
. The ampersand tells wxPython to create a keyboard shortcut of Alt+F to open the File
menu using just your keyboard.
接下来,您需要将菜单添加到菜单栏,因此需要调用菜单栏的.Append()
。 它带有菜单实例和菜单标签。 这个标签有点奇怪,因为您将其称为&File
而不是File
。 “与”号告诉wxPython创建Alt + F键盘快捷键,仅使用键盘即可打开“ File
菜单。
Note: If you would like to add keyboard shortcuts to your application, then you will want to use an instance of wx.AcceleratorTable
to create them. You can read more about Accerator Tables in the wxPython documentation.
注意:如果要向应用程序添加键盘快捷键,则需要使用wx.AcceleratorTable
实例创建它们。 您可以在wxPython 文档中阅读有关加速器表的更多信息。
To create an event binding, you will need to call self.Bind()
, which binds the frame to wx.EVT_MENU
. When you use self.Bind()
for a menu event, you need to not only tell wxPython which handler
to use, but also which source
to bind the handler to.
要创建事件绑定,您需要调用self.Bind()
,它将框架绑定到wx.EVT_MENU
。 当将self.Bind()
用于菜单事件时,不仅需要告诉wxPython使用哪个handler
,还需要告诉将handler
绑定到哪个source
。
Finally, you must call the frame’s .SetMenuBar()
and pass it the menubar instance for it to be shown to the user.
最后,必须调用框架的.SetMenuBar()
并将其传递给菜单栏实例,以使其显示给用户。
Now that you have the menu added to your frame, let’s go over the menu item’s event handler, which is reproduced again below:
现在,您已经将菜单添加到框架中,让我们看一下菜单项的事件处理程序,该事件处理程序在下面再次再现:
Since you want the user to choose a folder that contains MP3s, you will want to use wxPython’s wx.DirDialog
. The wx.DirDialog
allows the user to only open directories.
由于希望用户选择包含MP3的文件夹,因此需要使用wxPython的wx.DirDialog
。 wx.DirDialog
允许用户仅打开目录。
You can set the dialog’s title and various style flags. To show the dialog, you will need to call .ShowModal()
. This will cause the dialog to show modally, which means that the user won’t be able to interact with your main application while the dialog is shown.
您可以设置对话框的标题和各种样式标志。 要显示该对话框,您需要调用.ShowModal()
。 这将导致对话框以模态显示,这意味着在显示对话框时,用户将无法与您的主应用程序进行交互。
If the user presses the dialog’s OK button, you can get the user’s path choice via the dialog’s .GetPath()
. You will want to pass that path to your panel class, which you can do here by calling the panel’s .update_mp3_listing()
.
如果用户按下对话框的“确定”按钮,则可以通过对话框的.GetPath()
获得用户的路径选择。 您将需要将该路径传递给面板类,您可以在这里通过调用面板的.update_mp3_listing()
。
Finally you need to close the dialog. To close a dialog, the recommended method is to call its .Destroy()
.
最后,您需要关闭对话框。 要关闭对话框,建议的方法是调用其.Destroy()
。
Dialogs do have a .Close()
method, but that basically just hides the dialog, and it will not destroy itself when you close your application, which can lead to weird issues such as your application now shutting down properly. It’s simpler to call .Destroy()
on the dialog to prevent this issue.
对话框确实具有.Close()
方法,但是基本上只是隐藏对话框,并且在关闭应用程序时不会破坏自身,这可能导致奇怪的问题,例如您的应用程序现在可以正常关闭。 在对话框上调用.Destroy()
更容易地避免此问题。
Now let’s update your Mp3Panel
class. You can start by updating .update_mp3_listing()
:
现在,让我们更新您的Mp3Panel
类。 您可以通过更新.update_mp3_listing()
:
def def update_mp3_listingupdate_mp3_listing (( selfself , , folder_pathfolder_path ):
):
selfself .. current_folder_path current_folder_path = = folder_path
folder_path
selfself .. list_ctrllist_ctrl .. ClearAllClearAll ()
()
selfself .. list_ctrllist_ctrl .. InsertColumnInsertColumn (( 00 , , 'Artist''Artist' , , widthwidth == 140140 )
)
selfself .. list_ctrllist_ctrl .. InsertColumnInsertColumn (( 11 , , 'Album''Album' , , widthwidth == 140140 )
)
selfself .. list_ctrllist_ctrl .. InsertColumnInsertColumn (( 22 , , 'Title''Title' , , widthwidth == 200200 )
)
selfself .. list_ctrllist_ctrl .. InsertColumnInsertColumn (( 33 , , 'Year''Year' , , widthwidth == 200200 )
)
mp3s mp3s = = globglob .. globglob (( folder_path folder_path + + '/*.mp3''/*.mp3' )
)
mp3_objects mp3_objects = = []
[]
index index = = 0
0
for for mp3 mp3 in in mp3smp3s :
:
mp3_object mp3_object = = eyed3eyed3 .. loadload (( mp3mp3 )
)
selfself .. list_ctrllist_ctrl .. InsertItemInsertItem (( indexindex ,
,
mp3_objectmp3_object .. tagtag .. artistartist )
)
selfself .. list_ctrllist_ctrl .. SetItemSetItem (( indexindex , , 11 ,
,
mp3_objectmp3_object .. tagtag .. albumalbum )
)
selfself .. list_ctrllist_ctrl .. SetItemSetItem (( indexindex , , 22 ,
,
mp3_objectmp3_object .. tagtag .. titletitle )
)
mp3_objectsmp3_objects .. appendappend (( mp3_objectmp3_object )
)
selfself .. row_obj_dictrow_obj_dict [[ indexindex ] ] = = mp3_object
mp3_object
index index += += 1
1
Here you set the current directory to the specified folder and then you clear the list control. This keeps the list control fresh and only showing the MP3s that you are currently working on. That also means that you need to re-insert all the columns again.
在这里,将当前目录设置为指定的文件夹,然后清除列表控件。 这样可以使列表控件保持最新状态,并且仅显示您当前正在使用的MP3。 这也意味着您需要再次重新插入所有列。
Next, you’ll want to take the folder that was passed in and use Python’s glob
module to search for MP3 files.
接下来,您将要获取传入的文件夹,并使用Python的glob
模块搜索MP3文件。
Then you can loop over the MP3s and turn them into eyed3
objects. You can do this by calling the .load()
of eyed3
. Assuming that the MP3s have the appropriate tags already, you can then add the artist, album, and title of the MP3 to the list control.
然后,您可以循环播放MP3,并将它们变成eyed3
对象。 您可以通过调用eyed3
.load()
来eyed3
。 假设MP3已经具有适当的标签,则可以将MP3的艺术家,专辑和标题添加到列表控件中。
Interestingly, the method of adding a new row to a list control object is by calling .InsertItem()
for the first column and SetItem()
for all the subsequent columns.
有趣的是,添加一个新行清单控制对象的方法是通过调用.InsertItem()
为第一列和SetItem()
的所有后续列。
The last step is to save off your MP3 object to your Python dictionary, row_obj_dict
.
最后一步是将MP3对象保存到Python字典row_obj_dict
。
Now you need to update the .on_edit()
event handler so that you can edit an MP3’s tags:
现在,您需要更新.on_edit()
事件处理程序,以便可以编辑MP3的标签:
The first thing you need to do is get the user’s selection by calling the list control’s .GetFocusedItem()
.
您需要做的第一件事是通过调用列表控件的.GetFocusedItem()
获得用户的选择。
If the user has not selected anything in the list control, it will return -1
. Assuming that the user did select something, you will want to extract the MP3 object from your dictionary and open a MP3 tag editor dialog. This will be a custom dialog that you will use to edit the artist, album, and title tags of the MP3 file.
如果用户没有在列表控件中选择任何内容,它将返回-1
。 假设用户确实选择了某些内容,您将需要从字典中提取MP3对象并打开MP3标签编辑器对话框。 这将是一个自定义对话框,您可以使用该对话框来编辑MP3文件的艺术家,专辑和标题标签。
As usual, show the dialog modally. When the dialog closes, the last two lines in .on_edit()
will execute. These two lines will update the list control so it displays the current MP3 tag information that the user just edited and destroy the dialog.
与往常一样,以模态显示对话框。 对话框关闭时, .on_edit()
的最后两行将执行。 这两行将更新列表控件,因此它将显示用户刚刚编辑的当前MP3标签信息,并破坏对话框。
The final piece of the puzzle is creating an MP3 tag editing dialog. For brevity, we will skip sketching out this interface as it is a series of rows that contains labels and text controls. The text controls should have the existing tag information pre-populated within them. You can create a label for the text controls by creating instances of wx.StaticText
.
难题的最后一步是创建MP3标签编辑对话框。 为简便起见,我们将略过此接口的草图,因为它是包含标签和文本控件的一系列行。 文本控件应在其中预先填充现有的标签信息。 您可以通过创建wx.StaticText
实例来为文本控件创建标签。
When you need to create a custom dialog, the wx.Dialog
class is your friend. You can use that to design the editor:
当您需要创建自定义对话框时, wx.Dialog
类就是您的朋友。 您可以使用它来设计编辑器:
class class EditDialogEditDialog (( wxwx .. DialogDialog ):
):
def def __init____init__ (( selfself , , mp3mp3 ):
):
title title = = ff 'Editing "'Editing " {mp3.tag.title}{mp3.tag.title} "'
"'
supersuper ()() .. __init____init__ (( parentparent == NoneNone , , titletitle == titletitle )
)
selfself .. mp3 mp3 = = mp3
mp3
selfself .. main_sizer main_sizer = = wxwx .. BoxSizerBoxSizer (( wxwx .. VERTICALVERTICAL )
)
selfself .. artist artist = = wxwx .. TextCtrlTextCtrl (
(
selfself , , valuevalue == selfself .. mp3mp3 .. tagtag .. artistartist )
)
selfself .. add_widgetsadd_widgets (( 'Artist''Artist' , , selfself .. artistartist )
)
selfself .. album album = = wxwx .. TextCtrlTextCtrl (
(
selfself , , valuevalue == selfself .. mp3mp3 .. tagtag .. albumalbum )
)
selfself .. add_widgetsadd_widgets (( 'Album''Album' , , selfself .. albumalbum )
)
selfself .. title title = = wxwx .. TextCtrlTextCtrl (
(
selfself , , valuevalue == selfself .. mp3mp3 .. tagtag .. titletitle )
)
selfself .. add_widgetsadd_widgets (( 'Title''Title' , , selfself .. titletitle )
)
btn_sizer btn_sizer = = wxwx .. BoxSizerBoxSizer ()
()
save_btn save_btn = = wxwx .. ButtonButton (( selfself , , labellabel == 'Save''Save' )
)
save_btnsave_btn .. BindBind (( wxwx .. EVT_BUTTONEVT_BUTTON , , selfself .. on_saveon_save )
)
btn_sizerbtn_sizer .. AddAdd (( save_btnsave_btn , , 00 , , wxwx .. ALLALL , , 55 )
)
btn_sizerbtn_sizer .. AddAdd (( wxwx .. ButtonButton (
(
selfself , , idid == wxwx .. ID_CANCELID_CANCEL ), ), 00 , , wxwx .. ALLALL , , 55 )
)
selfself .. main_sizermain_sizer .. AddAdd (( btn_sizerbtn_sizer , , 00 , , wxwx .. CENTERCENTER )
)
selfself .. SetSizerSetSizer (( selfself .. main_sizermain_sizer )
)
Here you want to start off by sub-classing wx.Dialog
and giving it a custom title based on the title of the MP3 that you are editing.
在这里,您想通过对wx.Dialog
进行子wx.Dialog
并基于您正在编辑的MP3的标题为其提供自定义标题来开始。
Next you can create the sizer you want to use and the widgets. To make things easier, you can create a helper method called .add_widgets()
for adding the wx.StaticText
widgets as rows with the text control instances. The only other widget here is the Save button.
接下来,您可以创建要使用的大小调整器和小部件。 为了使事情变得容易,可以创建一个名为.add_widgets()
的帮助程序方法,以将wx.StaticText
小部件添加为带有文本控件实例的行。 这里唯一的其他小部件是“保存”按钮。
Let’s write the add_widgets
method next:
接下来让我们编写add_widgets
方法:
add_widgets()
takes the label’s text and the text control instance. It then creates a horizontally oriented BoxSizer
.
add_widgets()
获取标签的文本和文本控件实例。 然后,它创建一个水平方向的BoxSizer
。
Next you will create an instance of wx.StaticText
using the passed-in text for its label parameter. You will also set its size to be 50
pixels wide and the default height is set with a -1
. Since you want the label before the text control, you will add the StaticText widget to your BoxSizer first and then add the text control .
接下来,您将使用传入的文本作为其label参数创建wx.StaticText
的实例。 您还将其大小设置为50
像素宽,默认高度设置为-1
。 由于您希望标签位于文本控件之前,因此您将首先将StaticText小部件添加到BoxSizer中,然后再添加文本控件。
Finally, you want to add the horizontal sizer to the top level vertical sizer. By nesting the sizers in each other, you can design complex applications.
最后,您想将水平尺寸调整器添加到顶级垂直尺寸调整器。 通过将大小调整器彼此嵌套,可以设计复杂的应用程序。
Now you will need to create the on_save()
event handler so that you can save your changes:
现在,您将需要创建on_save()
事件处理程序,以便保存更改:
def def on_saveon_save (( selfself , , eventevent ):
):
selfself .. mp3mp3 .. tagtag .. artist artist = = selfself .. artistartist .. GetValueGetValue ()
()
selfself .. mp3mp3 .. tagtag .. album album = = selfself .. albumalbum .. GetValueGetValue ()
()
selfself .. mp3mp3 .. tagtag .. title title = = selfself .. titletitle .. GetValueGetValue ()
()
selfself .. mp3mp3 .. tagtag .. savesave ()
()
selfself .. CloseClose ()
()
Here you set the tags to the contents of the text controls and then call the eyed3
object’s .save()
. Finally, you call the .Close()
of the dialog. The reason you call .Close()
here instead of .Destroy()
is that you already call .Destroy()
in the .on_edit()
of your panel subclass.
在这里,您可以将标签设置为文本控件的内容,然后调用eyed3
对象的.save()
。 最后,调用对话框的.Close()
。 你打电话的原因。 这里的Close()
而不是.Destroy()
是因为您已经在面板子类的.Destroy()
中调用了.on_edit()
。
Now your application is complete!
现在您的申请已经完成!
You learned a lot about wxPython in this article. You became familiar with the basics of creating GUI applications using wxPython.
您在本文中学到了很多关于wxPython的知识。 您已熟悉使用wxPython创建GUI应用程序的基础知识。
You now know more about the following:
现在,您对以下内容有了更多的了解:
Finally you learned how to create a working application, an MP3 tag editor. You can use what you learned in this article to continue to enhance this application or perhaps create an amazing application on your own.
最后,您学习了如何创建可运行的应用程序,即MP3标签编辑器 。 您可以使用从本文中学到的知识来继续增强此应用程序,或者自己创建一个出色的应用程序。
The wxPython GUI toolkit is robust and full of interesting widgets that you can use to build cross-platform applications. You are limited by only your imagination.
wxPython GUI工具箱功能强大且充满了有趣的小部件,可用于构建跨平台应用程序。 您仅受您的想象力限制。
If you would like to learn more about wxPython, you can check out some of the following links:
如果您想了解有关wxPython的更多信息,可以查看以下一些链接:
For more information on what else you can do with Python, you might want to check out What Can I Do with Python? If you’d like to learn more about Python’s super()
, then Supercharge Your Classes With Python super() may be just right for you.
有关使用Python还能做什么的更多信息,您可能需要查看Python可以做什么? 如果您想了解有关Python的super()
更多信息,那么使用Python super()对类进行增压可能很适合您。
You can also download the code for the MP3 tag editor application that you created in this article if you want to study it more in depth.
如果您想更深入地研究它,还可以下载本文中创建的MP3标签编辑器应用程序的代码 。
翻译自: https://www.pybloggers.com/2019/03/how-to-build-a-python-gui-application-with-wxpython/