Как создать приложение на python с графическим интерфейсом

Создание приложения для просмотра и редактирования mp3 тегов на python с помощью wxPython

Перевод урока How to Build a Python GUI Application With wxPython, который я сделал с помощью гугл переводчика с небольшими изменениями.

Вступление

Графический пользовательский интерфейс - это приложение, в котором есть кнопки, окна и множество других виджетов, которые пользователь может использовать для взаимодействия с вашим приложением.
Он отображает информацию с помощью значков, меню и графики.
Они обрабатываются с помощью указывающего устройства, такого как клавиатура, мышь, трекбол или стилус.
Хорошим примером может служить веб-браузер.
В нем есть кнопки, вкладки и главное окно, в которое загружается весь контент.
Существует множество наборов инструментов графического пользовательского интерфейса (GUI), которые можно использовать с языком программирования Python.
Основными из них являются Tkinter, wxPython и PyQt.
Каждый из этих наборов инструментов будет работать с Windows, macOS и Linux, а PyQt имеет дополнительные возможности для работы на мобильных устройствах.
В этой статье вы узнаете, как создать графический пользовательский интерфейс с помощью Python и набора инструментов wxPython GUI.
Вот затронутые темы:
• Начало работы с wxPython
• Определение графического интерфейса
• Создание каркасного приложения
• Создание рабочего приложения
Приступим к обучению!

Инструментарий графического интерфейса пользователя wxPython представляет собой оболочку Python для библиотеки C ++ под названием wxWidgets.
wxPython был впервые выпущен в 1998 году. Это кроссплатформенный инструментарий Python с открытым исходным кодом.
Основная особенность wxPython, которая отличается от других наборов инструментов, таких как PyQt и Tkinter, заключается в том, что он использует собственные виджеты платформы, на которой запущен.
Благодаря этому приложения wxPython выглядят как родные для операционной системы, в которой они работают.
PyQt и Tkinter сами рисуют свои виджеты, поэтому они не всегда соответствуют нативным виджетам, хотя PyQt очень близок.
Это не означает, что wxPython не поддерживает настраиваемые виджеты.
Фактически, набор инструментов wxPython включает в себя множество настраиваемых виджетов, а также десятки и десятки основных виджетов.
На странице загрузок wxPython есть раздел Extra Files, который стоит проверить.
https://wxpython.org/pages/downloads/
Здесь можно скачать демонстрационный пакет wxPython. Это симпатичное маленькое приложение, которое демонстрирует подавляющее большинство виджетов, включенных в wxPython.
Демонстрация позволяет разработчику просматривать код на одной вкладке и запускать его на второй вкладке.
Вы даже можете редактировать и повторно запускать код в демонстрации, чтобы увидеть, как ваши изменения влияют на приложение.

Установка wxPython

Вы будете использовать последнюю версию wxPython, wxPython 4, которую также называют wxPython’s Project Phoenix.
Это новая реализация wxPython, направленная на повышение скорости, удобства обслуживания и расширяемости wxPython.
WxPython 3 и wxPython 2 были созданы только для Python 2. Сопровождающий wxPython отклонил множество псевдонимов и очистил много кода, чтобы сделать wxPython более простым и понятным для Python.
Вы можете использовать pip для установки wxPython 4:
$ pip install wxpython

Вы получите раздел предварительных требований на странице Github wxPython, который предоставит информацию для установки wxPython в системах Linux.
Вы также можете заглянуть в раздел Extras Linux, чтобы узнать о Python-пакетах для версий GTK2 и GTK3.
Чтобы установить интересующий пакет, используйте команду, указанную ниже:
pip install -U -f https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-18.04/ wxPython

При необходимости измените команду в соответствии со своей версией OS.

Компоненты GUI

Как упоминалось ранее, GUI - это не что иное, как интерфейс, позволяющий взаимодействовать с пользователем.
Общие компоненты пользовательских интерфейсов:

• Главное окно.
• Меню.
• Панель инструментов.
• Кнопки.
• Области для ввода текста.
• Надписи.

Эти элементы обычно называются виджетами. wxPython поддерживает множество других распространенных виджетов и множество настраиваемых виджетов, которые логически организованы разработчиком для обеспечения взаимодействия с пользователем.

Цикл событий

Графический интерфейс работает, ожидая, пока пользователь выполнит действие. Это называется событие.
Событие происходит, когда пользователь что-то набирает или когда пользователь использует свою мышь, чтобы нажать кнопку или какой-либо виджет, когда приложение находится в фокусе.
Под капотом инструментарий GUI запускает бесконечный цикл, называемый циклом событий.
Задача цикла обработки событий - действовать в соответствии с произошедшими событиями на основе того, что разработчик закодировал для приложения.
Приложение игнорирует событие, когда не может его отследить.
При программировании графического пользовательского интерфейса не забудьте прикрепить виджеты к обработчикам событий, чтобы ваше приложение что-то делало.
Вы также можете заблокировать цикл обработки событий, чтобы графический интерфейс не отвечал, и пользователю будет казаться, что он завис. Это особое соображение, о котором вы должны помнить при работе с циклами событий.
Запускайте специальный поток или процесс, когда графическому интерфейсу пользователя требуется больше четверти секунды для запуска процесса.
Фреймворки wxPython содержат специальные потокобезопасные методы, которые вы можете использовать для обратной связи с вашим приложением. Они сообщают, что поток завершен или ему дано обновление.

создание каркаса приложения

Каркас приложения в основном используется для создания прототипов. Это пользовательский интерфейс, состоящий из виджетов, не содержащих обработчиков событий. Вам просто нужно создать графический интерфейс и показать его заинтересованным сторонам для подписания и не тратить время на логику бэкэнда.
Пример создания приложения Hello World с Python:

import wx
app = wx.App()
framework = wx.Frame(parent=None, title='Hello World')
framework.Show()
app.MainLoop()

В приведенном выше примере есть две части программы: wx.App и wx.Frame.
Первый питоновский объект это app, который требуется для работы с графическим интерфейсом. Он инициирует цикл событий .MainLoop(), о котором вы узнали ранее.
Последняя часть создает окно для взаимодействия с пользователем. Он сообщает wxPython, что у фрейма нет родителя, и его заголовок Hello World.
Свернуть, развернуть и закрыть будут по умолчанию включены в wx.Frame.
Однако большая часть кода wxPython потребует от вас создания wx.Frame в качестве подкласса и других виджетов, чтобы использовать всю мощь инструментария.
Перепишем код с помощью класса:

import wx

class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title='Hello World')
self.Show()

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

Этот код можно использовать в качестве шаблона для вашего приложения.

Виджеты

Набор инструментов wxPython позволяет создавать многофункциональные приложения из более чем сотни виджетов. Но выбрать идеальный виджет из такого большого количества может быть очень сложно, поэтому wxPython включил демонстрацию wxPython, которая содержит фильтр поиска, который поможет вам найти нужный виджет из списка.
Теперь давайте добавим кнопку и позволим пользователю вводить текст, добавив текстовое поле:

import wx
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title='Hello World')
panel = wx.Panel(self)
self.text_ctrl = wx.TextCtrl(panel, pos=(5, 5))
my_btn = wx.Button(panel, label='Press Me', pos=(5, 55))
self.Show()
if __name__ == '__main__':
app = wx.App()
frame = MyFrame()
app.MainLoop()

Когда запустите приложение увидете текстовое поле, в котором можно будет ввести текст и кнопку.
Первый виджет, рекомендуемый для Windows, - это wx.Panel. Он делает цвет фона фрейма правильным оттенком серого. Переход по табуляции отключен без включения панели Windows.
Если панель является единственным дочерним элементом фрейма, она будет автоматически расширена, чтобы заполнить фрейм самим собой.
Следующее, что вам нужно сделать, это добавить wx.TextCtrl к панели.
Первым аргументом всегда является то, к какому родительскому элементу должен перейти виджет почти для всех виджетов. Поэтому, если вы хотите сохранить текстовый элемент управления и кнопку в главной панели, вам необходимо указать родительский элемент.
Вам также необходимо сообщить wxPython о позиции виджета. Вы можете сделать это с помощью параметра pos.
Местоположение по умолчанию - (0,0), т.е. находится в верхнем левом углу родительского элемента. Таким образом, чтобы изменить текстовый элемент управления, вы можете изменить положение фрейма, вы можете сместить его левый угол на 5 пикселей (x) и на 5 пикселей сверху (y). Наконец, вы можете добавить свою кнопку на панель и подписать ее. Вы также можете установить y-координату на 55, чтобы предотвратить перекрытие виджетов.

Абсолютное позиционирование

Абсолютное позиционирование - это метод, используемый в большинстве наборов инструментов графического интерфейса пользователя, с помощью которого вы можете указать точные координаты положения вашего виджета. Могут возникнуть ситуации, когда вам нужно отслеживать все свои виджеты и перемещать виджеты в случае сложного приложения. Это может быть очень непросто. Однако большинство современных наборов инструментов предоставляют решение для этой проблемы, которое мы изучим позже.

Сайзеры (динамический размер)

Сайзеры - это методы определения макета элемента управления в диалоговых окнах wxPython. У них есть возможность создавать диалоги, которые не зависят от платформы. Они управляют расположением виджетов и настраивают их, когда пользователь изменяет размер окна приложения.
Некоторые из основных типов сайзеров, которые обычно используются:
• wx.BoxSizer
• wx.GridSizer
• wx.FlexGridSizer
например сделаем wx.BoxSizer для предыдущего примера:

import wx
class MyFramework(wx.Frame):
def frame(self):
super().frame(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_button = 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__':
application = wx.App()
framework = MyFramework()
application.MainLoop()
В приведенном выше примере создается экземпляр wx.BoxSixer и передается в wx.VERTICAL, что на самом деле является ориентацией виджета, которая подключена в сайзере. Виджеты будут добавлены вертикально сверху вниз. Вы также можете установить ориентацию BoxSizer на wx.HORIZONTAL. В этом случае виджеты добавляются слева направо.
Вы можете использовать .Add() в виджет сайзере, который принимает максимум пять аргументов, как показано ниже:
• window ( the widget )- This is the widget that is added to the sizer.
• proportion - It sets how much space corresponding to other widgets in the sizer will the widget should take. By default, the proportion is zero which leaves the wxPython to its original proportion.
• flag - It allows you to pass in multiple flags by separating them with a pipe character: |. The text control is added using wx.ALL and wx.EXPAND flags. The wx.ALL flag adds a border on all sides of the widget. On the other hand, wx.EXPAND expands the widgets as much as the sizer can be expanded.
• border - This parameter informs wxPython about the number of pixels of border needed around the widget.
• userData - It is a rare argument that is used for resizing in case of complex applications.
Однако в этом примере флаг wx.EXPAND заменен на wx.CENTER для отображения кнопки в центре экрана.
Когда вы запустите код, ваше приложение будет выглядеть примерно так: Запустить код Python

Добавление события

Ваше приложение хоть и выглядит круто, но на самом деле ничего не делает. Созданная вами кнопка ничего не делает при ее нажатии. Дадим кнопке работу:

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-строки. Вы можете прочитать все о них в Python 3 f-Strings: An Improved String Formatting Syntax (Guide).
Вы конечно хотите, чтобы кнопка что-то делала, когда пользователь нажимает на не.
это можно сделать с помощью метода .Bind().
.Bind() принимает такие параметры - событие, к которому вы хотите привязаться, обработчик этого события, необязательный источник и несколько необязательных идентификаторов.
В приведенном выше примере объект кнопки привязан к wx.EVT_BUTTON и указываете вызывать on_press() при срабатывании события.
Событие «запускается», когда пользователь выполняет событие, к которому вы привязаны.
В этом случае настраиваемое событие - это событие нажатия кнопки wx.EVT_BUTTON.
.on_press() принимает второй аргумент, который вы можете вызвать как событие.
Параметр event предполагает, что второй аргумент должен быть объектом события.
Это условно. Вы могли бы назвать это как-нибудь иначе, если бы захотели.
Однако параметр события здесь относится к тому факту, что при вызове этого метода его вторым аргументом должен быть какой-то объект события.
Вы можете получить содержимое текстового элемента управления с помощью метода GetValue() в .button_press.
Затем вы печатаете строку в стандартный вывод в зависимости от содержимого текстового элемента управления.
Теперь, когда у вас есть основы, давайте узнаем, как создать приложение, которое будет делать что-то полезное!

Создание рабочего приложения

Рассмотрим ситуацию, когда вас просят создать редактор тегов MP3.
Первое, что вам нужно сделать, это найти необходимые пакеты.
Если вы выполните поиск в Google по фразе Python mp3 tag editor, вы найдете несколько вариантов, как показано ниже:
• mp3 -tagger
• eyeD3
• mutagen
Из них eyeD3 - лучший выбор, чем два других, так как у него довольно хороший API, который можно использовать, не увязая в спецификации MP3 ID3.
Вы можете установить eyeD3 с помощью pip со своего терминала:

pip install eyed3

Если вы хотите установить eyeD3 в macOS, вам необходимо установить libmagic с помощью brew. Пользователи Linux и Windows могут легко установить с помощью упомянутой выше команды.

Проектирование пользовательского интерфейса

Самое первое, что вы должны сделать перед проектированием интерфейса, - это набросать, как, по вашему мнению, должен выглядеть интерфейс. Пользовательский интерфейс должен выполнять следующие задачи:
• Open up one or more MP3 files.
• Display the current MP3 tags.
• Edit an MP3 tag.
В большинстве пользовательских интерфейсов для открытия файлов или папок используется меню или кнопка.
Для этого вы можете использовать меню «Файл». Поскольку вы, вероятно, захотите увидеть теги для нескольких файлов MP3, вам нужно будет найти виджет, который сможет сделать это в удобной форме.
Что-то табличное со столбцами и строками было бы идеальным, потому что тогда вы можете иметь помеченные столбцы для тегов MP3.
В наборе инструментов wxPython есть несколько виджетов, которые подойдут для этого, из которых два верхних:
• wx.grid.Grid
• wx.ListCtrl
wx.ListCtrl был бы лучшим вариантом из этих двух, поскольку виджет Grid является избыточным и сложным по своей природе.
Наконец, вы можете использовать кнопку для выполнения задач редактирования.

Создание пользовательского интерфейса

Вы можете использовать множество подходов при создании пользовательского интерфейса.
Вы можете следовать шаблону проектирования mvc - модель-представление-контроллер, который используется для разработки пользовательских интерфейсов, который разделяет логику программы на три взаимосвязанных элемента. Вы должны знать, как разделять классы и сколько классов должно быть включено в один файл и так далее.
Однако в этом случае вам нужны только два класса, а именно:
• wx.Panel class
• 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, glob и wx.
Затем создается пользовательский интерфейс путем превращения wx.Panel в подкласс.
Словарь row_obj_dict создан для хранения данных о MP3.
Следующее, что вам нужно сделать, это создать wx.ListCtrl и установить его в режим отчетов, то есть wx.LC_REPORT. Этот флаг отчета является самым популярным среди всех, но вы также можете выбрать свой собственный в зависимости от флага стиля, который вы передаете.
Теперь вам нужно вызвать .InsertColumn(), чтобы ListCtrl имел правильные заголовки, а затем предоставить индекс столбец, его метку и ширину в пикселях столбца.
Наконец, вам нужно добавить кнопку «Изменить», обработчик событий и метод.
Код фрейма следующий:

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()

Этот класс намного проще первого, потому что вам просто нужно установить заголовок фрейма и создать экземпляр класса панели MP3Panel.
Пользовательский интерфейс выглядит почти правильно, но у вас нет меню «Файл». Это делает невозможным добавление MP3 в приложение и редактирование их тегов!
Давай исправим это сейчас. Сделайте работающее приложение Первый шаг к тому, чтобы ваше приложение работало, - это обновить приложение, чтобы в нем было меню «Файл», потому что тогда вы можете добавлять файлы MP3 в свое творение.
В класс wx.Frame почти всегда добавляются меню, поэтому вам нужно изменить этот класс.
Примечание. Некоторые приложения перестали иметь меню в своих приложениях. Одним из первых, кто сделал это, был Microsoft Office, когда они добавили панель ленты. В наборе инструментов wxPython есть настраиваемый виджет, который можно использовать для создания лент в wx.lib.agw.ribbon. Другой тип приложений, в которых в последнее время отсутствуют меню, - это веб-браузеры, такие как Google Chrome и Mozilla Firefox. Сейчас они просто используют панели инструментов.

Сделайте работающее приложение

Давайте узнаем, как добавить строку меню в наше приложение:
Следующее, что мы сделаем, это добавим меню «Файл», чтобы добавить файлы MP3 в приложение, а также отредактировать их теги.
Самое первое, что вам нужно сделать, чтобы ваше приложение заработало, - это обновить класс wx.Frame, включив в него меню «Файл», которое позволит вам добавлять файлы MP3.
Код для добавления строки меню в наше приложение:

class Mp3Frame(wx.Frame):

def __init__(self):
wx.Frame.__init__(self, parent=None,
title='Mp3 Tag Editor')
self.panel = Mp3Panel(self)
self.create_menu()
self.Show()

def create_menu(self):
menu_bar = wx.MenuBar()
file_menu = wx.Menu()
open_folder_menu_item = file_menu.Append(
wx.ID_ANY, 'Open Folder',
'Open a folder with MP3s'
)
menu_bar.Append(file_menu, '&File')
self.Bind(
event=wx.EVT_MENU,
handler=self.on_open_folder,
source=open_folder_menu_item,
)
self.SetMenuBar(menu_bar)

def on_open_folder(self, event):
title = "Choose a directory:"
dlg = wx.DirDialog(self, title,
style=wx.DD_DEFAULT_STYLE)
if dlg.ShowModal() == wx.ID_OK:
self.panel.update_mp3_listing(dlg.GetPath())
dlg.Destroy()

В приведенном выше примере кода .create_menu() вызывается в конструкторе класса, а затем создаются два экземпляра - wx.MenuBar и wx.Menu. Теперь, если вы хотите добавить элемент в меню, вам нужно вызвать .Append() экземпляра меню и передать следующие вещи:
• A unique identifier
• Label
• A help string
После этого вызовите .Append(), чтобы добавить элемент меню в панель меню. Это займет экземпляр меню и метку для меню. Метка называется &File, поэтому создается сочетание клавиш для открытия меню File, используя только клавиатуру.
Теперь вызывается self.Bind() для привязки фрейма к wx.EVT_MENU. Он сообщает wxPython о том, какой обработчик следует использовать и к какому источнику привязать обработчик.
Наконец, вызовите .SetMenuBar фрейма и передайте ему экземпляр строки меню.
Ваше меню теперь добавлено во фрейм.
Теперь вернемся к обработчику события пункта меню:

def on_open_folder(self, event):
title = "Choose a directory:"
dlg = wx.DirDialog(self, title, style=wx.DD_DEFAULT_STYLE)
if dlg.ShowModal() == wx.ID_OK:
self.panel.update_mp3_listing(dlg.GetPath())
dlg.Destroy()

Вы можете использовать wx.DirDialog из wxPython, чтобы правильно выбрать папки с файлами MP3.
Для отображения диалогового окна используйте .ShowModal(). Это отобразит диалоговое окно модально, но не позволит пользователю взаимодействовать с основным приложением.
Вы можете перейти к выбранному пользователем пути с помощью .GetPath(), когда пользователь нажимает кнопку OK.
Этот путь должен быть добавлен к классу панели, и это можно сделать с помощью .update_mp3_listing() панели.
Наконец, вам нужно будет закрыть диалоговое окно, и лучший способ - использовать .Destroy().
Существуют методы закрытия диалогового окна, такие как .Close(), который будет просто диалогом, но не уничтожит его, поэтому .Destroy() является наиболее эффективным вариантом для предотвращения такой ситуации.
Теперь давайте обновим класс MP3Panel, начиная с .update_mp3_listing():

def update_mp3_listing(self, folder_path):
self.current_folder_path = folder_path
self.list_ctrl.ClearAll()
self.list_ctrl.InsertColumn(0, 'Artist', width=140)
self.list_ctrl.InsertColumn(1, 'Album', width=140)
self.list_ctrl.InsertColumn(2, 'Title', width=200)
self.list_ctrl.InsertColumn(3, 'Year', width=200)
mp3s = glob.glob(folder_path + '/*.mp3')
mp3_objects = []
index = 0
for mp3 in mp3s:
mp3_object = eyed3.load(mp3)
self.list_ctrl.InsertItem(index, mp3_object.tag.artist)
self.list_ctrl.SetItem(index, 1, mp3_object.tag.album)
self.list_ctrl.SetItem(index, 2, mp3_object.tag.title)
mp3_objects.append(mp3_object)
self.row_obj_dict[index] = mp3_object
index += 1

В приведенном выше примере текущий каталог установлен на указанную папку, а элемент управления списком очищен. Список элементов управления остается свежим и показывает файлы MP3, с которыми вы в настоящее время работаете. Затем папка берется, и модуль Python globmodule используется для поиска файлов MP3. Затем MP3-файлы зацикливаются и конвертируются в объекты eyed3. Это делается путем вызова .load() eyed3. После этого вы можете добавить исполнителя, альбом и название Mp3 в список управления, если у MP3 есть соответствующие теги. .InsertItem() используется для добавления новой строки в элемент управления списком в первый раз, а SetItem() используется для добавления строк в последующие столбцы.
Последний шаг - сохранить объект MP3 в словаре Python row_obj_dict.
Теперь, чтобы отредактировать теги MP3, вам нужно обновить обработчик событий .on_edit():

def on_edit(self, event):
selection = self.list_ctrl.GetFocusedItem()
if selection >= 0:
mp3 = self.row_obj_dict[selection]
dlg = EditDialog(mp3)
dlg.ShowModal()
self.update_mp3_listing(self.current_folder_path)
dlg.Destroy()

Первое, что вам нужно сделать, это получить выбор пользователя, вызвав метод .GetFocusedItem() элемента управления списком .
Он вернет -1, если пользователь ничего не выберет в элементе управления списком.
Однако, если вы хотите извлечь объект MP3 из словаря, пользователь должен что-то выбрать.
Затем вы можете открыть диалоговое окно редактора тегов MP3, которое будет настраиваемым диалоговым окном. Как и раньше, диалоговое окно отображается модально,
затем последние две строки в .on_edit() выполнят то, что в конечном итоге отобразит информацию о текущем теге MP3.

Создание диалогового окна редактирования

Последний кусок головоломки - создание диалогового окна редактирования тега MP3. Для краткости мы не будем рисовать этот интерфейс, так как он представляет собой серию строк, содержащих метки и текстовые элементы управления. Текстовые элементы управления должны содержать существующую информацию тегов, предварительно заполненную в них. Вы можете создать метку для текстовых элементов управления, создав экземпляры wx.StaticText. Когда вам нужно создать собственный диалог, класс wx.Dialog - ваш друг.
Вы можете использовать это для создания редактора:

class EditDialog(wx.Dialog):
def __init__(self, mp3):
title = f'Editing "{mp3.tag.title}"'
super().__init__(parent=None, title=title)
self.mp3 = mp3
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
self.artist = wx.TextCtrl(
self, value=self.mp3.tag.artist)
self.add_widgets('Artist', self.artist)
self.album = wx.TextCtrl(
self, value=self.mp3.tag.album)
self.add_widgets('Album', self.album)
self.title = wx.TextCtrl(
self, value=self.mp3.tag.title)
self.add_widgets('Title', self.title)
btn_sizer = wx.BoxSizer()
save_btn = wx.Button(self, label='Save')
save_btn.Bind(wx.EVT_BUTTON, self.on_save)
btn_sizer.Add(save_btn, 0, wx.ALL, 5)
btn_sizer.Add(wx.Button(
self, id=wx.ID_CANCEL), 0, wx.ALL, 5)
self.main_sizer.Add(btn_sizer, 0, wx.CENTER)
self.SetSizer(self.main_sizer)

Здесь вы хотите начать с подкласса wx.Dialog и присвоения ему собственного названия на основе названия MP3, который вы редактируете. Затем вы можете создать размер, который хотите использовать, и виджеты. Чтобы упростить задачу, вы можете создать вспомогательный метод с именем .add_widgets() для добавления виджетов wx.StaticText в виде строк с экземплярами текстовых элементов управления. Единственный другой виджет - кнопка «Сохранить».
Давайте теперь напишем метод add_widgets:

def add_widgets(self, label_text, text_ctrl):
row_sizer = wx.BoxSizer(wx.HORIZONTAL)
label = wx.StaticText(self, label=label_text,
size=(50, -1))
row_sizer.Add(label, 0, wx.ALL, 5)
row_sizer.Add(text_ctrl, 1, wx.ALL | wx.EXPAND, 5)
self.main_sizer.Add(row_sizer, 0, wx.EXPAND)

add_widgets() принимает текст метки и экземпляр элемента управления текстом.
Затем он создает горизонтально ориентированный BoxSizer. Затем вы создадите экземпляр wx.StaticText, используя переданный текст в качестве параметра метки. Вы также установите его размер равным 50 пикселей в ширину, а высота по умолчанию установлена ​​на -1. Поскольку вам нужна метка перед текстовым элементом управления, вы сначала добавите виджет StaticText в свой BoxSizer, а затем добавите текстовый элемент управления. Наконец, вы хотите добавить горизонтальный измеритель к вертикальному измерителю верхнего уровня. Вложив размеры друг в друга, вы можете разрабатывать сложные приложения.
Теперь вам нужно создать обработчик события on_save(), чтобы вы могли сохранить свои изменения:

def on_save(self, event):
self.mp3.tag.artist = self.artist.GetValue()
self.mp3.tag.album = self.album.GetValue()
self.mp3.tag.title = self.title.GetValue()
self.mp3.tag.save()
self.Close()

Здесь вы устанавливаете теги для содержимого текстовых элементов управления, а затем вызываете объект eyed3 .save().
Наконец, вы вызываете .Close() диалогового окна.
Причина, по которой вы вызываете здесь .Close() вместо .Destroy(), заключается в том, что вы уже вызываете .Destroy() в .on_edit() вашего подкласса панели.
Ваша работа готова!

Вывод

В этой статье вы узнали много нового о wxPython. Вы познакомились с основами создания приложений с графическим интерфейсом пользователя с помощью wxPython.
Теперь вы знаете больше о следующем:
• Установка wxPython.
• Сравнение абсолютного позиционирования с измерителями
• Как работать с некоторыми виджетами wxPython
• Как работают события в wxPython
• Как создать скелет приложения
Наконец, вы узнали, как создать работающее приложение - редактор тегов MP3.
Вы можете использовать то, что вы узнали из этой статьи, чтобы продолжить улучшать это приложение или, возможно, создать замечательное приложение самостоятельно. Инструментарий графического интерфейса пользователя wxPython надежен и полон интересных виджетов, которые можно использовать для создания кроссплатформенных приложений. Вы ограничены только своим воображением.
Главной особенностью графического интерфейса пользователя wxPython является его надежность и большой набор виджетов, которые можно использовать для создания кроссплатформенных приложений.

Поделитесь с друзьями

комментариев нет

Написать комментарий

Чтобы написать комментарий авторизуйтесь на сайте.