unit Thread_ImageCreate;
interface
uses
Windows, Classes, Forms, Graphics;
type
TImageCreateThread = class(TThread) //Новый класс
private
protected
procedure ShowError;
procedure Execute; override;
public
constructor Create(CreateSuspennded:Boolean);
end;
implementation
constructor TImageCreateThread.Create(CreateSuspennded:Boolean);
begin
inherited Create(CreateSuspennded);
end;
procedure TImageCreateThread.ShowError;
begin
Application.MessageBox(PChar('11111'),'Error',MB_ICONERROR);
end;
procedure TImageCreateThread.Execute;
var ZBitmap,BM:TBitmap;
i:Integer;
begin
try
ZBitmap:=TBitmap.Create;
ZBitmap.PixelFormat:=pf4bit;
ZBitmap.Width:=4000;
ZBitmap.Height:=4000;
for i:=1 to 1000 do
begin
BM:=TBitmap.Create;
BM.LoadFromFile('c:\1.bmp');
ZBitmap.Canvas.Draw(i*3,i*3,BM);
BM.Free;
end;
ZBitmap.SaveToFile('c:\3.bmp');
ZBitmap.Free;
except
Synchronize(ShowError);
end;
end;
end.
Поток+dll
Попытаюсь объяснить:
В приложении создан поток скажем Thread1:TThread, который делает следующее:
1. Кэширует БД с помощью RxMemoryData (RxMemoryData НЕ создается дин. в потоке);
2. Используя кэшированные данные, загружает соответствующие битмапы из dll
и отображает их в соотвествующих местах на большом битмапе, скажем BIGBM:BITMAP
(BIGBM - локальная переменная потока; загрузка из dll осуществляется через
TResourceStream (для избежания проблем с палитрой) через лок. переменную скажем
BM:BITMAP; перенос BM на BIGBM осущ. разными способами как методом Draw, так и по
пиксельно через Pixels);
3. Сохраняет BIGBM в файл ".bmp".
Поток запускается скажем по кнопке.
Мной ОТДЕЛЬНО проверен каждый из перечисленных этапов:
1. Данные успешно кэширются;
2. Картинки в BM загружаются. Проверяемая BM успешно перерисовывается на BIGBM;
3. BIGBM успешно сохр. в файл.
НО! В сумме при эксплуатации появляется непонятное явление - при очередном запуске на конечной картинке в файле обязательно какая-нибудь часть (или несколько частей) нарисована частично, как бы недорисована.
Подскажите, пжл., в каком направлении копать (бьюсь уже несколько дней, многое перепробовал).
PS: Когда тоже самое было реализовано не в потоке и без кэширования, то такой проблемы не было.
наверно, проблемы с синхронизацией, заключи весь код который работает с "контролами" в отдельную процедуру и вызывай её так Synchronize(<твоя процедура>), короче посмотри справку по классу TThread
Модуль потока:
Код:
Вызов потока из приложения:
Код:
procedure TForm.FormClick(Sender: TObject);
function GetHandle(iThread:TThread):HWND;
begin
if iThread<>nil then Result:=iThread.Handle
else Result:=HWND(0);
end;
begin
if WaitForSingleObject(GetHandle(ImageCreateThread),0)<>WAIT_TIMEOUT then
begin//запуск потока
ImageCreateThread:=TImageCreateThread.Create(True);
ImageCreateThread.FreeOnTerminate:=True;
ImageCreateThread.Resume;
end;
end;
function GetHandle(iThread:TThread):HWND;
begin
if iThread<>nil then Result:=iThread.Handle
else Result:=HWND(0);
end;
begin
if WaitForSingleObject(GetHandle(ImageCreateThread),0)<>WAIT_TIMEOUT then
begin//запуск потока
ImageCreateThread:=TImageCreateThread.Create(True);
ImageCreateThread.FreeOnTerminate:=True;
ImageCreateThread.Resume;
end;
end;
Если позапускать поток, то можно увидеть, что в файле 3.bmp часть картинок отсутствует в ряду (случайным образом) - их просто нет. Особо это заметно, если при работе потока интенсивно лазить по интефейсу программы.
попробуй "рефрешить" форму потом или что нибудь такое.....
Для всех кому интересно и тем, кто возможно с этим столкнется.
Ниже приведены модули ТЕСТОВОГО приложения. Отдельно помечены
обязательные добавления!
Вызов потока:
Код:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;
type
TForm1 = class(TForm)
procedure FormClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses Thread_ImageCreate;
{$R *.dfm}
procedure TForm1.FormClick(Sender: TObject);
begin
if Assigned(ImageCreateThread)=false then
begin
form1.Caption:='Start';
ImageCreateThread:=TImageCreateThread.Create(true);
ImageCreateThread.FreeOnTerminate:=true;
ImageCreateThread.Resume;
end;
end;
end.
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;
type
TForm1 = class(TForm)
procedure FormClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses Thread_ImageCreate;
{$R *.dfm}
procedure TForm1.FormClick(Sender: TObject);
begin
if Assigned(ImageCreateThread)=false then
begin
form1.Caption:='Start';
ImageCreateThread:=TImageCreateThread.Create(true);
ImageCreateThread.FreeOnTerminate:=true;
ImageCreateThread.Resume;
end;
end;
end.
Модуль потока:
Код:
unit Thread_ImageCreate;
interface
uses
Windows, Classes, Forms, Graphics, SysUtils;
type
TImageCreateThread = class(TThread) //Новый класс
private
FStep:Integer;
protected
procedure ShowError;
procedure Progress;
procedure Execute; override;
public
constructor Create(CreateSuspended:Boolean);
destructor Destroy; override;
end;
var ImageCreateThread:TImageCreateThread;
implementation
uses Unit1;
constructor TImageCreateThread.Create(CreateSuspended:Boolean);
begin
inherited Create(CreateSuspended);
FStep:=0;
end;
destructor TImageCreateThread.Destroy;
begin
inherited;
ImageCreateThread:=nil;
end;
procedure TImageCreateThread.Progress;
begin
form1.Caption:=IntToStr(FStep);
end;
procedure TImageCreateThread.ShowError;
begin
Application.MessageBox(PChar('11111'),'Error',MB_ICONERROR);
end;
procedure TImageCreateThread.Execute;
var ZBitmap,BM:TBitmap;
i:Integer;
begin
try
ZBitmap:=TBitmap.Create;
ZBitmap.PixelFormat:=pf4bit;
ZBitmap.Width:=4000;
ZBitmap.Height:=4000;
ZBitmap.Canvas.Lock;{NEWNEWNEWNENWNEWNEWNEW}
for i:=1 to 1000 do
begin
BM:=TBitmap.Create;
BM.Canvas.Lock;{NEWNEWNEWNENWNEWNEWNEW}
BM.LoadFromFile('c:\1.bmp');
ZBitmap.Canvas.Draw(i*3,i*3,BM);
BM.Canvas.Unlock;{NEWNEWNEWNENWNEWNEWNEW}
FreeAndNil(BM);
FStep:=i;
Synchronize(Progress);
end;
ZBitmap.SaveToFile('c:\3.bmp');
ZBitmap.Canvas.Unlock;{NEWNEWNEWNENWNEWNEWNEW}
FreeAndNil(ZBitmap);
except
Synchronize(ShowError);
end;
end;
end.
interface
uses
Windows, Classes, Forms, Graphics, SysUtils;
type
TImageCreateThread = class(TThread) //Новый класс
private
FStep:Integer;
protected
procedure ShowError;
procedure Progress;
procedure Execute; override;
public
constructor Create(CreateSuspended:Boolean);
destructor Destroy; override;
end;
var ImageCreateThread:TImageCreateThread;
implementation
uses Unit1;
constructor TImageCreateThread.Create(CreateSuspended:Boolean);
begin
inherited Create(CreateSuspended);
FStep:=0;
end;
destructor TImageCreateThread.Destroy;
begin
inherited;
ImageCreateThread:=nil;
end;
procedure TImageCreateThread.Progress;
begin
form1.Caption:=IntToStr(FStep);
end;
procedure TImageCreateThread.ShowError;
begin
Application.MessageBox(PChar('11111'),'Error',MB_ICONERROR);
end;
procedure TImageCreateThread.Execute;
var ZBitmap,BM:TBitmap;
i:Integer;
begin
try
ZBitmap:=TBitmap.Create;
ZBitmap.PixelFormat:=pf4bit;
ZBitmap.Width:=4000;
ZBitmap.Height:=4000;
ZBitmap.Canvas.Lock;{NEWNEWNEWNENWNEWNEWNEW}
for i:=1 to 1000 do
begin
BM:=TBitmap.Create;
BM.Canvas.Lock;{NEWNEWNEWNENWNEWNEWNEW}
BM.LoadFromFile('c:\1.bmp');
ZBitmap.Canvas.Draw(i*3,i*3,BM);
BM.Canvas.Unlock;{NEWNEWNEWNENWNEWNEWNEW}
FreeAndNil(BM);
FStep:=i;
Synchronize(Progress);
end;
ZBitmap.SaveToFile('c:\3.bmp');
ZBitmap.Canvas.Unlock;{NEWNEWNEWNENWNEWNEWNEW}
FreeAndNil(ZBitmap);
except
Synchronize(ShowError);
end;
end;
end.
PS: В примере специально часто вызывается Synchronize, чтобы усугубить нарушения канвы (см. далее).
В данном примере НИКАКИХ нарушений в конечном "3.bmp" в ходе тестирования я не обнаружил.
Если же УБРАТЬ блокировку канвы, то как я уже говорил часть картинок "1.bmp" будет просто ПРОПАДАТЬ из общего ряда. Особенно сильно это будет заметно, если при работе потока преремещать Form1 по экрану в разные стороны. Мало того довольно часто при записи "3.bmp" в файл будет выскакивать сообщение:
---------------------------
Debugger Exception Notification
---------------------------
Project Project1.exe raised exception class EOutOfResources with message 'Невозможно создать файл, так как он уже существует.
'. Process stopped. Use Step or Run to continue.
---------------------------
OK Help
---------------------------