如何在不同于主线程的单独线程中打开ClientDataSet(主/细节)

3

使用工具:Delphi XE2、DBExpress、Firebird

我无法安全地在主线程之外访问任何VCL控件,包括表单、面板、编辑框等以及Timage和Timage的派生类。我需要在单独的线程(不同于主线程)中打开ClientDataSet(主/细节)。

我需要在访问数据库时创建动画闪屏。

有人能给我展示一个简单的例子吗?


谢谢LI RD,但我正在寻找在同一表单中使用ClientDaSet的示例。 - dataol
使用这些代码后,我的动态GIF被冻结了。 - dataol
抱歉我的英语不好。 - dataol
明天我会发布一个例子。在此期间,祝你新年快乐! - LU RD
好的,谢谢!新年快乐! - dataol
1个回答

2
我认为在线程中访问数据库对您来说不是问题。
如果您需要一个完整的 dbExpress 数据库线程访问示例(包括反馈到主线程),请参见 Marco Cantù 在此处制作的示例:dbexpress_firebird_examples
它涉及将所有数据库连接设置放入 TDataModule 中,并为每个线程访问创建此数据模块的实例。
无论如何,要使 GUI 了解后台线程进程并显示动画 Gif,这里有一个示例:

enter image description here

unit TestAnimatedScreen;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Imaging.GIFImg,
  Vcl.ExtCtrls;

type
  TMyEndNotify = procedure (value: Boolean) of object;

type
  TMyThread = class(TThread)
  private
    fEndNotification : TMyEndNotify;
    procedure NotifyEndOfThread;
  protected
    procedure Execute; override;
  public
    Constructor Create(endNotification : TMyEndNotify);
  end;

type
  TMainForm = class(TForm)
    Image1: TImage;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    FShowAnimation : Boolean;
    procedure SetShowAnimation(value : Boolean);
  public
    { Public declarations }
    property ShowAnimation : Boolean read FShowAnimation write SetShowAnimation;
  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

procedure TMyThread.NotifyEndOfThread;
begin
  if Assigned(fEndNotification) then
    fEndNotification(False);
end;

constructor TMyThread.Create(endNotification: TMyEndNotify);
begin
  Inherited Create(false);
  fEndNotification := endNotification;
  Self.FreeOnTerminate := True; // Free automatically
end;

procedure TMyThread.Execute;
begin
  try
    {Add your database access code here}
    Sleep(5000); // Simulate lengthy process
  finally
    Synchronize(NotifyEndOfThread);
  end;
end;

{ TMainForm }

procedure TMainForm.Button1Click(Sender: TObject);
begin
  ShowAnimation := True;
  TMyThread.Create(Self.SetShowAnimation);
end;

procedure TMainForm.SetShowAnimation(value: Boolean);
begin
  FShowAnimation := Value;
  if FShowAnimation then
  begin
    {Add animation code here}
    Button1.Enabled := false;
    Button1.Caption := 'Processing, please wait ...';
    (Image1.Picture.Graphic as TGIFImage).AnimateLoop := glEnabled;
    (Image1.Picture.Graphic as TGIFImage).Animate := true;
  end
  else
  begin
    {Stop animation}
    (Image1.Picture.Graphic as TGIFImage).Animate := false;
    Button1.Caption := 'Start lengthy process';
    Button1.Enabled := True;
  end;
end;

end.

object MainForm: TMainForm
  Left = 0
  Top = 0
  Caption = 'MainForm'
  ClientHeight = 265
  ClientWidth = 236
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Image1: TImage
    Left = 8
    Top = 8
    Width = 200
    Height = 200
    AutoSize = True
    IncrementalDisplay = True
  end
  object Button1: TButton
    Left = 8
    Top = 224
    Width = 200
    Height = 25
    Caption = 'Start lengthy process'
    TabOrder = 0
    OnClick = Button1Click
  end
end

如果您使用的 Delphi 版本早于 Delphi 2007,请查看如何在 Delphi 表单中使用动态 GIF以获取有关如何实现动态 GIF 的更多信息。
我使用的动态 GIF 可在 这里 找到。

但是在线程中访问数据库对我来说是一个问题。当我尝试使用它时,会出现访问冲突的错误。 - dataol
好的,那我建议您编辑您的问题并添加数据库访问代码以及错误的详细描述。 - LU RD
通常情况下,TClientDataSet 应该是线程本地的。同时,请记得从线程中打开一个新的数据库会话。如果您想将线程 clientdataset 中的数据传输到主线程中的某个对象,请在 Synchronize() 方法中执行此操作。 - LU RD
好的。我正在制作一个小应用程序来展示错误。稍后在这里发布。 - dataol
Marco Cantu 发布了一些 FirebirddbExpress 的例子,其中包括一个多线程池示例。请参阅 dbexpress_firebird_examples - LU RD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接