Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 02.03.2012, 17:09   #1
demigod82
Пользователь
 
Регистрация: 16.01.2012
Сообщений: 35
По умолчанию Canvas в потоках

Я уже достаточно долго не могу понять, как иcпользовать методы canvas в потоке. Может кто нибудь объяснит это? Заранее благодарю.
demigod82 вне форума Ответить с цитированием
Старый 02.03.2012, 17:31   #2
Aliens_wolfs
Форумчанин
 
Регистрация: 16.12.2009
Сообщений: 902
По умолчанию

canvas в теле потока работать правильно никогда не будет, да и вообще визуальные действия в теле потока нельзя делать, для того чтобы работло нужно из тела потока синхронно вызывать созданное событие
К примеру


В форме задаем событие
Код:
    { Private declarations }
  public
    procedure OnLoadTexture(Sender: TObject)
end;

type
  TMoveObject = class(TThread)
  private
 FhEvent: THandle;
FCanvas: TCanvas;
FOnDraw: TNotifyEvent;
  protected
    procedure Execute; override;
    procedure Draw; virtual;
public
    constructor Create; virtual;
  destructor Destroy; override;
property OnDraw: TNotifyEvent read FOnDraw write FOnDraw;
property Canvas: TCanvasread FCanvas write FCanvas;
end;

var
  Form1: TForm1;
   MoveObjects: TMoveObjects;

implementation

{$R *.dfm}

constructor TMoveObject.Create;
begin
  inherited Create(True);
//для самоуничтожения когда Terminate
 FreeOnTerminate := True;
// Создаем хендел прерывания процесса
FhEvent := CreateEvent(nil, True, False, nil);
end;

procedure TMoveObject.Draw;
begin
//Рисуем 
FCanvas.Draw(0,0, и можно Bitmap но его нужно задать в потоке);
// предаем событие для наследника 
 if Assigned(FOnDraw) then
 FOnDraw(Self);
end;

destructor TMoveObject.Destroy;
begin
   CloseHandle(FhEvent);
  inherited;
end;

procedure TMoveObject.Execute;
begin
while not Terminated do
  begin
//Прерывание что бы неюыло зацикливания
     WaitForSingleObject(FhEvent, 100);
//Синхронно выполняем функцию
Synchronize(Draw);
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
//Создаем поток
MoveObjects:= TMoveObjects.Create;
//Передаем событие потока форме
MoveObjects.OnDraw:= OnDrawObject;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
//запускаем поток
MoveObjects.Resume;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
//останавливаем, об уничтожении нам заботится не нужно так как в потоке объявлено  FreeOnTerminate := True;
MoveObjects.Terminate;
end;


procedure TForm1.OnDrawObject(Sender: TObject) ;
begin
//Передаем канву потока форме
Form1.Canvas.Assign(MoveObjects.Canvas);
end;

Последний раз редактировалось Aliens_wolfs; 02.03.2012 в 17:47.
Aliens_wolfs вне форума Ответить с цитированием
Старый 02.03.2012, 18:00   #3
demigod82
Пользователь
 
Регистрация: 16.01.2012
Сообщений: 35
По умолчанию

А можно на примере этого кода?
Код:
procedure MyTread.Execute;
  { Place thread code here }
var
 symbol: string;
 f: TextFile;
 d, b: integer;
 symb: char;
begin
 AssignFile(f, '1.txt');// открываю файл
 Reset(f);
 for d:= 1 to 10 do begin// запускаю цикл
   for b:= 1 to 10 do begin
    While not(eof(f)) do begin
     Read(f, symb);
     FilesArr[d, b]:= symb;// записываю в массив
     symbol:= symb;
     Synchronize(DrawLevel);// пытаюсь сихронизировать для canvas
   end;
  end;
 end;
 CloseFile(f);
end;

procedure MyTread.DrawLevel(t, y: integer; sym: string);
begin
 u:= 60 * t;
 o:= 25 * y;
 if sym = '1' then begin
  with Form1.Canvas do begin// это не работает хотя мне советовали так
  Canvas.Brush.Color:=RGB(0, 255, 0);// пытаюсь рисовать
  Canvas.Rectangle(u, o, u - 60, o - 25);
 end;
 end;
 if sym = '2' then begin
  Canvas.Brush.Color:=RGB(0, 0, 255);
  Canvas.Rectangle(u, o, u - 60, o - 25);
 end;
end;
end;
В форме я просто запускаю цикл по созданию формы.
demigod82 вне форума Ответить с цитированием
Старый 02.03.2012, 19:54   #4
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

Подсказка: класс TBitmap тоже имеет Canvas
Делайте любые действия в потоке с переменной типа TBitmap, а потом просто в потоковой процедуре присваивайте ваш битмап.канвас визуальной канве. Процедура должна вызываться методом Synchronize().
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 04.03.2012, 12:37   #5
demigod82
Пользователь
 
Регистрация: 16.01.2012
Сообщений: 35
По умолчанию

А как присвоить bitmap канве формы?
demigod82 вне форума Ответить с цитированием
Старый 04.03.2012, 14:39   #6
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

Канву присвоить прямо нельзя, но вот рисовать на канве битмап - можно
Код:
  //работаем с канвой битмапа в потоке как хотим
  b:=TBitmap.Create;
  b.Width:=200;
  b.Height:=200;
  b.PixelFormat:=pf24bit;
  b.Canvas.Brush.Color:=clRed;
  b.Canvas.FillRect(b.Canvas.ClipRect);
  b.Canvas.Ellipse(0,0,50,50);
  b.Canvas.Rectangle(50,50,200,200);

  Form1.Image1.Canvas.Draw(0,0,b);//вызывать эту строчку в потоке с помощью Synchronize
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 04.03.2012, 15:38   #7
demigod82
Пользователь
 
Регистрация: 16.01.2012
Сообщений: 35
По умолчанию

Спасибо. Но у меня возникли новые проблемы. Фон image у меня стал белый, а нарисовать получается только один прямоугольник, хотя у меня код находится в цикле.
demigod82 вне форума Ответить с цитированием
Старый 04.03.2012, 16:03   #8
demigod82
Пользователь
 
Регистрация: 16.01.2012
Сообщений: 35
По умолчанию

Спасибо. Но у меня появились новые проблемы. У меня получается в цикле нарисовать только один прямоугольник( я так понял это потому что не перерисовывается?), а фон image стал белым и другие фигуры заходят за него. Да и если уж так всё с потоками сложно с графикой, как рисовать в canvas много фигур, чтобы это всё не тормозило при движении другой фигуры?

Последний раз редактировалось demigod82; 04.03.2012 в 16:19.
demigod82 вне форума Ответить с цитированием
Старый 04.03.2012, 19:34   #9
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

смысл в том, что ты рисуешь в потоке на канве БИТМАПА, а не формы! это разные вещи. Форма - визуальный VCl-компонент, и не ориентирован на многопоточность. С переменной типа TBitmap - другое дело, здесь ты в потоке работаешь с ней как с данными, не привязанными к чему-либо визуальному. Твоя ошибка скорее всего в неверном вызове процедуры синхронизации.
Например, в методе Execute твоего потока написать код работы с битмапом, а потом в нем же сделать такой вызов:
Код:
procedure TMyThread.Execute(Sender: TObject);
begin
//вставляешь здесь свой код с циклами по работе с переменной b
  Synchronize(VclDraw);//вызываешь прорисовку канвы переменной b
end;
Процедура VclDraw должна быть методом твоего потока:
Код:
procedure TMyThread.VclDraw;
begin
  Form1.Image1.Canvas.Draw(0,0,b);
end;
И не забудь прописать в секции uses модуль с твоей формой.
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 05.03.2012, 08:51   #10
Aliens_wolfs
Форумчанин
 
Регистрация: 16.12.2009
Сообщений: 902
По умолчанию

Цитата:
procedure TMyThread.Execute(Sender: TObject);
begin
//вставляешь здесь свой код с циклами по работе с переменной b
Synchronize(VclDraw);//вызываешь прорисовку канвы переменной b
end;
(Sender: TObject); там ненужен, и вообще смысл потока без цикла для простых действий где нет ожидания выполнения в этом случае он ненужен и еще нужно прерывание делать если будет цикл в потоке типа
while not Terminated do
а то процессор будет грузить даже когда Synchronize либо Sleep(10); либо WaitForSingleObject(FhEvent, 10);

Цикл должен быть в теле потока. Примерно так
Код:
procedure TMyThread.Execute;
begin
while not Terminated do
  begin
//Прерывание что бы небыло загруженности процессора
Sleep(10);
либо
WaitForSingleObject(FhEvent, 100);// тогда можно ускорять с помощью SetEvent(FhEvent) из какой нибудь функции если нужно да и так правельнее
//Синхронно выполняем функцию
 Synchronize(VclDraw);
end;
end;

Последний раз редактировалось Aliens_wolfs; 05.03.2012 в 09:08.
Aliens_wolfs вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
О подключаемых модулях, формах и потоках bagos Общие вопросы Delphi 6 13.12.2010 19:53
синхронизация в потоках xrob Общие вопросы Delphi 8 15.11.2010 17:25
Suspend и Resume в потоках (C#) lot555 C# (си шарп) 0 31.10.2010 20:37