2015-09-25 50 views
0

我想使用线程创建备份文件,并且过程的进度将用TProgressBarTLabel表示,该动态将被动态创建为TStatusBar之一面板。德尔福:将StatusBar.OnDrawPanel事件分配给线程

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; 

主题是这样的:

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_barlabel_status并使它们在status_bar上可见,可以吗?我相信它会工作...

回答

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; 
+0

作品!谢谢雷米的解决方案和您的时间! – REALSOFO