Как показать прошедшее время, в то время как долгий SQL-запрос выполняется?

Я должен показать всплывающее окно перед выполнением запросов, показать, что время протекло, в то время как запрос SQL выполняется, и закройте то окно, когда запрос заканчивается.

На самом деле я делаю что-то вроде этого

var
  frm : tFrmPopupElapsed;
  // this form has a TTimer and a TLabel to show the elapsed time
  // but the label is not updated, I tried using update and refresh
  // but nothing happens
begin
  frm := tFrmPopupElapsed.Create(nil);
  try
    frm.Init; // this procedure enables the timer
    frm.Show();
    ExecuteMyVeryLongQuery();
  finally
    frm.Close; 
  end;
end;

Как маркировка может быть обновлена для показа прошедшего времени, в то время как запрос выполняется? Используя таймер? Или поток?

6
задан mghie 27 March 2010 в 14:01
поделиться

3 ответа

Вам необходимо выполнить запрос асинхронно , позволяя тем временем обновлять форму.
Самый простой способ сделать это, не запачкая руки потоками , - это использовать библиотеку Андреаса Хаусладена AsynCalls .
Вы также можете ознакомиться с библиотекой OmniThread , написанной Примозом Габриелчичем.

4
ответ дан 17 December 2019 в 04:44
поделиться

Вам нужно будет запустить запрос в фоновом потоке, если вы хотите, чтобы пользовательский интерфейс реагировал во время выполнения запроса. Если запрос поддерживает отмену, вы также можете добавить кнопку отмены. Однако я считаю, что это поддерживают только запросы ADO.

1
ответ дан 17 December 2019 в 04:44
поделиться

Этот вопрос намного сложнее, чем предполагалось изначально; что делает это хорошим вопросом.

Сначала я подумал, что Application.processmessages - правильный путь, однако это потенциальное минное поле, если вы не будете осторожны (спасибо @skamradt за указание на это). Это также не помогает с единичным блокирующим звонком.

Фоновый поток необходим следующим образом: (спасибо @mghie за указание на ошибки, которые теперь устранены). По-прежнему могут возникать проблемы с вызовом объекта базы данных в разных потоках, поэтому фоновому потоку может потребоваться собственное соединение с базой данных для этой операции (если это возможно).

В приведенном ниже примере я специально не показывал код для создания и уничтожения окна прогресса, так как это сделает код еще длиннее, и это будет легко сделать.

Итак, для этого нам нужны два объекта:

Во-первых, фоновый поток для обработки запроса.

unit BackgroundProcess;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs, windows;

const
  WM_MY_BACKGROUNDNOTIFY = WM_USER + 555; { change this }
  NOTIFY_BEGIN = 22;
  NOTIFY_END   = 33;

type
  TBackgroundQueryThread = class(TThread)
  private
    hwndnotify : HWND;
  protected
    procedure Execute; override;
  public
    constructor Create(owner: TForm);
  end;


implementation

constructor TBackgroundQueryThread.Create(owner: TForm) ;
begin
    inherited Create(False);
    hwndnotify := owner.Handle;
    FreeOnTerminate := true;
    resume;
end;

procedure TBackgroundQueryThread.Execute;
begin
     PostMessage(hwndnotify, WM_MY_BACKGROUNDNOTIFY, NOTIFY_BEGIN, 0);
     Sleep(2000); (* Query goes here. *)
     PostMessage(hwndnotify, WM_MY_BACKGROUNDNOTIFY, NOTIFY_END, 0);
end;

end.           

Форма, которая вызывает запрос:

unit mainform;

interface

uses
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  StdCtrls, ExtCtrls, windows, BackgroundProcess;

type
  TForm1 = class(TForm)
  private
    frm : tFrmPopupElapsed;
    { private declarations }
    procedure OnMyBackgrounNotify(var Msg: TMessage); message WM_MY_BACKGROUNDNOTIFY;
  public
    { public declarations }
  end; 

var
  Form1: TForm1; 

implementation


procedure TForm1.OnMyBackgrounNotify(var Msg: TMessage);
begin
  if (msg.WParam = NOTIFY_BEGIN) THEN
  BEGIN
     if (frm = nil) THEN
     BEGIN
         frm := tFrmPopupElapsed.Create(nil);
         frm.Init; // this procedure enables the timer
         frm.Show();
     END;
  END;

  if (msg.WParam = NOTIFY_END) THEN
  BEGIN
     if (frm <> nil) THEN
     BEGIN
         frm.Close;
     END;
  END;

end;

end.
0
ответ дан 17 December 2019 в 04:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: