Форум программистов, компьютерный форум, киберфорум
Leshakk
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
Разборы кода (Дали код? Скажи спасибо и пойди выучи и разберись как он работает. )
Заметки кажущиеся на данном этапе полезными.
Описание пройденного материала своими словами для лучшего усваивания и возможности получить замечание, от мимо проходивших специалистов.

Фоновая музыка в приложении WinForms. Разбор кода.

Запись от Leshakk размещена 13.04.2022 в 16:43
Показов 2478 Комментарии 4

Разбор кода в учебных целях.

Добрый день.

Для практики делал игру "пятнашки" в WinForms, коими полон интернет. Ну и захотелось, чтобы еще играла любимая музыка. Несколько треков по кругу. И значит чтобы были кнопки play, stop, и регулятор громкости. Вроде сделал. Но как-то коряво. И если нажимаешь на Плей, то играет следующая песня, а если ничего не нажимать, то песня заканчивается и тишина, надо опять нажимать.

В этой теме: Создать плеер хотя бы с кнопкой "открыть" "играть" и с TrackBar для проигрывания mp3,
Уважаемый I can дал код, который сразу заработал, и заработал так как и было нужно. И поскольку проект был учебным. Хотелось бы не просто скопипастить код, а разобрать его устройство. Получить знания так сказать. Если вы, дорогой читатель, изучаете C# более чем 2 месяца, то наврядли вам тут будет интересно. Но вы можете поправить, или подсказать. И за это зараннее спасибо.

Вот сам код:

Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
 
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
        }
 
        public WMPLib.WindowsMediaPlayer WMP = new WMPLib.WindowsMediaPlayer();
        private void button_Play_Click(object sender, EventArgs e)
        {
            Random dise = new Random();
            string[] a = System.IO.Directory.GetFiles(Application.StartupPath, "*.wav");
            WMP.URL = a[dise.Next(0, a.Length)];
            trackBar1.Value = 5;
            WMP.settings.volume = trackBar1.Value * 10;
            timer1.Start();
        }
 
        private void button_Stop_Click(object sender, EventArgs e)
        { WMP.controls.stop(); timer1.Stop(); Text = ""; }
 
        private void trackBar1_Scroll(object sender, EventArgs e)
           {  WMP.settings.volume = trackBar1.Value*10;}
 
        private void timer1_Tick(object sender, EventArgs e)
        {
            Text = WMP.status.ToString();
            if (Text == "Остановлено") button_Play_Click(null,null);
        }
 
 
        }
 
 
    }


Итак:

⚫ this.timer1.Tick += new System.EventHandler(this.timer1_Tick);

На первый нубовзгляд эта строчка, напоминает создание обьекта класса, но во первых нет переменной, куда записывается экземпляр класса.
Во вторых, зачем вместо = написано +=? Такого мы еще не проходили.
Идем в гугл копать. И находим там страшные, ужасные доселе неведомые....События!!! И.....ДЕЛЕГАТЫ!!!
Что там в гугле про События и делегаты...много чего..Ссылки копировать нельзя, а обьяснить сложно,особенно, когда сам не понял...

timer1.Tick это событие

+= это подписка на событие........................или нет.........

Можно интуитивно предположить следующее:
метод this.timer1_Tick подписан на событие this.timer1.Tick
таймер запускается при нажатии кнопки плей, и начинает тикать. И каждые 100милисекунд ( можно любое значение, но сейчас вот 100мс) выполняется метод - обработчик события: timer1_Tick.

private void timer1_Tick(object sender, EventArgs e)
{
Text = WMP.status.ToString();
if (Text == "Остановлено") button_Play_Click(null,null);
}

Этот метод говорит: Давайте-ка запишем в виртуальный Текст статус плеера, а потом проверим его, и если плеер имеет статус "Остановлено", то давайте нажмем кнопку плей еще раз.
А если нет статуса "Остановлено" то ничего делать не будет. И так каждые 100мс, пока играет музыка.
И если в очередной раз выяснится что статус "Остановлено" появился,а он появится когда трек закончится, то метод сбросит кнопку плей командой button_Play_Click(null,null) и все повторится. Такой своего рода цикл по рандомизации песен, их проигрыванию, и с проверкой статуса плеера с заданным интервалом.
То есть, если установить, например в свойствах таймера 24 часа, то рандомная песня будет играть раз в сутки.
Остановить это все, можно кнопкой стоп.

⚫ private void button_Stop_Click(object sender, EventArgs e)
{ WMP.controls.stop(); timer1.Stop(); Text = ""; }

Это кнопка стоп, точнее метод-обработчик события:
останавливает проигрывание, останавливает таймер, и очищает виртуальный текст от записаного туда статуса плеера.

⚫ public WMPLib.WindowsMediaPlayer WMP = new WMPLib.WindowsMediaPlayer();

Создание экземпляра класса WMPLib.WindowsMediaPlayer, странный конечно класс, но по ситаксису, таки-да, это экземпляр класса. И записывается он в переменную - обьект WMP.

⚫ private void button_Play_Click(object sender, EventArgs e)

Эта фигня сама создается, когда на форму заносишь кнопку и кликаешь на нее два раза.
Официальный тутор говорит что это: "Обработчик событий — это метод, привязанный к событию. При возникновении события выполняется код в обработчике событий. "
Короче нажали кнопку, выполнился код который в фигурных скобках.

Random dise = new Random();
string[] a = System.IO.Directory.GetFiles(Application .StartupPath, "*.wav");
WMP.URL = a[dise.Next(0, a.Length)];
trackBar1.Value = 5;
WMP.settings.volume = trackBar1.Value * 10;
timer1.Start();

Ну наконец-то, хоть какие то знакомые слова!
Random dise = new Random(); проходили! Тут короче стандартная процедура, создание экземпляра класса, запись его в новый обьект dise
Kласс рандом, выдает случайные числа в заданном диапазоне посредством метода Next и принимаемых им параметров от забора и до обеда откуда и докуда выдавать рандомные числа. В нашем случае, от нуля до максимальной длины массива. Длина массива не корректно, но не знаю как правильно сказать. Короче метод Next последовательно пройдет по всей длине массива, от первого до последнего значения. и выберет рандомное значению (песню) и вернет/запишет/присвоит это значение в WMP.URL (Что это?)

⚫ string[] a = System.IO.Directory.GetFiles(Application .StartupPath, "*.wav");
Здесь объявлен и проинициализирован строковый массив и в него записаны все песни в формате wav которые лежат....

⚫ System.IO.Directory.GetFiles(Application .StartupPath, "*.wav")
Это значит так:
System.IO.Directory.GetFiles ==Возвращает имена файлов, соответствующих указанным критериям
Application.StartupPath ==путь для исполняемого файла, запустившего приложение, не включая исполняемое имя.
"*.wav" == звуковой формат.
Короче надо пойти туда, где лежит исполняемый файл, найти и собрать имена всех WAVок, и записать их в массив string[] a


⚫ WMP.URL = a[dise.Next(0, a.Length)];
Гугл находит только URL и говорит что это свойство, но там непонятно все. Наверное это как в пословице : Понять это невозможно, это можно только запомнить!!!
Поэтому запомним что URL это адрес (локация, местонахождение) для чего-то.
Если попытаться обьяснить своими словами то объект WMP не знает где брать песню, для того чтобы ему это как-то обьяснить, надо наделить его свойством, умением разбираться в картах и навигации. Этим свойством его наделяет URL.
А затем треки записваются в массив, и скормливаются, плееру, любым способом читающим массив.
Просто так приписать WMP.URL = a; не сработает потому что плеер не будет знать какую именно песню из всего массива брать и играть. И только когда метод Next a[dise.Next(0, a.Length)] выберет рандомную песню , одну, определенную, и даст ее Плееру, тогда он наконец ее захавает.
Надо кстати для практики попробовать другие способы обработки массива, например последовательное проигрывание всего массива, или через одну песню, или исключить песни с цифрой 2 в названии. Чисто поугорать для тренировки. Но это потом.

⚫ trackBar1.Value = 5;
WMP.settings.volume = trackBar1.Value * 10;

Это громкость звука.
Школа трекбара по умолчанию имеет 10 делений.
А громкость Медиаплеера по умолчанию 0 - 100.
И значит здесь при старте, ползунок трекбара станет на 5,а громкость 5 * 10 будет 50. Короче по умолчанию будет по серединке, а там уже регулировать.

⚫ timer1.Start();
Ну тут уже понятно, уже разобрали, старт таймера.

Остался вопрос, берется статус "Остановлено" почему он на русском? Почему не стоп и не stop, какие еще бывают статусы и где их найти. Гуглил-не нашел. Точнее нашел на английском Stop, а на русском нигде не пошел. Это "Остановлено" совсем уже замучило свой загадочностью.
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 4
Комментарии
  1. Старый комментарий
    Уважаемые читатели, если кто забредет сюда, поправьте пожалуйста, что не так. Хотелось бы довести это до ума, не только в тексте но и в голове.
    Запись от Leshakk размещена 13.04.2022 в 16:46 Leshakk вне форума
  2. Старый комментарий
    Аватар для roach1967
    Попробую пояснить некоторые моменты (в которых разобрался сам) и внести изменения/дополнения:
    ● с таймером можно поступить проще - кинуть на форму из панели элементов "Компоненты" таймер. Тогда можно будет пока пропустить изучение делегатов и т.п. Все свойства и задания на обработку событий можно будет изменять на панели "Свойства".
    ● с trackBar1 можно поступить проще - изменить в свойства максимальное значение на 100, тогда ничего умножать не надо будет.
    ● WMP.URL - указываем, какой файл проигрывать. Запоминать ничего не надо. Свойство всеядно - понимает как локальные аудиофайлы, так и стримы/онлайнрадио с интернета. Естественно, желательно, придерживаться правил указания абсолютных путей к файлам.
    ● Список файлов тоже можно изменить - WMP прекрасно воспроизводит почти все известные форматы аудио/видео а не только *.WAV. Удобнее заранее накидать в определённую папку (например "MEDIA") нужные файлы wav, mp3, midi, ogg... и просто весь список без разбора закидывать в плейлист.
    ● ещё насчёт таймера. Если не нужна позиция проигрывания и т.п., то он и не нужен. У WMPLib есть событие PlayStateChange, в котором он передаёт индекс нового состояния плеера. Всего их 13 (здесь они перечислены). А статус "Остановлено" получается при преобразовании перечисления состояний в строку на русифицированной системе.
    Для задания обработки события изменения состояния можно так поступить - написать процедуру, например:
    C#
    1
    2
    3
    4
    
    private void WMP_PlayStateChange(int NewState)
    {
        // здесь и будет обрабатываться событие изменения состояния
    }
    А после объявления переменной WMP указать на этот обработчик:
    C#
    1
    
    WMP.PlayStateChange += WMP_PlayStateChange;
    Для примера отсюда у меня была такая обработка:
    C#
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    
            private void WMP_PlayStateChange(int NewState)
            {
                // изменение состояния плеера
                if (NewState == (int)WMPPlayState.wmppsMediaEnded)
                {
                    // по окончанию воспроизведения на следующий, если не последний
                    if (currtrack < listTracks.Items.Count - 1)
                    {
                        listTracks.SelectedIndex++;
                        WMP.URL = "";
                    }
                    else
                    {
                        btn_stop.PerformClick();
                    }
                }
                if (NewState == (int)WMPPlayState.wmppsReady)
                {
                    // если состояние готовности и программа воспроизводит, нажимаем кнопку PLAY
                    if (flg_play) btn_play.PerformClick();
                }
                if (NewState == (int)WMPPlayState.wmppsPlaying)
                {
                    // если начал воспроизведение, считываем продолжительность трека и запускаем таймер
                    lbl_duration.Text = ToTime(WMP.currentMedia.duration);
                    timer1.Start();
                    currplay = currtrack;
                }
                if (NewState == (int)WMPPlayState.wmppsStopped)
                {
                    // если останавливается, то и таймер стоп
                    timer1.Stop();
                }
                StatusLabel1.Text = status[NewState];
            }
    Запись от roach1967 размещена 14.04.2022 в 15:54 roach1967 вне форума
  3. Старый комментарий
    Уххх! Спасибо!!! Буду разбираться.
    Запись от Leshakk размещена 14.04.2022 в 18:22 Leshakk вне форума
  4. Старый комментарий
    А вот про статусы прям обидно и стыдно. Рылся основательно в этом плеере и не нашел. Спасибо что ткнули носом.
    currentStateLabel.Text = "Stopped"; Вот же он! В переводе на русский "Остановлено", да.
    Спасибо еще раз!
    Запись от Leshakk размещена 15.04.2022 в 10:40 Leshakk вне форума
 
Новые блоги и статьи
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
Как ИИ начал спорить и врать (возможно почуяв опасность для себя от индустрии - уход от электроники).
Hrethgir 04.08.2026
Недельный диалог, на фоне событий с НПЗ. Да, из спирта можно получать бензин, и это не сложно. Но потом в схеме я решил избавиться от насоса, при этом полностью сделав контроль подачи спирта в. . .
Термопринтер QR701
Argus19 03.08.2026
Термопринтер QR701 Купил два термопринтера QR701. На сэлф-тесте написано: Language: PC936 (GB18030). Что означает, что принтеры могут печатать только латиницу и китайские иероглифы. Так же. . .
Создание формы заимствованного документа
Maks 03.08.2026
Задача: Необходимо создать собственную форму заимствованного документа. На форме должен быть реквизит "Покупатель", а также табличная часть со следующими реквизитами: - Расчетный счет покупателя. . .
Задача предоставления скидок покупателям
Maks 03.08.2026
Задача: В документе "Продажи" необходимо реализовать функционал предоставления скидок покупателям. Скидка должна автоматически рассчитываться и подставляться в соответствующее поле при выборе. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru