我正在尝试使用线程创建备份文件,并且将使用TProgressBar
和TLabel
来指示流程的进度,该TStatusBar
和backup_thread:= Tbackup_thread.Create(True);
backup_thread.status_bar:= status_bar;
backup_thread.status_bar_OnDrawPanel:= status_bar.OnDrawPanel; //is it correct?
backup_thread.dir:= backup_dir;
backup_thread.OnTerminate:= backup_thread_OnTerminate;
backup_thread.Start;
将动态创建到其中一个{{1}面板。
Tbackup_thread = class(TThread)
private
Fstatus_bar: TStatusBar;
Fprogress_bar: TProgressBar;
Flabel_status: TLabel;
Fdir: String;
Fprogress_bar_position: Word;
Flabel_status_caption: String;
procedure do_update_progress_bar_position;
procedure do_update_label_status_caption;
procedure set_object_progress_bar(const progress_bar: TProgressBar);
procedure execute_backup;
procedure Get_status_bar_OnDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect); //is it correct?
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean);
destructor Destroy; override;
property status_bar: TStatusBar write Fstatus_bar;
property status_bar_OnDrawPanel: TDrawPanelEvent read Get_status_bar_OnDrawPanel; //I get the error here...
property dir: String write Fdir;
end;
线程看起来像这样:
Get_status_bar_OnDrawPanel
procedure Tbackup_thread.Get_status_bar_OnDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect);
begin
if Panel = Fstatus_bar.Panels[1] then
begin
with Fprogress_bar do begin
Top := Rect.Top;
Left := Rect.Left;
Width := 60;
Height := Rect.Bottom - Rect.Top;
end;
with Flabel_status do begin
Top := Rect.Top;
Left := Rect.Left + 105;
Width := 150;
Height := Rect.Bottom - Rect.Top;
end;
end;
end;
看起来像这样:
OnDrawPanel
我的问题是如何从线程内部分配事件progress_bar
。
如果我从线程内部动态创建label_status
和<?php
$literalObjectDeclared = (object) array(
'foo' => (object) array(
'bar' => 'baz',
'pax' => 'vax'
),
'moo' => 'ui'
);
print $literalObjectDeclared->foo->bar; // outputs "baz"!
?>
并使其在status_bar上可见,这样可以吗?我相信它会奏效......
答案 0 :(得分:3)
我的问题是如何从线程内部分配事件OnDrawPanel。
你没有从线程中指定它,如果已经分配,你只需调用它。在绘图事件的情况下,你没有手动调用开始,你让操作系统发出主要UI线程的信号调用事件处理程序何时需要。
如果我从线程内部动态创建progress_bar和label_status并在status_bar上显示它们,这样可以吗?
只有在执行此操作时才与UI线程同步。它们是UI控件,毕竟它们只需要在主UI线程的上下文中创建和更新。
我相信它会奏效......
不是你表现出来的方式,不。
我会建议一个不同的设计。该帖子应该具有状态栏的无知识或标签。它应该只是公开对其进度数据的访问,然后让主UI线程决定如何根据需要显示该数据。您可以为线程类创建新事件,只需确保在调用其处理程序时与主UI线程同步。
TThread.OnTerminate
事件就是一个很好的例子。
尝试这样的事情:
type
Tbackup_ProgressStatus_event = procedure(progress: Word; const status: String) of object;
Tbackup_thread = class(TThread)
private
...
Fposition: Word;
Fstatus: String;
FOnProgressStatus: Tbackup_ProgressStatus_event;
procedure update_progress_status(new_position: Word; const new_status: String);
procedure do_update_progress_status;
...
protected
procedure Execute; override;
public
...
property OnProgressStatus: Tbackup_ProgressStatus_event read FOnProgressStatus write FOnProgressStatus;
end;
procedure Tbackup_thread.Execute;
begin
...
update_progress_status(..., ...);
...
end;
procedure Tbackup_thread.update_progress_status(new_position: Word; const new_status: String);
begin
Fposition := new_position;
Fstatus := new_status;
if Assigned(FOnProgressStatus) then
Synchronize(do_update_progress_status);
end;
procedure Tbackup_thread.do_update_progress_status;
begin
if Assigned(FOnProgressStatus) then
FOnProgressStatus(Fposition, Fstatus);
end;
backup_thread := Tbackup_thread.Create(True);
backup_thread.dir := backup_dir;
backup_thread.OnStatus := backup_thread_OnProgressStatus;
backup_thread.OnTerminate := backup_thread_OnTerminate;
backup_thread.Start;
...
procedure TMyForm.backup_thread_OnProgressStatus(progress: Word; const status: String);
begin
// use progress and status as needed...
progress_bar.Position := progress;
label.Caption := status;
end;
procedure TMyForm.status_bar_OnDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect);
begin
// DRAW the specified TStatusPanel content within the specified TRect as needed...
// DO NOT do anything else here! Resizing controls DOES NOT belong in a
// DRAWING event! Do it before you even start the thread...
//
// Personally, I would not bother putting TProgressBar/TLabel controls
// inside a TStatusPanel to begin with. I would instead use THIS event
// to DRAW a progress bar and text directly onto the Sender.Canvas
// within the TRect using things like Sender.Canvas.FillRect() and
// Sender.Canvas.TextRect()...
end;