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

CCM*_*CCM 5 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;
Run Code Online (Sandbox Code Playgroud)

问题是,panel1直到媒体播放器播放声音文件时,标题才会改变; 我需要改变标题,让玩家同时开始玩.我怎样才能确保这一点?

我认为该过程将按顺序执行每行代码,这意味着panel1更改的标题,然后媒体播放器开始行动.我哪里出错了?

qua*_*oft 10

说明:

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

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

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

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

这不会给主线程处理它的消息队列并启动重绘的机会.

快速解决:

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

panel1.Caption := 'This is a sentence';
Application.ProcessMessages();
Run Code Online (Sandbox Code Playgroud)

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

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

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;
Run Code Online (Sandbox Code Playgroud)

附注:

这里发布的VCL消息循环(Delphi Developer's Guide的一部分)有一个简短的解释:

消息系统剖析:VCL

另外,与问题无关,但请看一下Delphi编码风格指南.当代码发布格式化时,这很好.


bec*_*ems 2

Refresh设置标题后添加调用,即:

panel1.caption:='This is a sentence'; 
Refresh;
Run Code Online (Sandbox Code Playgroud)

  • 我对此表示反对,因为它没有回答问题,即为什么问题中的代码会如此运行。我认为理解比能够盲目遵循食谱重要得多。就你所知,这个食谱可能看似解决了一个问题,但却引入了更多问题。 (4认同)
  • 最好能解释一下为什么这样做会起作用。具体来说,它都是在应用程序的主线程中处理的。 (2认同)