【问题标题】:How to open ClientDataSet (master/detail) in separate thread(different of main thread)如何在单独的线程(与主线程不同)中打开 ClientDataSet(主/详细信息)
【发布时间】:2012-12-30 19:27:22
【问题描述】:

使用:Delphi XE2、DBExpress、Firebird

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

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

谁能给我一个简单的例子来说明如何做到这一点?

【问题讨论】:

标签: multithreading delphi firebird datasnap dbexpress


【解决方案1】:

我假设线程中的数据库访问对你来说没有问题。

有关对 dbExpress 数据库进行线程访问的完整示例(包括对主线程的反馈),请参阅Marco Cantù 提供的示例:dbexpress_firebird_examples

它涉及将所有数据库连接设置放在TDataModule 中,并为每个线程访问创建此数据模块的实例。

无论如何, 使用动画 Gif 让 GUI 了解后台线程进程,下面是一个示例:

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 旧,请参阅 How to use Animated Gif in a delphi form 了解有关如何实现动画 GIF 的更多信息。

我使用的动图可以在here找到。

【讨论】:

  • 但是线程中的数据库访问对我来说是个问题。当我尝试使用 i 时,出现访问冲突
  • 好的,那么我建议您编辑您的问题并添加数据库访问代码以及对错误的良好描述。
  • 通常TClientDataSet 应该是线程本地的。并且记住也要从线程中打开一个新的数据库会话。如果要将数据从线程 clientdataset 传输到主线程中的某个东西,请在 Synchronize() 方法中执行此操作。
  • 好的。我正在一个小应用程序中重现错误以向您展示。稍后在此处发布。
  • Marco Cantu 发布了一些FirebirddbExpress 的示例,包括一个多线程池示例。见dbexpress_firebird_examples
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多