Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Звук, графика и видео > GDI+ Глюк или особенность???


Автор: ivan219 28.7.2007, 20:19
Этот код не работает так как надо:
Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,GDIPAPI,GDIPOBJ, StdCtrls, ExtCtrls, ComCtrls, Math;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    Button1: TButton;
    procedure P(Pos, Max, Rmax, Rmin: Integer);
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  GraphicsGDIPlus : TGPGraphics;
  Pen: TGPPen;
  SolidBrush: TGPSolidBrush;
  I, I1: Integer;

implementation

{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
 DoubleBuffered:=True;
end;


procedure TForm1.P(Pos, Max, Rmax, Rmin: Integer);
var
  F, X, Y: Extended;
begin
 if Pos>Max then Exit;
 F:=2 * Pi * Pos / Max;
 SinCos(F, X, Y);
 GraphicsGDIPlus.DrawLine(Pen,  Rmax + X * Rmin,
                                Rmax + Y * Rmin,
                                Rmax + X * Rmax,
                                Rmax + Y * Rmax);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
 Repaint;
 GraphicsGDIPlus.FillEllipse(SolidBrush,95,95,10,10);
 for I:=0 to 100 do
  begin
   P(I,10,100,85);
   P(I,20,100,90);
   P(I,100,100,95);
  end;
 P(I1,100,100,0);
 Inc(I1, 1);
 if I1>100 then I1:=10;
 Caption:=IntToStr(I1);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 GraphicsGDIPlus:=TGPGraphics.Create(Canvas.Handle);
 GraphicsGDIPlus.SetSmoothingMode(SmoothingModeHighQuality);
 Pen:=TGPPen.Create(MakeColor(255, 0, 0, 0), 2);
 SolidBrush:=TGPSolidBrush.Create(MakeColor(255, 0, 0, 0));
 Timer1.Enabled:=True;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 Pen.Free;
 SolidBrush.Free;
 GraphicsGDIPlus.Free;
end;
end.


А вот так работае:
Код

procedure TForm1.Timer1Timer(Sender: TObject);
begin
 Repaint;
 GraphicsGDIPlus:=TGPGraphics.Create(Canvas.Handle);
 GraphicsGDIPlus.SetSmoothingMode(SmoothingModeHighQuality);
 Pen:=TGPPen.Create(MakeColor(255, 0, 0, 0), 2);
 SolidBrush:=TGPSolidBrush.Create(MakeColor(255, 0, 0, 0));
 GraphicsGDIPlus.FillEllipse(SolidBrush,95,95,10,10);
 for I:=0 to 100 do
  begin
   P(I,10,100,85);
   P(I,20,100,90);
   P(I,100,100,95);
  end;
 P(I1,100,100,0);
 Inc(I1, 1);
 if I1>100 then I1:=10;
 Pen.Free;
 SolidBrush.Free;
 GraphicsGDIPlus.Free;
 Caption:=IntToStr(I1);
end;

Вопрос: почему когда: 
Код

 GraphicsGDIPlus:=TGPGraphics.Create(Canvas.Handle);
 GraphicsGDIPlus.SetSmoothingMode(SmoothingModeHighQuality);
 Pen:=TGPPen.Create(MakeColor(255, 0, 0, 0), 2);
 SolidBrush:=TGPSolidBrush.Create(MakeColor(255, 0, 0, 0));


 Pen.Free;
 SolidBrush.Free;
 GraphicsGDIPlus.Free;

выносиш за пределы одной процедуры то ничего не рисует???
И как от этого избавится???

Автор: s-mike 29.7.2007, 19:25
Я бы сказал, что это элементарное незнание принципов работы VCL. Рисовать нужно в событии OnPaint.

Автор: ivan219 29.7.2007, 21:43
s-mike, Вобщето я это знаю вопрос в другом.

Автор: s-mike 29.7.2007, 21:46
Цитата(ivan219 @  29.7.2007,  21:43 Найти цитируемый пост)
Вобщето я это знаю вопрос в другом. 

Судя по коду - нет. Иначе зачем рисовать в Button.OnClick, Timer.OnTimer? Если известно, что это _в корне_ неправильно.

Собственно проблемы все из-за как раз из-за этого.

Весь код отрисовки следует переместить в Form.OnPaint, а в событии кнопки или таймера следует поместить только команду перерисовки — Invalidate.

Автор: ivan219 29.7.2007, 22:53
Ну хорошо вот так будет правильно?
Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls,GDIPAPI,GDIPOBJ;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormPaint(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  GraphicsGDIPlus : TGPGraphics;
  Pen: TGPPen;

implementation

{$R *.dfm}

procedure TForm1.FormShow(Sender: TObject);
begin
 GraphicsGDIPlus:=TGPGraphics.Create(Canvas.Handle);
 GraphicsGDIPlus.SetSmoothingMode(SmoothingModeHighQuality);
 Pen:=TGPPen.Create(MakeColor(255, 0, 0, 0), 2);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 Invalidate;
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
  GraphicsGDIPlus.DrawLine(Pen,0,0,100,100);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 Pen.Free;
 GraphicsGDIPlus.Free;
end;
end.

Только проблема осталось.
Зато если сделать так:
Код

procedure TForm1.FormPaint(Sender: TObject);
begin
 GraphicsGDIPlus:=TGPGraphics.Create(Canvas.Handle);
 GraphicsGDIPlus.SetSmoothingMode(SmoothingModeHighQuality);
 Pen:=TGPPen.Create(MakeColor(255, 0, 0, 0), 2);
 GraphicsGDIPlus.DrawLine(Pen,0,0,100,100);
 Pen.Free;
 GraphicsGDIPlus.Free;
end;

или так
Код

procedure TForm1.Button1Click(Sender: TObject);
begin
 A;
 B;
 C;
end;

procedure TForm1.A;
begin
 GraphicsGDIPlus:=TGPGraphics.Create(Canvas.Handle);
 GraphicsGDIPlus.SetSmoothingMode(SmoothingModeHighQuality);
 Pen:=TGPPen.Create(MakeColor(255, 0, 0, 0), 2);
end;

procedure TForm1.B;
begin
 GraphicsGDIPlus.DrawLine(Pen,0,0,100,100);
end;

procedure TForm1.C;
begin
 Pen.Free;
 GraphicsGDIPlus.Free;
end;

То всё отрисовывается, вот я и задал вопрос почему нужно создавать обекты GraphicsGDIPlus Pen их отрисовывать и уничтожать в одной процедуре т.е. последовательно, так как ели сделать так:
Код

procedure TForm1.Button1Click(Sender: TObject);
begin
 GraphicsGDIPlus:=TGPGraphics.Create(Canvas.Handle);
 GraphicsGDIPlus.SetSmoothingMode(SmoothingModeHighQuality);
 Pen:=TGPPen.Create(MakeColor(255, 0, 0, 0), 2);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 GraphicsGDIPlus.DrawLine(Pen,0,0,100,100);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
 Pen.Free;
 GraphicsGDIPlus.Free;
end;

И нажать по очереди Button1..3 то тоже ничего неотрисовывается.

Автор: Alexeis 30.7.2007, 08:35
ivan219, насколько я знаю графические дескрипторы GDI даются во время прорисовки и существуют недолго, потому если их получить в разное время, то потом они могут оказаться недействительными.

Автор: s-mike 30.7.2007, 08:46
Конечно не правильно. Объект Graphics должен создаваться при каждой перерисовке.
Цитата(ivan219 @  29.7.2007,  22:53 Найти цитируемый пост)
То всё отрисовывается

Повезло, не более smile Повезло, что дескриптор не был изменен.

Правильно будет так:
Код

procedure TForm.FormPaint;
var
  G: TGPGraphics;
begin
  G := TGPGraphics.Create(Canvas.Handle);
  try
    // здесь код отрисовки
  finally
    G.Free;
  end;
end;

Автор: ivan219 30.7.2007, 16:39
Печально smile
Значит надо всегда создавать и уничтожать ведь это лишнии затраты ресурсов.
Это особенность Windows или что???

Автор: Alexeis 30.7.2007, 17:12
ivan219, не такие уж и затраты. Объект типа TGPGraphics - этого своего рода DC для GDI+. В GDI его же получают и пересоздают при каждой перерисовке и ничего.

Автор: s-mike 30.7.2007, 17:34
Объект TGPGraphics.Create/Free — это по сути обертки над двумя противоположными функциями. Так что ничего ресурсоемкого в этом нет.

Сейчас нет под рукой GDI+, но принцип там таков: передавая в определенную функцию DC окна мы получаем дескриптор GDI+, на котором можно рисовать. То есть процесс абсолютно аналогичный получению DC.

Может быть более правильным было бы в объекте сделать возможность изменять Handle для рисования не пересоздавая объект (как Canvas.Handle). Ведь все-таки при создании объекта выделяется память, и хорошо если при каждом новом создании объекта используется выделенная перед этим область памяти. Но текущая реализация GDI+ от progdigy этого не предусматривает.

Автор: ivan219 30.7.2007, 18:26
Спасибо разяснили.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)