Как показать модальное окно во время выполнения TThread и закрыть его при завершении
При разработке приложений на Delphi и Pascal часто возникает необходимость показать пользователю модальное окно, которое будет информировать его о том, что приложение выполняет какую-то длительную операцию. В этом случае можно использовать потоки (threads) для выполнения фоновой работы, а модальное окно показывать поверх основного окна приложения. В этой статье мы рассмотрим, как это можно сделать.
Подход №1: не используйте модальное окно
Первый подход заключается в том, чтобы не использовать модальное окно вообще. Вместо этого можно просто показывать основное окно приложения, а фоновую работу выполнять в отдельном потоке. При этом можно использовать методы TThread.Synchronize() или TThread.Queue() для безопасного доступа к элементам интерфейса пользователя из потока.
Вот пример кода, который демонстрирует этот подход:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TLoader = class(TThread)
private
FStrings: TStrings;
procedure ShowWait;
procedure EndsWait;
public
constructor Create(AStrings: TStrings);
destructor Destroy; override;
procedure Execute; override;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
List: TStrings;
begin
List := TStringList.Create;
try
// Загрузка данных
TLoader.Create(List);
finally
List.Free;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
end;
{ TLoader }
constructor TLoader.Create(AStrings: TStrings);
begin
inherited Create;
FreeOnTerminate:= True;
FStrings:= TStringList.Create;
FStrings.AddStrings(AStrings);
end;
destructor TLoader.Destroy;
begin
FStrings.Free;
inherited;
end;
procedure TLoader.Execute;
begin
inherited;
Synchronize(ShowWait);
// Выполнение фоновой работы
Sleep(1000);
// Закрытие модального окна
Synchronize(EndsWait);
end;
procedure TLoader.ShowWait;
begin
with TForm.Create(Application) do
begin
// Некоторые действия
Name:= 'FWait';
Show;
end;
end;
procedure TLoader.EndsWait;
begin
TForm(Application.FindComponent('FWait')).Close;
end;
end.
В этом примере при нажатии на кнопку Button1 создается новый поток TLoader, который выполняет фоновую работу. Перед началом работы поток показывает модальное окно FWait с помощью метода Show(). После завершения работы поток закрывает модальное окно с помощью метода Close().
Подход №2: используйте модальное окно
Второй подход заключается в том, чтобы использовать модальное окно для информирования пользователя о том, что приложение выполняет длительную операцию. В этом случае можно создать отдельный поток, который будет выполнять фоновую работу, а модальное окно показывать из основного потока.
Вот пример кода, который демонстрирует этот подход:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TLoader = class(TThread)
private
FStrings: TStrings;
FWaitForm: TForm;
procedure ShowWait;
procedure EndsWait;
public
constructor Create(AStrings: TStrings; AWaitForm: TForm);
destructor Destroy; override;
procedure Execute; override;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
List: TStrings;
begin
List := TStringList.Create;
try
// Загрузка данных
TLoader.Create(List, Form1);
finally
List.Free;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
// Создание модального окна
with TForm.Create(Application) do
begin
Name:= 'FWait';
BorderStyle:= bsDialog;
Caption:= 'Please wait...';
Width:= 200;
Height:= 150;
Position:= poDesktopCenter;
ShowModal;
end;
end;
{ TLoader }
constructor TLoader.Create(AStrings: TStrings; AWaitForm: TForm);
begin
inherited Create;
FreeOnTerminate:= True;
FStrings:= TStringList.Create;
FStrings.AddStrings(AStrings);
FWaitForm:= AWaitForm;
end;
destructor TLoader.Destroy;
begin
FStrings.Free;
inherited;
end;
procedure TLoader.Execute;
begin
inherited;
// Выполнение фоновой работы
Sleep(1000);
// Закрытие модального окна
Synchronize(EndsWait);
end;
procedure TLoader.ShowWait;
begin
FWaitForm.Show;
end;
procedure TLoader.EndsWait;
begin
FWaitForm.Close;
end;
end.
В этом примере при нажатии на кнопку Button1 создается новый поток TLoader, который выполняет фоновую работу. Перед началом работы поток показывает модальное окно FWait с помощью метода Show(). После завершения работы поток закрывает модальное окно с помощью метода Close().
При этом модальное окно создается из основного потока в методе FormCreate() формы Form1. При нажатии на кнопку Button1 создается новый поток TLoader, которому передается указатель на модальное окно FWait и список данных для загрузки.
Заключение
В этой статье мы рассмотрели два подхода к показу модального окна во время выполнения фоновой работы в потоке. Первый подход заключается в том, чтобы не использовать модальное окно вообще, а второй подход заключается в том, чтобы использовать модальное окно для информирования пользователя о том, что приложение выполняет длительную операцию. В зависимости от конкретной задачи можно выбрать один из этих подходов или комбинировать их.
При разработке приложений на Delphi и Pascal для информирования пользователя о длительной фоновой операции можно использовать потоки и показывать модальное окно поверх основного окна приложения.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.