Урок 2.2. Пишем видеоплеер (проигрыватель видео) на Delphi с использованием технологии DirectShow.
На этом уроке мы напишем код для обработки событий формы, созданной на прошлом уроке. Не много о самом плеере: - Плеер будет поддерживать все форматы аудио (mp3, wma ...) и почти все форматы видео (зависит от видео кодеков установленных в вашей системе); - Плейлист; - функции Play, Pause, Stop; - ускоренное и замедленное воспроизведение; - полоску воспроизведения (перемотки, поиска); - полно экранный режим (FullScreen); - регулирование громкости.
Приступим…
Добавим в модуль Uses строчки DirectShow9, ActiveX; Скачать заголовочные файлы DirectShow можно здесь.
В раздел type добавим строчку
TPlayerMode = (Stop, Play, Paused); // режим воспроизведения
и заголовки процедур: procedure Initializ; procedure Player; procedure AddPlayList;
В раздел private добавляем
//процедура обработки сообщений от клавиатуры Procedure WMKeyDown(Var Msg:TWMKeyDown); Message WM_KeyDown;
В раздел var добавляем:
hr: HRESULT = 1; //задаем начальное значение ложь (используется обратная логика) pCurrent, pDuration: Double;// Текужее положение и длительность фильма Mode: TPlayerMode; // режим воспроизведения Rate: Double;// нормальная скорость воспроизведения FullScreen: boolean = false; //индикатор перехода в полноэкранный режим i: integer = 0;// счетчик загруженных файлов FileName: string;//имя файла xn, yn : integer; //для хранения координат мыши mouse: tmouse; //координаты мыши
//интерфейсы для построения и управления графом pGraphBuilder : IGraphBuilder = nil; //сам граф pMediaControl : IMediaControl = nil; //управление графом pMediaEvent : IMediaEvent = nil; //обработчик событий pVideoWindow : IVideoWindow = nil; //задает окно для вывода pMediaPosition : IMediaPosition = nil; //позиция проигрывания pBasicAudio : IBasicAudio = nil; //управление звуком
после раздела implementation пишем код добавленных процедур: {$R *.dfm}
//процедура построения графа procedure TForm1.Initializ; begin //освобождаем подключенные интерфейсы if Assigned(pMediaPosition) then pMediaPosition := nil; if Assigned(pBasicAudio) then pBasicAudio := nil; if Assigned(pVideoWindow) then pVideoWindow := nil; if Assigned(pMediaEvent) then pMediaEvent := nil; if Assigned(pMediaControl) then pMediaControl := nil; if Assigned(pGraphBuilder) then pGraphBuilder := nil; //получаем интерфейс построения графа hr := CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, pGraphBuilder); if hr<>0 then begin ShowMessage('Не удается создать граф'); exit; end; //получаем интерфейс управления hr := pGraphBuilder.QueryInterface(IID_IMediaControl, pMediaControl); if hr<>0 then begin ShowMessage('Не удается получить интерфейс IMediaControl'); exit; end; //получаем интерфейс событий hr := pGraphBuilder.QueryInterface(IID_IMediaEvent, pMediaEvent); if hr<>0 then begin ShowMessage('Не удается получить интерфейс событий'); exit; end; //получаем интерфейс управления окном вывода видео hr := pGraphBuilder.QueryInterface(IID_IVideoWindow, pVideoWindow); if hr<>0 then begin ShowMessage('Не удается получить IVideoWindow'); exit; end; //получаем интерфейс управления звуком hr := pGraphBuilder.QueryInterface(IBasicAudio, pBasicAudio); if hr<>0 then begin ShowMessage('Не удается получить аудио интерфейс'); exit; end; //получаем интерфейс управления позицией проигрывания hr := pGraphBuilder.QueryInterface(IID_IMediaPosition, pMediaPosition); if hr<>0 then begin ShowMessage('Не удается получить интерфейс управления позицией'); exit; end; //загружаем файл для проигрывания при этом граф строится автоматический hr := pGraphBuilder.RenderFile(StringToOleStr(PChar(filename)), ''); if hr<>0 then begin ShowMessage('Не удается прорендерить файл'); exit; end;
//располагаем окошко с видео на панель pVideoWindow.Put_Owner(Panel1.Handle);//Устанавливаем "владельца" окна, в нашем случае Panel1 pVideoWindow.Put_WindowStyle(WS_CHILD OR WS_CLIPSIBLINGS);//Стиль окна pVideoWindow.put_MessageDrain(Panel1.Handle);//указываем что Panel1 будет получать сообщения видео окна pVideoWindow.SetWindowPosition(0,0,Panel1.ClientRect.Right,Panel1.ClientRect.Bottom); //размеры end;
//процедура проигрывания файла procedure TForm1.Player; begin if mode<>paused then begin //проверяем существует ли файл загружаемый из PlayList //если файл не существует, то выходим if not FileExists(FileName) then begin ShowMessage('Файл не существует');exit;end; //освобождаем канал воспроизведения Initializ; end; //Запускаем процедуру проигрывания pMediaControl.Run; //получаем скорость врспроизведения pMediaPosition.get_Rate(Rate); //присваеваем заголовку формы имя проигрываемого файла Form1.Caption:=ExtractFileName(FileName); //Устанавливаем режим воспроизведения PlayMode - play mode:=play; end;
//выход из полноэкранного режима по кнопке ESC Procedure TForm1.WMKeyDown(Var Msg:TWMKeyDown); begin if Msg.CharCode=VK_ESCAPE then begin pVideoWindow.HideCursor(False); //показываем курсор //показываем плейлист, сплиттер, панель управления GroupBox Form1.ListBox2.Visible:=True; Form1.Splitter1.Visible:=True; Form1.CheckBox1.Checked:=True; Form1.GroupBox1.Visible:=True; //устанавливаем исходные параметры окна Form1.BorderStyle:=bsSizeable; Form1.windowState:= wsNormal; Form1.FormStyle:=fsNormal; //задаем размеры окна вывода pVideoWindow.SetWindowPosition(0,0,Panel1.ClientRect.Right,Panel1.ClientRect.Bottom); FullScreen:=False; end; inherited; end;
//процедура зугрузки файлов в плейлист procedure TForm1.AddPlayList; var j: Integer; begin OpenDialog1.Options:=[ofHideReadOnly,ofAllowMultiSelect,ofEnableSizing]; OpenDialog1.Title := 'Открытие файлов'; //фильтр для файлов OpenDialog1.Filter := 'Файлы мультимедиа |*.mp3;*.wma;*.wav;*.vob;*.avi;*.mpg;*.mp4;*.mov;*.mpeg;*.flv;*.wmv;*.qt;|Все файлы|*.*'; //проверяем если PlayList не пустой то запоминаем номер текущей записи //иначе устанавливаем номер записи 0 (первая позиция в PlayList) if listbox2.Count<>0 then i:=ListBox2.ItemIndex else i:=0; //Диалог открытия файла if not OpenDialog1.Execute then exit; Begin For j:=0 to OpenDialog1.Files.Count -1 do Begin ListBox2.Items.Add(ExtractFileName(OpenDialog1.Files.Strings[j])); ListBox1.Items.Add(OpenDialog1.Files.Strings[j]); End; End; //запоминаем имя файла текущей записи в плейлисте Filename:=ListBox1.Items.Strings[i]; //Выделяем эту запись в PlayList ListBox1.ItemIndex:=i; ListBox2.ItemIndex:=i; end;
Для компонента CheckBox1 события OnClick пишем код:
procedure TForm1.CheckBox1Click(Sender: TObject); //показываем или скрываем плейлист begin if Form1.CheckBox1.Checked=True then begin Form1.ListBox2.Visible:=True; Form1.Splitter1.Visible:=True; end else begin Form1.ListBox2.Visible:=False; Form1.Splitter1.Visible:=False; end; end;
Для события OnCreate формы пишем код:
procedure TForm1.FormCreate(Sender: TObject); begin CoInitialize(nil);// инициализировать OLE end;
Для события Destroy формы пишем код:
procedure TForm1.FormDestroy(Sender: TObject); begin CoUninitialize;// деинициализировать OLE end;
Для компонента ListBox2 события OnClick пишем код:
procedure TForm1.ListBox2Click(Sender: TObject); begin //устанавливаем одинаковую позицию в плейлистах при выборе i:=ListBox2.Itemindex; ListBox1.Itemindex:=i; end;
Для компонента ListBox2 события OnDblClick пишем код:
procedure TForm1.ListBox2DblClick(Sender: TObject); begin //выбираем файл из плейлиста при двойном клике для воспроизведения i:=ListBox2.Itemindex; ListBox1.Itemindex:=i; Filename:=ListBox1.Items.Strings[i]; mode:=stop; //вызываем процедуру проигрывания файла player; end;
Для компонента ListBox2 события OnMouseActivate пишем код:
//процедура вызова PopupMenu при нажатии правой кнопкой мыши на плейлисте (ListBox) procedure TForm1.ListBox2MouseActivate(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y, HitTest: Integer; var MouseActivate: TMouseActivate); var point : TPoint; begin if (Button = mbRight) then // нажата правая мышь begin point.X := X; point.Y := Y; i := ListBox2.ItemAtPos(point, true); // выделяем строку ListBox1.ItemIndex:=i; ListBox2.ItemIndex:=i; if i >= 0 then // если щелкнули по полям списка begin // поднимаем меню PopupMenu1.Popup(ListBox2.ClientOrigin.X + X, ListBox2.ClientOrigin.Y + Y); end; end; end;
Для компонента PopumMenu1 события кнопка очистить пишем код:
//процедура удаления записей в плейлисте procedure TForm1.N1Click(Sender: TObject); begin //очистка плейлиста ListBox1.Clear; ListBox2.Clear; end;
Для компонента PopumMenu1 события кнопка удалить пишем код:
procedure TForm1.N2Click(Sender: TObject); //удаление записи begin ListBox1.DeleteSelected; ListBox2.DeleteSelected; end;
Для компонента PopumMenu1 события кнопка добавить пишем код:
procedure TForm1.N3Click(Sender: TObject); begin //вызываем процедуру загрузки плейлиста AddPlayList; end;
Для компонента Panel1 события OnDblClick пишем код:
//Процедура перехода в полноэкранный режим и обратно procedure TForm1.Panel1DblClick(Sender: TObject); begin if hr <> 0 then exit; //если файл не загружен выходим pVideoWindow.HideCursor(False); //показываем курсор if FullScreen=False then begin //скрываем плейлист, сплиттер и панель управления Form1.ListBox2.Visible:=False; Form1.Splitter1.Visible:=false; Form1.GroupBox1.Visible:=false; //устанавливаем параметры формы Form1.BorderStyle:=bsNone; //без бордюра Form1.FormStyle :=fsstayOnTop; //поверх окон Form1.windowState:= wsMaximized;// на весь экран //устанавливаем вывод видео на всю ширину экрана pVideoWindow.SetWindowPosition(0,0,screen.Width,screen.Height); FullScreen:=True; end else begin // восстанавливаем значения при выходе из полноэкранного режима if form1.CheckBox1.Checked=true then Form1.ListBox2.Visible:=True; Form1.GroupBox1.Visible:=True; Form1.Splitter1.Visible:=True; Form1.BorderStyle:=bsSizeable; Form1.windowState:= wsNormal; Form1.FormStyle:=fsNormal; pVideoWindow.SetWindowPosition(0,0,Panel1.ClientRect.Right,Panel1.ClientRect.Bottom); FullScreen:=False; end; end;
Для компонента Panel1 события OnMouseMove пишем код:
//процедура показывания плейлиста и панели управления при наведении на них мыши procedure TForm1.Panel1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin //выходим если режим не полноэкранный if FullScreen<>True then Exit; //скрываем плейлист если курсор мыши с него уходит if (mouse.CursorPos.X<panel1.Width) and (ListBox2.Visible=True) then begin Form1.ListBox2.Visible:=False; Form1.Splitter1.Visible:=False; end; //показываем плейлист при наведении на его положение мыши, если он был включен if (mouse.CursorPos.X>=panel1.Width-ListBox2.Width) and (ListBox2.Visible=False) then begin if form1.CheckBox1.Checked=true then begin Form1.ListBox2.Visible:=True; Form1.Splitter1.Visible:=True; end; end;
//аналогично с панелью упралением проигрыванием if (mouse.CursorPos.Y<panel1.Height) and (groupbox1.Visible=True) then begin groupbox1.Visible:=false; end;
if (mouse.CursorPos.Y>=panel1.Height-groupbox1.Height) and (groupbox1.Visible=False) then begin groupbox1.Visible:=True; end; end;
Для компонента Panel1 события OnResize пишем код:
//Процедура изменения размеов окна проигрывания при изменении размеров панели procedure TForm1.Panel1Resize(Sender: TObject); begin if mode=play then begin pVideoWindow.SetWindowPosition(0,0,Panel1.ClientRect.Right,Panel1.ClientRect.Bottom); end; end;
Для компонента ProgressBar1 события OnMouseMove пишем код:
//процедура изменения позиции проигрывания при изменении позиции ProgressBar (перемотка) procedure TForm1.ProgressBar1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var p: real; begin if hr = 0 then begin if ssleft in shift then //если нажата левая кнопка мыши begin p:=ProgressBar1.Max/ProgressBar1.Width; ProgressBar1.Position:=round(x*p); pMediaControl.Stop; pMediaPosition.put_CurrentPosition(ProgressBar1.Position); pMediaControl.Run; mode:=play; end; end; end;
Для компонента SpeedButton1 события OnClick пишем код:
//процедура воспроизведения procedure TForm1.SpeedButton1Click(Sender: TObject); begin //Проверяем если воспроизведение уже идет то устанавливаем //нормальную скорость воспроизведения и выходим if mode=play then begin pMediaPosition.put_Rate(Rate);exit;end ; Player; end;
Для компонента SpeedButton2 события OnClick пишем код:
//процедура паузы procedure TForm1.SpeedButton2Click(Sender: TObject); begin //Проверяем идет ли воспроизведение if mode=play then begin pMediaControl.Pause; mode:=paused;//устанавливаем playmode -> пауза end; end;
Для компонента SpeedButton3 события OnClick пишем код:
//процедура остановки procedure TForm1.SpeedButton3Click(Sender: TObject); begin //Проверяем идет ли воспроизведение if mode=play then begin pMediaControl.Stop; mode:=Stop;//устанавливаем playmode -> стоп //задаем начальное положение проигравания pMediaPosition.put_CurrentPosition(0); end; end;
Для компонента SpeedButton4 события OnClick пишем код:
//процедура замедленного воспроизведения procedure TForm1.SpeedButton4Click(Sender: TObject); var pdRate: Double; begin if mode=play then begin //читаем текущую скорость pMediaPosition.get_Rate(pdRate); //уменьшаем ее в два раза pMediaPosition.put_Rate(pdRate/2); end; end;
Для компонента SpeedButton5 события OnClick пишем код:
//процедура ускоренного воспроизведения procedure TForm1.SpeedButton5Click(Sender: TObject); var pdRate: Double; begin if mode=play then begin //читаем текущую скорость pMediaPosition.get_Rate(pdRate); //увеличиваем ее в два раза pMediaPosition.put_Rate(pdRate*2); end; end;
Для компонента SpeedButton6 события OnClick пишем код:
procedure TForm1.SpeedButton6Click(Sender: TObject); begin //вызываем процедуру загрузки плейлиста AddPlayList; end;
Для компонента Timer1 события OnTimer пишем код:
procedure TForm1.Timer1Timer(Sender: TObject); var TrackLen, TrackPos: Double; ValPos: Double; ValLen: Double; plVolume:Longint; db : integer; begin //выводим время Panel4.Caption:=TimeToStr(SysUtils.Time); //проверяем режим воспроизведения, если не Play то выходим if hr <> 0 then Exit; //время проигрывания фильма //считываем всю длину фильма в секундах pMediaPosition.get_Duration(pDuration); //задаем максимальное положение ProgressBar ProgressBar1.Max:=round(pDuration); //считаваем сколько секунд прошло от начала воспроизведения pMediaPosition.get_CurrentPosition(pCurrent); //задаем текущее положение ProgressBar ProgressBar1.Position:=round(pCurrent); //воспроизведение следующего фильма //если время проигрывания равно длине фильма по времени, if pCurrent=pDuration then begin //то выбираем следующую запись из плейлиста if i<ListBox2.Items.Count-1 then begin inc(i); Filename:=ListBox1.Items.Strings[i]; ListBox1.ItemIndex:=i; ListBox2.ItemIndex:=i; mode:=stop; player; end //если лист закончился - выходим else exit; end;
//Установка громкости, громкость задается от -10000 до 0 //к сожелению при таком регулировании звук начинает заметно прибавляться только в конце шкалы //pBasicAudio.put_Volume(TrackBar1.Position*100-10000);
//еще один вариант регулирования громкости. Более плавное регулирование звука plVolume:= (65535 * TrackBar1.Position) div 100; //нормируем характеристику уровня громкости db:= trunc(33.22 * 100 * ln((plVolume+1e-6)/65535)/ln(10)); pBasicAudio.put_Volume(db);
//делаем вычисление времени TrackLen:=pDuration; TrackPos:=pCurrent; //переводим секунды в часы ValPos:=TrackPos / (24 * 3600); ValLen:=TrackLen / (24 * 3600); //Выводим данные о времени на форму в Label1 и Label2 Label2.Caption:=FormatDateTime('hh:mm:ss',ValPos); Label3.Caption:=FormatDateTime('hh:mm:ss',ValLen); end;
Для компонента Timer2 события OnTimer пишем код:
//процедура скрытия курсора в полноэкранном режиме procedure TForm1.Timer2Timer(Sender: TObject); begin if FullScreen<>True then Exit; //проверяем положение курсора и если он не отклонился //от своего положения больше чем на пять точек, то скрываем курсор иначе показываем if ((xn-5)<=mouse.CursorPos.X) and ((yn-5)<=mouse.CursorPos.Y) and ((xn+5)>=mouse.CursorPos.X) and ((yn+5)>=mouse.CursorPos.Y)then pVideoWindow.HideCursor(true) else pVideoWindow.HideCursor(False); //запоминаем координаты курсора xn:=mouse.CursorPos.X; yn:=mouse.CursorPos.Y; end;
end.
Весь код приведен с подробными комментариями, думаю, что разобраться с ним будет не сложно. Если возникнут вопросы, пишите в комментариях.
В статье использованы материалы из книги "Есенин С.А. DirectX и Delphi. Разработка графических и мультимедийных приложений".
procedure TForm2.Timer1Timer(Sender: TObject); var TrackLen, TrackPos: Double; ValPos: Double; ValLen: Double; plVolume:Longint; db : integer; begin //выводим время Panel4.Caption:=TimeToStr(SysUtils.Time); ! //проверяем режим воспроизведения, если не Play то выходим if hr <> 0 then Exit; ! //время проигрывания фильма //считываем всю длину фильма в секундах pMediaPosition.get_Duration(pDuration); //задаем максимальное положение ProgressBar ProgressBar1.Max:=round(pDuration); //считаваем сколько секунд прошло от начала воспроизведения pMediaPosition.get_CurrentPosition(pCurrent); //задаем текущее положение ProgressBar ProgressBar1.Position:=round(pCurrent); //воспроизведение следующего фильма //если время проигрывания равно длине фильма по времени, if pCurrent=pDuration then begin //то выбираем следующую запись из плейлиста if i<ListBox2.Items.Count-1 then ! begin inc(i); Filename:=ListBox1.Items.Strings[i]; ! ListBox1.ItemIndex:=i; ! ListBox2.ItemIndex:=i; ! mode:=stop; player; ! end //если лист закончился - выходим else exit;
Здравствуйте. Подскажите пожалуйста, из -за чего появляются эти ошибки? Ошибки я отметил восклицательным знаком. При коментировании Panel4.Caption:=TimeToStr(SysUtils.Time); ошибки исчезают, кроме player.Кодprocedure TForm2.Timer1Timer(Sender: TObject); varTrackLen, TrackPos: Double;ValPos: Double;ValLen: Double;plVolume:Longint;db : integer;begin//выводим времяPanel4.Caption:=TimeToStr(SysUtils.Time); !//проверяем режим воспроизведения, если не Play то выходимif hr <> 0 then Exit; !//время проигрывания фильма//считываем всю длину фильма в секундахpMediaPosition.get_Duration(pDuration);//задаем максимальное положение ProgressBarProgressBar1.Max:=round(pDuration);//считаваем сколько секунд прошло от начала воспроизведенияpMediaPosition.get_CurrentPosition(pCurrent);//задаем текущее положение ProgressBarProgressBar1.Position:=round(pCurrent); //воспроизведение следующего фильма//если время проигрывания равно длине фильма по времени,if pCurrent=pDuration thenbegin//то выбираем следующую запись из плейлистаif i<ListBox2.Items.Count-1 then ! begin inc(i); Filename:=ListBox1.Items.Strings; ! ListBox1.ItemIndex:=i; ! ListBox2.ItemIndex:=i;! mode:=stop; player; ! end//если лист закончился - выходим else exit; end; !
Нужна помощь, при воспроизведении какого либо фильма, отсутствует звук. Использовал оба варианта изменения громкости - тишина все равно, можешь помочь?..
Не работает мой исходник или ваш? Где вы пишите эту строчку? TPlayerMode = (Stop, Play, Paused); // режим воспроизведения Она должна быть в разделе Type:
type TPlayerMode = (Stop, Play, Paused); // режим воспроизведения TForm1 = class(TForm) ....................................... .......................................
Отличная статья для начинающих всё разжёвано и доступно подано! Да и в исходниках не чего лишнего (всё понятно наверное) для тех кто не сталкивался с этим. Я бы предложил для гибкости и удобства за место процедуры
procedure Initializ; написать функцию. например:
function CreateGraph(Pach:string; Panel:TPanel):Bool; stdcall; begin //освобождаем подключенные интерфейсы if Assigned(FMediaPosition) then FMediaPosition := nil; if Assigned(FBasicAudio) then FBasicAudio := nil; if Assigned(FVideoWindow) then FVideoWindow := nil; if Assigned(FMediaEvent) then FMediaEvent := nil; if Assigned(FMediaControl) then FMediaControl := nil; if Assigned(FGraphBuilder) then FGraphBuilder := nil; //Выходим если канал не выбран if Pach='' then exit; //получаем интерфейс IGraphBuilder CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, FGraphBuilder); //получаем интерфейс IGraphBuilder CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, FGraphBuilder); //получаем интерфейс управления звуком hr := FGraphBuilder.QueryInterface(IBasicAudio, FBasicAudio); if hr<>0 then begin ShowMessage('Не удается получить аудио интерфейс'); exit; end; //получаем интерфейс управления позицией проигрывания hr := FGraphBuilder.QueryInterface(IID_IMediaPosition, FMediaPosition); if hr<>0 then begin ShowMessage('Не удается получить интерфейс управления позицией'); exit; end; //вызываем RenderFile - граф фильтров строится автоматически if failed(FGraphBuilder.RenderFile(StringToOleStr(AnsiString(Pach)), nil)) then begin showmessage('Ошибка подключения.'); exit; end; //получаем интерфейс ImediaControl FGraphBuilder.QueryInterface(IID_IMediaControl, FMediaControl); //получаем интерфейс IVideoWindow FGraphBuilder.QueryInterface(IID_IVideoWindow, FVideoWindow); //распологаем окно вывода на Panel1 FVideoWindow.put_Owner(Panel.Handle); FVideoWindow.put_WindowStyle(WS_CHILD or WS_CLIPSIBLINGS); FVideoWindow.put_MessageDrain(Panel.Handle); FVideoWindow.SetWindowPosition(0, 0, Panel.ClientRect.Right,Panel.ClientRect.Bottom); //запускаем на воспроизведение FMediaControl.Run; end;
использовать типо так CreateGraph(PChar(Addons[ListBox2.ItemIndex + 1]),Panel1)
Я попробовал ваш плеер в работе и обнаружил такую фигню почему то курсор плеера исчезает только при легком движении мыши а без движения мыши может остаться видимым или скрыться, когда как. Я сам уже давно пытаюсь решить эту проблему в своем плеере на основе DirectShow .У меня та же проблема ни как не хочет скрывать курсор независимо от движения мыши как например сделано в VLC плеере или Media Player Classik Ума не приложу как у них выполнено решение данной задачи,на мой взгляд не маловажной задачи. Может вы знаете как решить эту проблему или можете сказать почему требуется двигать мышь, чтобы курсор скрывался?
Ну не знаю, я специально минут пять пробовал, поймать у себя глюк который вы описываете, но так и не смог. У меня все работает правильно, если курсор мыши замирает, то он через две секунды скрывается, и больше не появляется пока мышь с нова не пошевелишь. Возможно у вас проблемы с мышью, бывает такое, что на некоторых поверхностях, происходит самопроизвольное движение мыши, это связано с плохой оптикой мыши (для нее нужен специальный коврик). Здесь скрытие курсора происходит довольно просто, каждые две секунды считываются координаты мыши (по таймеру), а затем происходит проверка, изменились ли координаты мыши в пределах пяти точек от их первоначального значения, если нет то скрываем курсор иначе показываем. Единственное, что курсор сам не скрывается, если он наведен на панель управления или плейлист. Хотите, чтобы это скрывалось тоже, то нужно логику показа панели и плейлиста перенести из события: //процедура показывания плейлиста и панели управления при наведении на них мыши procedure TForm1.Panel1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); в таймер где происходит скрытие курсора. Например, так для панели управления:
Код
//процедура скрытия курсора в полноэкранном режиме procedure TForm1.Timer2Timer(Sender: TObject); begin if FullScreen<>True then Exit; //проверяем положение курсора и если он не отклонился //от своего положения больше чем на пять точек, то скрываем курсор иначе показываем if ((xn-5)<=mouse.CursorPos.X) and ((yn-5)<=mouse.CursorPos.Y) and ((xn+5)>=mouse.CursorPos.X) and ((yn+5)>=mouse.CursorPos.Y)then begin pVideoWindow.HideCursor(true); groupbox1.Visible:=false; end else begin pVideoWindow.HideCursor(False); groupbox1.Visible:=true; end; //запоминаем координаты курсора xn:=mouse.CursorPos.X; yn:=mouse.CursorPos.Y; end;
Тогда панель управления будет появляться при движении мыши и исчезать, если движения нет.))))
Не знаю актуально-ли, но в win7x64 и D7 встретил эту проблему. Походу pVideoWindow.HideCursor() некорректно отрабатывает. Всё вылечилось заменой этой процедуры на:
procedure ShowMouse; var CState: Integer; begin CState := ShowCursor(True); while CState < 0 do CState := ShowCursor(True); end;
procedure HideMouse; var CState: Integer; begin CState := ShowCursor(True); while Cstate >= 0 do Cstate := ShowCursor(False); end;
Вроде сделал подобный плеер, переписав малость "под себя", всё работает, вот только никак не могу сообразить как реализовать переключение аудиоканалов в файлах с более чем одной звуковой дорожкой?