Russian (Pусский) translation by Yuri Yuriev (you can also view the original English article)
Платформа Android предоставляет ресурсы для управления воспроизведением мультимедиа, которые ваши приложения могут использовать для создания интерфейса между пользователем и его музыкальными файлами. В этой серии уроков мы создадим базовый музыкальный плеер для Android. Приложение представит список песен на устройстве, чтобы пользователь мог выбирать их для воспроизведения. Приложение будет управлять воспроизведением и продолжит исполнение, когда пользователь выйдет из приложения, при этом будет отображаться уведомление.
Введение
Для создания music player потребуется класс ContentResolver
для извлечения треков на устройстве, класс MediaPlayer
для воспроизведения звука и класс MediaController
для управления воспроизведением. Мы также будем использовать Service
для воспроизведения звука, когда пользователь не взаимодействует напрямую с приложением. Дальше можете не смотреть, если вы промежуточный разработчик Android, и, если уже создали несколько приложений, вам будет неинтересно. Вот предварительный вид готового приложения:
В этом уроке мы создадим приложение и запросим пользовательское устройство для аудиофайлов с использованием классов ContentResolver
и Cursor
. В следующей части мы будем использовать образец Adapter
для показа песен в виде списка, начала воспроизведения при выборе элемента из списка. В последнем выпуске серии мы используем класс MediaController
, чтобы дать пользователю контроль над воспроизведением, реализовать функции перемотки вперёд и назад и включить функцию shuffle. По окончании серии мы рассмотрим другие аспекты воспроизведения media, которые могут улучшить приложение, такие как обработка фокуса аудио, представление медиафайлов в разных видах и воспроизведение потокового media .
1. Создание и настройка нового проекта
Шаг 1
Создайте новый проект Android. Если вы используете Eclipse, то пусть IDE (Integrated Development Environment) создаст для вас основной класс Activity
и файл макета. Для некоторых кодов, которые мы используем в этой серии, понадобится минимальный уровень API 16, так что вам нужно будет сделать дополнительные шаги для поддержки более старых версий. Когда проект будет создан, откройте файл Manifest проекта. Внутри элемента manifest
добавьте следующее разрешение:
<uses-permission android:name="android.permission.WAKE_LOCK" />
Мы сделаем это разрешение, чтобы воспроизведение музыки продолжалось, когда устройство не работает. В вашем Manifest должен быть элемент для основного класса Activity
. Добавьте следующие атрибуты в элемент activity
, чтобы установить screenOrientation
и launchMode
:
<activity android:name="com.example.musicplayer.MainActivity" android:label="@string/app_name" android:launchMode="singleTop" android:screenOrientation="portrait" >
Для простоты мы будем придерживаться книжной ориентации. launchMode
поможет процессу перехода к приложению после его удаления. Мы отобразим уведомление о текущей песне, нажатие на уведомление вернёт пользователя в приложение. Мы также будем использовать класс Service
для воспроизведения музыки. Добавьте следующую строку в Manifest проекта внутри элемента application
и после элемента activity
:
<service android:name="com.example.musicplayer.MusicService" />
Измените имя пакета, как хотите и измените имя класса, если хотите.
Шаг 2
Откройте основной файл layout проекта и замените его на следующий layout:
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="#FF330000" tools:context=".MainActivity" > <ListView android:id="@+id/song_list" android:layout_width="fill_parent" android:layout_height="wrap_content" > </ListView> </LinearLayout>
Обязательно измените атрибут tools:context, если ваш основной класс Activity
называется по-другому. Макет включает ListView
, в котором мы представим список песен.
Мы собираемся включить два пункта меню для переключения функции перемешивания и выхода из приложения. Откройте файл главного меню (res/menu/main.xml) и замените его содержимое следующим:
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/action_shuffle" android:icon="@drawable/rand" android:orderInCategory="1" android:showAsAction="always" android:title="Shuffle"/> <item android:id="@+id/action_end" android:icon="@drawable/end" android:orderInCategory="2" android:showAsAction="always" android:title="End"/> </menu>
Если нравится, вы можете хранить строки заголовка в файле res/values/strings.xml. Эти два элемента относятся к drawable файлам. Создайте собственные или используйте эти два изображения для начала:
Мы будем использовать и значок уведомления о воспроизведении. Создайте его или используйте следующий:
Код будет ссылаться на изображения, используя имена rand, end и play, поэтому убедитесь, что вы используете одни и те же имена файлов. Скопируйте изображения в папку (-и) drawables вашего проекта. Мы будем реализовывать эти действия позже.
2. Запрос устройства для песен
Шаг 1
Попробуем запросить устройство пользователя для аудиофайлов. Во-первых, добавьте новый класс Song
. Мы будем использовать этот класс для моделирования данных одного звукового файла. В объявлении класса добавьте три переменные экземпляра данных, которые мы сохраним для каждого трека:
private long id; private String title; private String artist;
Затем добавьте метод конструктора, в котором мы создаём экземпляры переменных:
public Song(long songID, String songTitle, String songArtist) { id=songID; title=songTitle; artist=songArtist; }
Наконец, добавьте методы get для переменных экземпляра:
public long getID(){return id;} public String getTitle(){return title;} public String getArtist(){return artist;}
Если вы планируете использовать больше информации о треке, вы можете добавить дополнительные переменные экземпляра в класс.
Шаг 2
Откройте основной класс Activity
и добавьте imports:
import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import android.net.Uri; import android.content.ContentResolver; import android.database.Cursor; import android.widget.ListView;
Объявите следующие переменные экземпляра перед методом onCreate
:
private ArrayList<Song> songList; private ListView songView;
Мы будем хранить песни в списке и отображать их в экземпляре ListView
в главном layout. В onCreate
после установки вида содержимого извлеките экземпляр ListView
, используя ID, который мы дали ему в главном макете:
songView = (ListView)findViewById(R.id.song_list);
Создайте список, как показано ниже:
songList = new ArrayList<Song>();
Затем в объявлении основного класса Activity
после существующих методов создайте вспомогательный метод для извлечения информации о звуковом файле:
public void getSongList() { //retrieve song info }
Внутри этого метода создайте экземпляр ContentResolver
, извлеките URI для внешних музыкальных файлов и создайте экземпляр Cursor
, используя экземпляр ContentResolver
для запроса музыкальных файлов:
ContentResolver musicResolver = getContentResolver(); Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; Cursor musicCursor = musicResolver.query(musicUri, null, null, null, null);
Теперь мы можем перебрать результаты, сначала проверив, что у нас достоверные данные:
if(musicCursor!=null && musicCursor.moveToFirst()){ //get columns int titleColumn = musicCursor.getColumnIndex (android.provider.MediaStore.Audio.Media.TITLE); int idColumn = musicCursor.getColumnIndex (android.provider.MediaStore.Audio.Media._ID); int artistColumn = musicCursor.getColumnIndex (android.provider.MediaStore.Audio.Media.ARTIST); //add songs to list do { long thisId = musicCursor.getLong(idColumn); String thisTitle = musicCursor.getString(titleColumn); String thisArtist = musicCursor.getString(artistColumn); songList.add(new Song(thisId, thisTitle, thisArtist)); } while (musicCursor.moveToNext()); }
Сначала мы извлекаем индексы столбцов для интересующих нас элементов данных для каждой песни, затем мы используем их для создания нового объекта Song
и добавления его в список, перед тем как продолжить обзор результатов.
Вернитесь в onCreate
после кода, который мы добавили, вызовите этот новый метод:
getSongList();
3. Отображение композиций
Шаг 1
Теперь мы можем отобразить список песен в пользовательском интерфейсе. В методе onCreate
после вызова вспомогательного метода, который мы создали минуту назад, давайте отсортируем данные так, чтобы песни представлялись в алфавитном порядке:
Collections.sort(songList, new Comparator<Song>(){ public int compare(Song a, Song b){ return a.getTitle().compareTo(b.getTitle()); } });
Мы используем переменную title
в классе Song
, используя добавленные методы get, чтобы реализовать метод compare
, сортируя песни по заголовкам.
Шаг 2
Определим layout для представления каждой песни в списке. Добавьте новый файл в папку res/layout вашего проекта, назвав его song.xml и введя следующее:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="songPicked" android:orientation="vertical" android:padding="5dp" > <TextView android:id="@+id/song_title" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="#FFFFFF99" android:textSize="20sp" android:textStyle="bold" /> <TextView android:id="@+id/song_artist" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="#FFFFFF99" android:textSize="18sp" /> </LinearLayout>
Не стесняйтесь изменять layout по своему вкусу. Каждая песня в списке будет представлена строками названия и артиста, поэтому мы будем использовать TextViews
для отображения этих данных. Обратите внимание: в теге открытия LinearLayout
указан атрибут onClick
. Мы будем использовать этот метод в основном классе Activity
, чтобы реагировать на выбор песни в списке, проигрывая песню, представленную элементом списка, который был выбран.
Шаг 3
Мы будем использовать Adapter для отображения песен в виде списка. Добавьте в приложение новый класс SongAdapter или назовите иначе. При создании класса назначьте ему суперкласс android.widget.BaseAdapter
. Eclipse должен вставить следующую схему:
public class SongAdapter extends BaseAdapter { @Override public int getCount() { // TODO Auto-generated method stub return 0; } @Override public Object getItem(int arg0) { // TODO Auto-generated method stub return null; } @Override public long getItemId(int arg0) { // TODO Auto-generated method stub return 0; } @Override public View getView(int arg0, View arg1, ViewGroup arg2) { // TODO Auto-generated method stub return null; } }
Вам нужно будет добавить следующие imports:
import java.util.ArrayList; import android.content.Context; import android.view.LayoutInflater; import android.widget.LinearLayout; import android.widget.TextView;
В объявлении класса задайте следующие переменные:
private ArrayList<Song> songs; private LayoutInflater songInf;
Мы передадим список композиций из основного класса Activity
и используем LayoutInflater
для сопоставления строк заголовка и исполнителя с TextViews
в созданном нами layout песни.
После переменных экземпляра придайте адаптеру метод конструктора для их создания:
public SongAdapter(Context c, ArrayList<Song> theSongs){ songs=theSongs; songInf=LayoutInflater.from(c); }
Измените содержимое метода getCount
, чтобы вернуть размер списка:
@Override public int getCount() { return songs.size(); }
Вы можете оставить методы getItem
и getItemId
нетронутыми. Обновите реализацию метода getView
, как показано ниже:
@Override public View getView(int position, View convertView, ViewGroup parent) { //map to song layout LinearLayout songLay = (LinearLayout)songInf.inflate (R.layout.song, parent, false); //get title and artist views TextView songView = (TextView)songLay.findViewById(R.id.song_title); TextView artistView = (TextView)songLay.findViewById(R.id.song_artist); //get song using position Song currSong = songs.get(position); //get title and artist strings songView.setText(currSong.getTitle()); artistView.setText(currSong.getArtist()); //set position as tag songLay.setTag(position); return songLay; }
Мы устанавливаем текст названия и исполнителя, выбирая правильный экземпляр Song
из списка, используя индекс позиции, сопоставляя эти строки с представлениями, добавленными в файл макета песни. Мы также устанавливаем позицию в качестве тега вида, которая позволит нам играть правильную песню, когда пользователь нажимает на элемент в списке. Помните, что файл формата song.xml включал атрибут onClick
. Мы будем использовать метод, указанный там, чтобы получить тег в Activity
.
Шаг 3
Вернувшись в основной класс Activity
, в методе onCreate
после сортировки списка создайте новый экземпляр класса Adapter
и установите его в ListView
:
SongAdapter songAdt = new SongAdapter(this, songList); songView.setAdapter(songAdt);
Когда вы запускаете приложение, оно должно отображать список песен на устройстве, щёлкнув по ним, приложение будет вызывать исключение на данный момент, но мы реализуем обработчик щелчка в следующем уроке.
Заключение
Теперь мы настроили приложение для чтения песен с пользовательского устройства. В следующей части мы начнем воспроизведение, когда пользователь выберет песню, используя класс MediaPlayer
. Мы реализуем воспроизведение с использованием класса Service
, чтобы оно продолжалось, пока пользователь занят другими приложениями. Наконец, мы будем использовать класс MediaController
, чтобы дать пользователю управлять воспроизведением.
Время на прочтение
7 мин
Количество просмотров 6.7K
Мы продолжаем рассматривать разные платформенные применения Go (ранее мы посмотрели как использовать Go для микроконтроллеров, веб-приложений, разработки API, создания мобильных приложений) и сегодня поговорим об использовании Go для создания приложений для настольных компьютеров на примере реализации несложного mp3-плеера с поддержкой графического интерфейса. Мы будем использовать связывание с GTK для реализации интерфейса, библиотеки декодирования mp3 и взаимодействия с аудиосистемой (для Windows, Linux и MacOS).
Прежде всего начнем с того, что при компиляции Go финальным артефактом может быть исполняемый файл для Windows / Linux / MacOS. Поскольку на этапе связывания приложение может взаимодействовать с системными и прикладными библиотеками, разработанными для соответствующей операционной системы, мы можем использовать возможности кроссплатформенных графических библиотек (например, GTK) и библиотеки для подключения к аудиосерверам (например, pulseaudio или более новый pipewire). Начнем рассмотрение с изучения методов связывания С-библиотек и кода на Go:
Для примера создадим простую функцию на C, которая будет суммировать два числа и соответствующую обертку на Go для ее вызова (разместим в c/sum.c):
int sum(int a, int b) {
return a+b;
}
Теперь в коде на Go добавим в комментарий импорт исходного текста на C (через директиву #include) и импортируем именованный пакет «C», в результате получим при компиляции экспортированные символы в псевдопакете C (наряду с другими функциями, например преобразования числа Go в целочисленную переменную C, для работы с указателями и др). Для вызова нашей функции создадим функцию-обертку на Go:
package main
/*
#include "c/sum.c"
*/
import "C"
import (
"errors"
"fmt"
)
func main() {
fmt.Println("Hello, World!")
val, _ := sum(1, 2)
fmt.Printf("Sum: %dn", val)
}
func sum(a, b int) (int, error) {
// val, _ := a+b, 0
val, err := C.sum(C.int(a), C.int(b))
if err != nil {
return 0, errors.New("Error calling sum " + err.Error())
}
return int(val), nil
}
Наиболее важные функции из пакета С:
-
CString(str)
— возвращает указатель на C-представление строки из Go -
CBytes([]byte)
— указатель на массив байт (в действительности на копию) -
GoString(ptr)
— преобразует C-строку в строку для Go -
GoStringN(ptr, N)
— преобразует C-строку с заданной длиной в строку Go -
GoBytes(ptr, N)
— последовательность байт длиной N для Go (тип []byte) -
free(unsafe.Pointer(ptr))
— освобождение памяти под указателем (часто используется с defer), при подключенииstdlib.h
Эти функции могут быть полезны при разработке собственных оберток вокруг динамических библиотек, а также для понимания принципов работы существующих go-модулей, которые используют внешние загружаемые библиотеки (например, GTK). При импорте можно использовать как файлы с исходными кодами, так и header-файлы (в этом случае будет использоваться связывание с библиотекой при сборке приложения).
Теперь посмотрим на реализацию связывания Go с библиотеками Gtk. Будем использовать проект https://github.com/gotk3/gotk3. Он предоставляет обертки вокруг GTK-функций и использует тот же подход компиляции через cgo, что и был рассмотрен ранее. Создадим простое окно на экране через использование этого пакета:
package main
import (
"log"
"github.com/gotk3/gotk3/gtk"
)
func main() {
gtk.Init(nil)
//новое окно
win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
if err != nil {
log.Fatal("Unable to create window:", err)
}
win.SetTitle("MP3 Player")
win.Connect("destroy", func() {
//при событии закрытия окна отключаемся от gtk
gtk.MainQuit()
})
ui(win)
win.SetDefaultSize(400, 300)
//отображение окна и запуск цикла событий
win.ShowAll()
gtk.Main()
}
func ui(win *gtk.Window) {
}
Наш mp3-проигрыватель будет принимать название файла как аргумент командной строки и отображать на окне одну кнопку — Play/Pause. Добавим кнопку в функцию ui:
func ui(win *gtk.Window) {
button, _ := gtk.ButtonNew()
button.Connect("clicked", func() {
//toggle state
})
button_label, _ := gtk.LabelNew("Play/Pause")
button.Add(button_label)
win.Add(button)
}
Теперь добавим информацию об mp3-файле, для этого разделим окно по вертикали и в верхнюю часть будем отображать метку (создаем через gtk.LabelNew) с названием из метаданных mp3-файла. Для чтения метаданных будем использовать пакет github.com/bogem/id3v2. Добавим в импорты «github.com/bogem/id3v2/v2» и «os» для получения аргументов командной строки и прочитаем метаданные mp3:
func main() {
mp3 := os.Args[1]
tag, errid3 := id3v2.Open(mp3, id3v2.Options{Parse: true})
if errid3 != nil {
log.Fatalln("File not found or error in metadata extraction")
}
//...
}
Также будем использовать построение с использованием сетки (gtk.Grid) и разместим кнопку под заголовок с названием из метаданных mp3 (каждый виджет будет занимать размер 1х1 элемент сетки):
func ui(win *gtk.Window, tag *id3v2.Tag) {
layout, _ := gtk.GridNew()
title, _ := gtk.LabelNew(tag.Title())
layout.Attach(title, 0, 0, 1, 1) //верхний ряд
button, _ := gtk.ButtonNew()
button.Connect("clicked", func() {
//toggle state
})
button_label, _ := gtk.LabelNew("Play/Pause")
button.Add(button_label)
//кнопка под меткой
layout.AttachNextTo(button, title, gtk.POS_BOTTOM, 1, 1)
win.Add(layout)
}
Теперь, когда мы имеем простой графический интерфейс, подключимся к аудиосерверу нашей операционной системы. Если мы используем Linux, то можно задействовать alsa, pulseaudio или pipewire (в зависимости от дистрибутива). MacOS используется интерфейс CoreAudio, для Windows — Windows Core Audio. Наиболее универсальным выглядят решения с использованием PortAudio (github.com/gordonklaus/portaudio) или библиотеки github.com/hajimehoshi/oto, которая позволяет воспроизводить звук на любой операционной системе (при этом для Windows и MacOS используется нативная реализация протокола, без cgo, в частности для MacOS будет присоединяться AudioToolbox.framework на этапе сборки исполняемого файла). В библиотеке oto для взаимодействия с аудиосервером используется Context, а для воспроизведения звука из декодированного аудиофайла — Players (создается из контекста).
Также от этого автора представлена библиотека декодирования mp3-файла, которая может взаимодействовать с библиотекой воспроизведения звука. Добавим необходимые импорты:
import (
...
"github.com/hajimehoshi/go-mp3"
"github.com/hajimehoshi/oto/v2"
)
Выполним инициализацию контекста и плеера (свяжем с mp3-файлом):
func initOto(file string) {
log.Println("Loading mp3 from " + file)
data, e1 := os.Open(file)
if e1 != nil {
log.Fatalln(e1.Error())
}
decodedStream, e2 := mp3.NewDecoder(data)
if e2 != nil {
log.Fatalln(e2.Error())
}
otoCtx, readyChan, e3 := oto.NewContext(44100, 2, 2)
if e3 != nil {
log.Fatalln(e3.Error())
}
//ждем завершения инициализации
<-readyChan
player = otoCtx.NewPlayer(decodedStream)
loaded = true
//сохраним объект для использования, пока окно открыто
players := make([]oto.Player, 1, 1)
players[0] = player
runtime.KeepAlive(players)
}
Поскольку при воспроизведении будет нужно изменять надпись на кнопке (Play <—> Pause) перенесем объект метки для кнопки в глобальную переменную и реализуем логику запуска/приостановки воспроизведения:
var button_label *gtk.Label
var player oto.Player
var playing bool
var loaded bool
func ui(win *gtk.Window, tag *id3v2.Tag) {
layout, _ := gtk.GridNew()
title, _ := gtk.LabelNew(tag.Title())
layout.Attach(title, 0, 0, 1, 1) //верхний ряд
button, _ := gtk.ButtonNew()
button.Connect("clicked", func() {
if loaded {
if playing {
log.Println("Pause")
player.Pause()
button_label.SetLabel("Play")
} else {
log.Println("Play")
player.Play()
button_label.SetLabel("Pause")
}
playing = !playing
}
})
button_label, _ = gtk.LabelNew("Play")
button.Add(button_label)
//кнопка под меткой
layout.AttachNextTo(button, title, gtk.POS_BOTTOM, 1, 1)
win.Add(layout)
}
После запуска (go run . test.mp3 или go build . && ./player test.mp3) появится окно с названием из метаданных mp3 и кнопкой «Play», при нажатии на которую начнется воспроизведение mp3-файла (кнопка будет заменена на Pause и будет приостанавливать воспроизведение). Однако, при завершении mp3-файла надпись на кнопке останется «Pause». Давайте это исправим, для этого мы будем отслеживать текущее состояние player.IsPlaying в goroutine и изменять соответствующие флаги и отображение на кнопке (добавим в конец initOto):
go func() {
playing = player.IsPlaying()
for {
if player.IsPlaying() != playing {
playing = player.IsPlaying()
if playing {
button_label.SetLabel("Pause")
} else {
button_label.SetLabel("Play")
}
}
time.Sleep(16 * time.Millisecond) //60fps
}
}()
и теперь в callback-функции для нажатия кнопки будем только управлять состоянием воспроизведения:
button.Connect("clicked", func() {
if loaded {
if playing {
log.Println("Pause")
player.Pause()
} else {
log.Println("Play")
player.Play()
}
}
})
Теперь осталось добавить индикатор позиции воспроизведения. Текущее положение можно получить из объекта decodedStream, а полный размер потока (в байтах) через decodedStream.Length. Добавим индикатор (gtk.ProgressBar) на экран (в ui):
progress, _ = gtk.ProgressBarNew()
layout.AttachNextTo(progress, button, gtk.POS_BOTTOM, 1, 1)
в загрузке (после loaded=true):
lengthInBytes := decodedStream.Length()
в цикле проверки состояния:
if playing {
pos, _ := decodedStream.Seek(0, io.SeekCurrent)
var fraction float64
fraction = float64(pos) / float64(lengthInBytes)
progress.SetFraction(fraction)
}
Текущее положение также может быть получено в секундах (поскольку decodedStream это сырой поток несжатых данных, то одна секунда содержит 44100 * 2 * 2 байт). Также при установке нового положения нужно задавать смещение кратное 4 байтам (чтобы указывать на начало сэмпла). Последнее, что мы сделаем сейчас — возможность перемещения позиции воспроизведения при нажатии на индикатор положения. И здесь мы столкнемся с проблемой, что при регистрации callback-функции для контейнера будет получаться объект gdk.Event (внутри GTK это union, интерпретация которого зависит от типа события). В GDK библиотеке есть структура ButtonEvent, но из gdk.Event можно получить только Native представление структуры. Поэтому для извлечения координаты мыши при нажатии на элемент управления будем использовать unsafe.Pointer.
Сначала обернем виджет ProgressBar в контейнер EventBox и затем добавим обработчик события button-press-event через eventbox.Connect. Фрагмент функции ui может выглядить подобным образом:
eventbox, _ := gtk.EventBoxNew()
eventbox.Connect("button-press-event", func(widget *gtk.EventBox, event *gdk.Event) {
allocation := widget.GetAllocation()
width := allocation.GetWidth()
//получаем координату X из структуры gdk.ButtonEvent
x := *(*float64)(unsafe.Pointer(event.Native() + 24))
//получаем долю общей продолжительности
fraction := float64(x) / float64(width)
//определяем смещение (с округлением до 4)
offset := int64(float64(decodedStream.Length()) * fraction)
offset = offset / 4 * 4 //align to sample
//перемещаем воспроизведение на смещение
player.(io.Seeker).Seek(offset, io.SeekStart)
log.Println("Seek to fraction ", fraction)
})
progress, _ = gtk.ProgressBarNew()
eventbox.Add(progress)
layout.AttachNextTo(eventbox, button, gtk.POS_BOTTOM, 1, 1)
Мы создали простой проигрыватель MP3-файлов для desktop-операционных систем (Windows, Linux, MacOS) с использованием связываний на графическую библиотеку GTK и универсальные библиотеки для подключения к аудиосерверу. Разумеется, нужно предусмотреть также обработку ошибок, поддержку управления громкостью и многое другое, но основная задача была в рассмотрении принципов создания desktop-приложений с поддержкой мультимедиа в Go.
Исходный текст программы опубликован в github-репозитории.
GitHub — dzolotov/gomp3player: Simple Go + GTK MP3 Player
github.com
В заключение приглашаю всех на бесплатный урок курса Golang Developer, где разберем, что такое «дженерики» и как они нам могут помочь в ежедневных задачах. А также разберем, как они влияют на производительность и чем они лучше/хуже обычных интерфейсов.
-
Зарегистрироваться на бесплатный урок
Everyone enjoys listening to music, therefore wouldn’t it be great to have our own MP3 player? So, in this python project, we’re going to use python and its libraries to make an mp3 player. Let’s get started on the mp3 player in Python project.
MP3 Music Player Application in Python Language
We’ll make an mp3 music player that allows us to play, stop, and restart tracks, as well as move from one song to the next and previous ones.
Python and associated libraries will be used. The first package we’ll use is Tkinter, a widely used GUI toolkit provided by Python. We don’t need to install it separately since it’s included with Python.
The mixer module of Pygame, a well-known Python library, will be used next.
Pygame is a programming language that is used to develop video games and contains graphics and sound libraries. One such sound library is Mixer. Then, to interface with the operating system, we’ll utilize Python’s os package.
Prerequisites for the Project
Working on a python mp3 player requires a basic familiarity of the Python programming language, tkinter, and the Pygame mixer module.
A basic grasp of Tkinter widgets is also necessary, but don’t worry, we’ll go through every line of code as we build this mp3 player project.
Unlike the Tkinter library, the Pygame library must be installed.
To install pygame, use the following line in your command prompt or terminal.
pip install pygame
Steps to take in order to complete this project
- Import essential libraries
- Make a project layout.
- Define the functionality of the music player, such as play, pause, and other options.
Source Code for MP3 Music Player Application
#importing libraries
from pygame import mixer
from tkinter import *
import tkinter.font as font
from tkinter import filedialog
#creating the root window
root=Tk()
root.title('DataFlair Python MP3 Music player App ')
#initialize mixer
mixer.init()
#create the listbox to contain songs
songs_list=Listbox(root,selectmode=SINGLE,bg="black",fg="white",font=('arial',15),height=12,width=47,selectbackground="gray",selectforeground="black")
songs_list.grid(columnspan=9)
#font is defined which is to be used for the button font
defined_font = font.Font(family='Helvetica')
#play button
play_button=Button(root,text="Play",width =7,command=Play)
play_button['font']=defined_font
play_button.grid(row=1,column=0)
#pause button
pause_button=Button(root,text="Pause",width =7,command=Pause)
pause_button['font']=defined_font
pause_button.grid(row=1,column=1)
#stop button
stop_button=Button(root,text="Stop",width =7,command=Stop)
stop_button['font']=defined_font
stop_button.grid(row=1,column=2)
#resume button
Resume_button=Button(root,text="Resume",width =7,command=Resume)
Resume_button['font']=defined_font
Resume_button.grid(row=1,column=3)
#previous button
previous_button=Button(root,text="Prev",width =7,command=Previous)
previous_button['font']=defined_font
previous_button.grid(row=1,column=4)
#nextbutton
next_button=Button(root,text="Next",width =7,command=Next)
next_button['font']=defined_font
next_button.grid(row=1,column=5)
#menu
my_menu=Menu(root)
root.config(menu=my_menu)
add_song_menu=Menu(my_menu)
my_menu.add_cascade(label="Menu",menu=add_song_menu)
add_song_menu.add_command(label="Add songs",command=addsongs)
add_song_menu.add_command(label="Delete song",command=deletesong)
mainloop()
#add many songs to the playlist of python mp3 player
def addsongs():
#to open a file
temp_song=filedialog.askopenfilenames(initialdir="Music/",title="Choose a song", filetypes=(("mp3 Files","*.mp3"),))
##loop through every item in the list to insert in the listbox
for s in temp_song:
s=s.replace("C:/Users/DataFlair/python-mp3-music-player/","")
songs_list.insert(END,s)
def deletesong():
curr_song=songs_list.curselection()
songs_list.delete(curr_song[0])
def Play():
song=songs_list.get(ACTIVE)
song=f'C:/Users/lenovo/Desktop/DataFlair/Notepad/Music/{song}'
mixer.music.load(song)
mixer.music.play()
#to pause the song
def Pause():
mixer.music.pause()
#to stop the song
def Stop():
mixer.music.stop()
songs_list.selection_clear(ACTIVE)
#to resume the song
def Resume():
mixer.music.unpause()
#Function to navigate from the current song
def Previous():
#to get the selected song index
previous_one=songs_list.curselection()
#to get the previous song index
previous_one=previous_one[0]-1
#to get the previous song
temp2=songs_list.get(previous_one)
temp2=f'C:/Users/DataFlair/python-mp3-music-player/{temp2}'
mixer.music.load(temp2)
mixer.music.play()
songs_list.selection_clear(0,END)
#activate new song
songs_list.activate(previous_one)
#set the next song
songs_list.selection_set(previous_one)
def Next():
#to get the selected song index
next_one=songs_list.curselection()
#to get the next song index
next_one=next_one[0]+1
#to get the next song
temp=songs_list.get(next_one)
temp=f'C:/Users/DataFlair/python-mp3-music-player/{temp}'
mixer.music.load(temp)
mixer.music.play()
songs_list.selection_clear(0,END)
#activate newsong
songs_list.activate(next_one)
#set the next song
songs_list.selection_set(next_one)
Output
Summary
Congratulations! We have successfully developed a python mp3 music player, and we no longer need to depend on any other application.
We learnt a lot about python and its libraries via this project, the first of which was the Tkinter library, which is a widely-used GUI library with a variety of widgets, and then the essential mixer module of the pygame library, which is used to alter the music.
Everyone enjoys listening to music, therefore wouldn’t it be great to have our own MP3 player? So, in this python project, we’re going to use python and its libraries to make an mp3 player. Let’s get started on the mp3 player in Python project.
MP3 Music Player Application in Python Language
We’ll make an mp3 music player that allows us to play, stop, and restart tracks, as well as move from one song to the next and previous ones.
Python and associated libraries will be used. The first package we’ll use is Tkinter, a widely used GUI toolkit provided by Python. We don’t need to install it separately since it’s included with Python.
The mixer module of Pygame, a well-known Python library, will be used next.
Pygame is a programming language that is used to develop video games and contains graphics and sound libraries. One such sound library is Mixer. Then, to interface with the operating system, we’ll utilize Python’s os package.
Prerequisites for the Project
Working on a python mp3 player requires a basic familiarity of the Python programming language, tkinter, and the Pygame mixer module.
A basic grasp of Tkinter widgets is also necessary, but don’t worry, we’ll go through every line of code as we build this mp3 player project.
Unlike the Tkinter library, the Pygame library must be installed.
To install pygame, use the following line in your command prompt or terminal.
pip install pygame
Steps to take in order to complete this project
- Import essential libraries
- Make a project layout.
- Define the functionality of the music player, such as play, pause, and other options.
Source Code for MP3 Music Player Application
#importing libraries
from pygame import mixer
from tkinter import *
import tkinter.font as font
from tkinter import filedialog
#creating the root window
root=Tk()
root.title('DataFlair Python MP3 Music player App ')
#initialize mixer
mixer.init()
#create the listbox to contain songs
songs_list=Listbox(root,selectmode=SINGLE,bg="black",fg="white",font=('arial',15),height=12,width=47,selectbackground="gray",selectforeground="black")
songs_list.grid(columnspan=9)
#font is defined which is to be used for the button font
defined_font = font.Font(family='Helvetica')
#play button
play_button=Button(root,text="Play",width =7,command=Play)
play_button['font']=defined_font
play_button.grid(row=1,column=0)
#pause button
pause_button=Button(root,text="Pause",width =7,command=Pause)
pause_button['font']=defined_font
pause_button.grid(row=1,column=1)
#stop button
stop_button=Button(root,text="Stop",width =7,command=Stop)
stop_button['font']=defined_font
stop_button.grid(row=1,column=2)
#resume button
Resume_button=Button(root,text="Resume",width =7,command=Resume)
Resume_button['font']=defined_font
Resume_button.grid(row=1,column=3)
#previous button
previous_button=Button(root,text="Prev",width =7,command=Previous)
previous_button['font']=defined_font
previous_button.grid(row=1,column=4)
#nextbutton
next_button=Button(root,text="Next",width =7,command=Next)
next_button['font']=defined_font
next_button.grid(row=1,column=5)
#menu
my_menu=Menu(root)
root.config(menu=my_menu)
add_song_menu=Menu(my_menu)
my_menu.add_cascade(label="Menu",menu=add_song_menu)
add_song_menu.add_command(label="Add songs",command=addsongs)
add_song_menu.add_command(label="Delete song",command=deletesong)
mainloop()
#add many songs to the playlist of python mp3 player
def addsongs():
#to open a file
temp_song=filedialog.askopenfilenames(initialdir="Music/",title="Choose a song", filetypes=(("mp3 Files","*.mp3"),))
##loop through every item in the list to insert in the listbox
for s in temp_song:
s=s.replace("C:/Users/DataFlair/python-mp3-music-player/","")
songs_list.insert(END,s)
def deletesong():
curr_song=songs_list.curselection()
songs_list.delete(curr_song[0])
def Play():
song=songs_list.get(ACTIVE)
song=f'C:/Users/lenovo/Desktop/DataFlair/Notepad/Music/{song}'
mixer.music.load(song)
mixer.music.play()
#to pause the song
def Pause():
mixer.music.pause()
#to stop the song
def Stop():
mixer.music.stop()
songs_list.selection_clear(ACTIVE)
#to resume the song
def Resume():
mixer.music.unpause()
#Function to navigate from the current song
def Previous():
#to get the selected song index
previous_one=songs_list.curselection()
#to get the previous song index
previous_one=previous_one[0]-1
#to get the previous song
temp2=songs_list.get(previous_one)
temp2=f'C:/Users/DataFlair/python-mp3-music-player/{temp2}'
mixer.music.load(temp2)
mixer.music.play()
songs_list.selection_clear(0,END)
#activate new song
songs_list.activate(previous_one)
#set the next song
songs_list.selection_set(previous_one)
def Next():
#to get the selected song index
next_one=songs_list.curselection()
#to get the next song index
next_one=next_one[0]+1
#to get the next song
temp=songs_list.get(next_one)
temp=f'C:/Users/DataFlair/python-mp3-music-player/{temp}'
mixer.music.load(temp)
mixer.music.play()
songs_list.selection_clear(0,END)
#activate newsong
songs_list.activate(next_one)
#set the next song
songs_list.selection_set(next_one)
Output
Summary
Congratulations! We have successfully developed a python mp3 music player, and we no longer need to depend on any other application.
We learnt a lot about python and its libraries via this project, the first of which was the Tkinter library, which is a widely-used GUI library with a variety of widgets, and then the essential mixer module of the pygame library, which is used to alter the music.
- 1. Структура проекта
- 2. widget.ui
- 3. SimplePlayer.pro
- 4. widget.h
- 5. widget.cpp
- 6. Итог
- 7. Видеоурок
Предлагаю написать простенький аудио плеер для mp3 файлов с использованием Qt/C++, который будет иметь плейлист, возможность запуска/паузы/остановки треков, а также пролистывания треков.
Для реализации данной задумки в Qt имеются классы
QMediaPlayer
и
QMediaPlaylist,
которые относятся к модулю
multimedia.
А для отображения плейлиста воспользуемся
QStandardItemModel
и
QTableView.
Статьи данного цикла:
- Кастомизация плеера в стиле AIMP
Структура проекта
SimplePlayer.pro
— профайл проекта;
main.cpp
— файл с функцией main;
widget.ui
— файл формы окна приложения;
widget.h
— заголовочный файл окна приложения;
widget.cpp
— файл исходных кодов окна приложения;
buttons.qrc
— ресурсный файл иконок кнопок приложения.
widget.ui
Интерфейс приложения сделаем с использованием графического дизайнера, и выглядеть он должен будет следующим образом.
В состав интерфейса приложения входят следующие элементы:
btn_add (QToolButton*)
— отвечает за добавление треков в плейлист;
btn_next
(QToolButton*)
— отвечает за пролистывание плейлиста вперёд;
btn_previous (QToolButton*)
— отвечает за пролистывание плейлиста назад;
btn_play (QToolButton*)
— отвечает за воспроизведение трека;
btn_pause
(QToolButton*)
— отвечает за постановку трека на паузу;
btn_stop (QToolButton*)
— отвечает за остановку трека;
currentTrack (QLabel*)
— лейбл, в котором будет отображаться текущий трек;
playlistView (QTableView*)
— таблица, отвечающая за отображение плейлиста.
SimplePlayer.pro
В профайле проекта не забудьте подключить модуль
multimedia,
иначе классы
QMediaPlayer
и
QMediaPlaylist
будут недоступны.
#------------------------------------------------- # # Project created by QtCreator 2016-06-29T11:25:56 # #------------------------------------------------- QT += core gui multimedia greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = SimplePlayer TEMPLATE = app SOURCES += main.cpp widget.cpp HEADERS += widget.h FORMS += widget.ui RESOURCES += buttons.qrcwidget.h
Для реализации отображения плейлиста, придется использовать QStandardItemModel. В неё будут помещаться пути к аудио файлам, а также имена аудио файлов. В первой колонке будет имя аудио файла, а во второй будет полный путь, но данная колонка будет скрыта в объекте QTableView, который будет отвечать за отображение плейлиста.
Также пути к файлом в качестве медиа источников необходимо будет поместить в объект QMediaPlaylist, который будет помещён в QMediaPlayer.
Указатели на эти объекты помещаются в заголовочном файле окна приложения. Также здесь присутствует автогенерированый через дизайнер интерфейсов слот для обработки нажатия по кнопке добавления треков в плейлист.
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QStandardItemModel> #include <QMediaPlayer> #include <QMediaPlaylist> namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); private slots: void on_btn_add_clicked(); // Слот для обработки добавления треков через диалоговое окно private: Ui::Widget *ui; QStandardItemModel *m_playListModel; // Модель данных плейлиста для отображения QMediaPlayer *m_player; // Проигрыватель треков QMediaPlaylist *m_playlist; // Плейлиста проигрывателя }; #endif // WIDGET_Hwidget.cpp
Для реализации плеера необходимо инициализировать объекты
QMediaPlayer, QMediaPlaylist
и
QStandardItemModel,
которые были объявлены в заголовочном файле окна приложения. В первой половине конструктора производится настройка внешнего вида таблицы для отображения плейлиста, тогда как во второй настройка самого плеера. Управление плеером осуществляется через кнопки, которые подключены к управляющим слотам
m_playlist
(для навигации) и
m_player
(для запуска/паузы/остановки).При изменении текущего трека, плеер автоматически завершает воспроизведение того, трека который был до изменения, и запускает на воспроизведение новый трек.
В силу того, что
QMediaPlaylist
не имеет модели для отображения в таблице, мы воспользуемся классом
QStandardItemModel,
поэтому придётся добавлять данные о путях к файлам и туда, и туда.#include "widget.h" #include "ui_widget.h" #include <QFileDialog> #include <QDir> Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); // Настройка таблицы плейлиста m_playListModel = new QStandardItemModel(this); ui->playlistView->setModel(m_playListModel); // Устанавливаем модель данных в TableView // Устанавливаем заголовки таблицы m_playListModel->setHorizontalHeaderLabels(QStringList() << tr("Audio Track") << tr("File Path")); ui->playlistView->hideColumn(1); // Скрываем колонку, в которой хранится путь к файлу ui->playlistView->verticalHeader()->setVisible(false); // Скрываем нумерацию строк ui->playlistView->setSelectionBehavior(QAbstractItemView::SelectRows); // Включаем выделение строк ui->playlistView->setSelectionMode(QAbstractItemView::SingleSelection); // Разрешаем выделять только одну строку ui->playlistView->setEditTriggers(QAbstractItemView::NoEditTriggers); // Отключаем редактирование // Включаем подгонку размера последней видимой колонки к ширине TableView ui->playlistView->horizontalHeader()->setStretchLastSection(true); m_player = new QMediaPlayer(this); // Инициализируем плеер m_playlist = new QMediaPlaylist(m_player); // Инициализируем плейлист m_player->setPlaylist(m_playlist); // Устанавливаем плейлист в плеер m_player->setVolume(70); // Устанавливаем громкость воспроизведения треков m_playlist->setPlaybackMode(QMediaPlaylist::Loop); // Устанавливаем циклический режим проигрывания плейлиста // подключаем кнопки управления к слотам управления // Здесь отметим, что навигация по плейлисту осуществляется именно через плейлист // а запуск/пауза/остановка через сам плеер connect(ui->btn_previous, &QToolButton::clicked, m_playlist, &QMediaPlaylist::previous); connect(ui->btn_next, &QToolButton::clicked, m_playlist, &QMediaPlaylist::next); connect(ui->btn_play, &QToolButton::clicked, m_player, &QMediaPlayer::play); connect(ui->btn_pause, &QToolButton::clicked, m_player, &QMediaPlayer::pause); connect(ui->btn_stop, &QToolButton::clicked, m_player, &QMediaPlayer::stop); // При даблклике по треку в таблице устанавливаем трек в плейлисте connect(ui->playlistView, &QTableView::doubleClicked, [this](const QModelIndex &index){ m_playlist->setCurrentIndex(index.row()); }); // при изменении индекса текущего трека в плейлисте, устанавливаем название файла в специальном лейбле connect(m_playlist, &QMediaPlaylist::currentIndexChanged, [this](int index){ ui->currentTrack->setText(m_playListModel->data(m_playListModel->index(index, 0)).toString()); }); } Widget::~Widget() { delete ui; delete m_playListModel; delete m_playlist; delete m_player; } void Widget::on_btn_add_clicked() { // С помощью диалога выбора файлов делаем множественный выбор mp3 файлов QStringList files = QFileDialog::getOpenFileNames(this, tr("Open files"), QString(), tr("Audio Files (*.mp3)")); // Далее устанавливаем данные по именам и пути к файлам // в плейлист и таблицу отображающую плейлист foreach (QString filePath, files) { QList<QStandardItem *> items; items.append(new QStandardItem(QDir(filePath).dirName())); items.append(new QStandardItem(filePath)); m_playListModel->appendRow(items); m_playlist->addMedia(QUrl(filePath)); } }Итог
После того, как приложение запустится, Вы сможете открыть mp3 треки и прослушать их.
Скачать Qt Audio Player
Видеоурок
Для создания проигрывателя, будем использовать элемент управления Media Player, который поддерживает следующие форматы:
— Advanced Streaming Format (ASF)
— Video On Demand (VOD)
— Moving Picture Experts Group 1,2,3 (MPEG 1,2,3)
— Real Audio (RA)
— Real Video (RV)
— Audio – Video Interleaved (AVI)
— Quick Time (MOV)
— Musical Instrument Digital Interface (MIDI)
— Indeo 5
— Waveform Audio (WAV)
— Sound File (SND)
— UNIX audio (AU)
— Audio Interchange File Format (AIFF)
Элемент управления Media Player представляет собой ActiveX, основывающийся на компоненте DirectShow уровня DirectX Media. Первое, что необходимо сделать, создать приложение на основе диалога с помощью мастера AppWizard.Следующий шаг, добавление к проекту элемента, делается это через «Project – Add To Project – Components and Controls»
Далее в появившемся окне открываем папку «Registered ActiveX Controls», находим ссылку «Windows Media Player.lnk» и жмем Insert
Нас спросят, хотим ли мы подключить компонент? Соглашайтесь. 🙂
После, откроется окно, где Вы можете поменять имена у подключаемых файлов. Когда компонент добавлен, в нашем проекте появится два новых файла. В них находится класс CMediaPlayer, который выполняет роль оболочки для элемента Media Player, а в редакторе ресурсов появится элемент Windows Media Player. Поместите его на свой диалог, в свойствах уберите галочку с пункта «Visible».
Теперь необходимо создать указатель с типом CMediaPlayer, в файле заголовке «ИмяВашегоПроектаDlg.h» напишите следующее:
перед этим не забудьте добавить файл «mediaplayer.h»
Далее в инициализации диалога OnInitDialog() мы должны получить указатель на элемент Media Player, следующим способом:
m_pMediaPlayer = (CMediaPlayer *)GetDlgItem(IDC_MP);
Поместите на диалог кнопки с заголовками «Load…,Play,Pause,Stop» и Edit Box. В обработчике сообщения к кнопке «Load…» напишите:
CFileDialog m_dlg(TRUE,NULL,NULL,NULL,"MPEG Audio Files(*.mp3)|*.mp3|"); if (m_dlg.DoModal() == IDOK) { m_pMediaPlayer->SetFileName(m_dlg.GetPathName()); m_edit.SetWindowText(m_dlg.GetPathName()); }
Функция SetFileName() устанавливает файл который нужно воспроизвести. В Edit Box помещаем путь к файлу.
Обработчик сообщения кнопки «Play»: m_pMediaPlayer->Play();
Обработчик сообщения кнопки «Pause»: m_pMediaPlayer->Pause();
Обработчик сообщения кнопки «Stop»: m_pMediaPlayer->Stop();
m_pMediaPlayer->SetCurrentPosition(0); Данная функция устанавливает текущую точку воспроизведения.
Вот некоторые из наиболее часто используемых функций:
GetVolume() – получить значение громкости
SetVolume() – установить значение громкости
GetCurrentPosition() – получить текущую позицию воспроизведения
GetDuration() – возвращает длительность воспроизведения в секундах
Все теперь жмите F7 и Ваш собственный проигрыватель готов.
Сегодня я скомпилировал предыдущий код домашней работы на python и нашел несколько интересных мелочей, таких как следующие, около 70 строк кода, чтобы сделать простой музыкальный проигрыватель.
install some packages
pip install pygame
pygame — это кроссплатформенный модуль Python, разработанный специально для видеоигр, включая изображения и звуки.
Я в основном использую здесь Pygame для воспроизведения музыки. Есть два способа воспроизведения музыки в Pygame, такие как
music_one = pygame.mixer.Sound("test.mp3")
music_one.set_volume(0.05)
music_one.play()
pygame.mixer.music.load('test.mp3')
pygame.mixer.music.set_volume(0.05)
pygame.mixer.music.play()
Что касается эффекта, вышеупомянутые два метода одинаковы, небольшая разница в том, чтоpygame.mixer.Sound()
имеет возвращаемое значение иpygame.mixer.music.load()
Нет, если нам нужно играть разную музыку в разных сценах в программе, возможно, даже в одно и то же время, мы не будем ее использоватьpygame.mixer.music.load()
, Поскольку она похожа на глобальную переменную (это также может быть причиной того, что ее не нужно возвращать), последняя загрузка переопределит предыдущую загрузку, поэтому она подходит для воспроизведения фоновой музыки. иpygame.mixer.Sound()
Существует возвращаемое значение, мы можем присвоить его переменной и использовать в сценах, где нужно проигрывать музыкуПеременная name.play ()
Можно играть сразу.
Для более подробного использования pygame, такого как настройка параметров функции play (), обратитесь кофициальный учебник Pygame
pip install wxPython
Программирование на Python gui — более простая библиотека, поэтому я не буду много говорить.
Source codes
# -*- coding: utf-8 -*-
# автор: inpurer (Юэ Сяошуй Чанг)
# pc_type lenovo
# create_date: 2018/12/1
# file_name: test.py
# описание: Юэ Xiaoshui долго, кровь не круто
import os
import pygame
import random
import wx
musicUrlList = []
# Загрузить все .mp3 файлы в рабочий каталог
def musicUrlLoader():
fileList = os.listdir(".")
for filename in fileList:
if filename.endswith(".mp3"):
печать («найти аудиофайл», имя файла)
musicUrlList.append(filename)
class MyMusicPlayer(wx.Frame):
def __init__(self,superion):
wx.Frame.__init__(self,parent = superion, title = 'Xinspurer Player',size = (400,300))
musicUrlLoader()
MainPanel = wx.Panel(self)
MainPanel.SetBackgroundColour('pink')
self.ShowInfoText = wx.StaticText (parent = MainPanel, label = 'Воспроизведение не началось', pos = (100,100)
,size = (185,25),style = wx.ALIGN_CENTER_VERTICAL)
self.ShowInfoText.SetBackgroundColour('white')
self.isPaused = False # Должно ли быть приостановлено
self.StartPlayButton = wx.Button (parent = MainPanel, label = 'Shuffle Play', pos = (100,150))
self.Bind(wx.EVT_BUTTON, self.OnStartClicked, self.StartPlayButton)
self.PauseOrContinueButton = wx.Button (parent = MainPanel, label = 'Пауза воспроизведения', pos = (200,150))
self.Bind(wx.EVT_BUTTON, self.OnPauseOrContinueClicked, self.PauseOrContinueButton)
self.PauseOrContinueButton.Enable(False)
pygame.mixer.init()
def OnStartClicked(self,event):
self.isPaused = False
self.PauseOrContinueButton.Enable(True)
self.willPlayMusic = random.choice(musicUrlList)
pygame.mixer.music.load(self.willPlayMusic.encode())
pygame.mixer.music.play()
self.ShowInfoText.SetLabel («Текущая игра:» + self.willPlayMusic)
def OnPauseOrContinueClicked(self,event):
if not self.isPaused:
self.isPaused = True
pygame.mixer.music.pause()
self.PauseOrContinueButton.SetLabel («Продолжить играть»)
self.ShowInfoText.SetLabel (воспроизведение приостановлено)
else:
self.isPaused = False
pygame.mixer.music.unpause()
self.PauseOrContinueButton.SetLabel («Приостановить воспроизведение»)
self.ShowInfoText.SetLabel («Текущая игра:» + self.willPlayMusic)
if __name__ == "__main__":
app = wx.App()
myMusicPlayer = MyMusicPlayer(None)
myMusicPlayer.Show()
app.MainLoop()
Следует отметить, что для запуска кода необходимо поместить несколько песен .mp3 в текущий каталог.
Эффект бега
постскриптум
Весь код имеет последнее обновление на github:PythonLearning
Добро пожаловать на персональный публичный номер: вдохновитель