为什么tmediaplayer会延迟更改tpanel上的标题?

时间:2016-10-27 02:07:38

标签: delphi media-player

我是一名新手程序员,如果这对你们所有人来说听起来非常基本,那么道歉。 我有一个看起来(基本上)像这样的程序:

procedure TForm1.BitBtn1Click(Sender: TObject);
begin
  panel1.caption:='This is a sentence';
  with MediaPlayer1 do
  begin
    filename:='f:\untitled.wma';
    open;
    wait:=true;
    play;
    close;
  end;
end;

问题是panel1上的标题在媒体播放器播放声音文件之前不会改变;我需要改变标题,让玩家同时开始玩。我该如何确保这一点?

我认为该过程会按顺序执行每一行代码,这意味着panel1的标题会发生变化,然后媒体播放器就会生效。我哪里出错?

2 个答案:

答案 0 :(得分:10)

说明:

VCL组件(如TPanel)通常有一个名为Invalidate()的内部方法,当属性(如Caption)发生变化时调用该方法,并且该更改需要重新绘制部分控件(例如。绘制新标题文本)。

此方法仅在窗口控件内设置一个标志,但不调用重绘方法本身。这样做的原因是,如果一次更改许多属性(在短时间内顺序更改),则应避免多次调用Repaint()方法。

当组件通过主消息循环(从应用程序的主线程 - GUI线程处理)接收要重新绘制的消息时,实际调用Repaint()方法。

您开始播放媒体播放器的方式是阻止,因为您将Wait属性设置为True,这会使播放器阻止调用线程(再次是主线程),直到文件被删除为止播放。

这不会让主线程处理它的消息队列并启动重绘。

快速修复:

问题的快速解决方案是becsystems建议的那个,或者这个:

panel1.Caption := 'This is a sentence';
Application.ProcessMessages();

在开始播放文件之前,调用ProcessMessages()将使主线程有机会处理消息队列并执行更新。

这是一个快速修复,因为主线程在开始播放后仍然会被阻止,这将阻止窗口的其他部分重新绘制(例如,尝试移动窗口或在播放时最小化并最大化它)。< / p>

becsystems建议的代码类似,但不是处理消息队列,只是强制控件重绘。

正确修复:

要正确解决问题,您不应使用Wait属性,而应处理媒体播放器的OnNotify事件。

这是一个例子,改编自Swiss Delphi Center未测试,因为我目前没有安装Delphi ):

procedure TForm1.BitBtn1Click(Sender: TObject);
begin
  panel1.Caption := 'This is a sentence';
  with MediaPlayer1 do
  begin
    Notify := True;
    OnNotify := NotifyProc;
    Filename := 'f:\untitled.wma';
    Open;
    Play;
  end;
end;

procedure TForm1.NotifyProc(Sender: TObject);
begin
  with Sender as TMediaPlayer do 
  begin
    case Mode of
      mpStopped: {do something here};
    end;

    // Set to true to enable next-time notification
    Notify := True;
  end;
end;

附注:

此处发布的VCL消息循环(Delphi Developer&Guide?的一部分)有一个简短的解释:

  

Anatomy of a Message System: VCL

此外,与问题无关,但请查看Delphi Coding Style Guide。发布代码格式化后,这很不错。

答案 1 :(得分:2)

设置标题后添加Refresh来电,即:

panel1.caption:='This is a sentence'; 
Refresh;