Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 445
  • Last Modified:

Why does Delphi delete the painted content of a panel?

I create a tPanel in a form of a Delphi application. Through a dll an external program is filling the panel with data (drawing a picture).
So far so good. The data is visible.

But only if I didn't 'touch' the panel before. If I set the panel visible or changed the top, left, width, ... values then the panel is filled with the data of the external program - but directly after that the data will be 'deleted?'. And the look of the panel is the same again as it was before the data were transferred.

Where could be the problem? Why does Delphi allow to draw a picture on the panel in the first case but in the second case it overwrote all again?
0
Treppenmeister
Asked:
Treppenmeister
3 Solutions
 
Wim ten BrinkSelf-employed developerCommented:
Simple. You don't store whatever is painted on it. Thus, whenever there's a need to REPAINT the control, it doesn't know about what you have painted over it and thus it gets wiped away.
Normally, controls will respond on a special Paint message, and paint their contents. Thus, when it needs to be repainted, the code will just repaint it. Some controls will just follow a list of instructions to do the actual repaint while others will just store the original contents in a bitmap and just draw the bitmap in the right place again.

In your case, you will have to make sure that you can capture the Paint message from this panel and then paint on it. The easiest solution would be to drop a TImage on the panel (align to client) and draw on this TImage component, since it contains a bitmap internally that can store all changes and thus redraw it. Or try to hook into the Paint message of the panel...
0
 
TreppenmeisterAuthor Commented:
Our first choice of component was a drawbox. But the external program writes via OpenGL into the component. The programmer (an external one) of that program means, that they cannot write into an image or drawbox - only the panel let them write the data directly from the graphiccard. I don't know whether that is true - but since I have no clue of OpenGL I have to believe him.

Btw How can I capture the paint message of the panel?
0
 
mokuleCommented:
Hi,
Maybe consider the creation of control descedant from TCustomControl.
It will be possible to draw on it by OpenGL.
Something like this.

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TOGControl = class(TCustomControl)
  private
    procedure Paint; override;
  end;

var
  Form1: TForm1;
  OGControl1: TOGControl;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  OGControl1 := TOGControl.Create(self);
  OGControl1.Parent := Form1;
  OGControl1.SetBounds(20,20,220,220);
end;

{ TOGControl }

procedure TOGControl.Paint;
begin
// In Your case OpenGL should draw here, it's only for simplicity
  Canvas.Brush.Color := clRed;
  Canvas.Rectangle(0,0,Width,Height);
end;

end.
0
 
Wim ten BrinkSelf-employed developerCommented:
Mokule is right. You'd have to make your own custom panel component to allow the panel to repaint itself. The code where he's drawing a rectangle should be replaced by the code that tells the OpenGL component to redraw itself again. Mokule did forget to call the inherited paint method though. (You're overriding it!) If you call the inherited paint method first, it will also draw the border and the gray stuff in the panel before your openGL thing fills it.

But it is weird that an external DLL can only paint on a panel while basically, it should be able to paint on anything that has a windows handle. (Or actually, the canvas handle of the component that you want to draw it on.) So technically, you should be able to just use a TPaintbox and pass the canvas handle of it to the external DLL so it can draw in it whenever you need it to draw something...
0
 
Slick812Commented:
hello Treppenmeister ,  I think you would need to Record the Image that the openGL has drawn on the panel to a Bitmap, so you can draw this bitmap on the panel when the Panel's Paint message is processed. Here is some code I would use if I wanted to have a persistent Image on a TPanel. There is the Window Proc for the Panel1, and single button click in  procedure TForm1.but_DrawPanelClick , I create the PanelBmp in the Form's OnCreate method -






type
  TForm1 = class(TForm)
    Panel1: TPanel;
    but_DrawPanel: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure but_DrawPanelClick(Sender: TObject);
  private
    { Private declarations }
    PanelBmp: TBitmap;
    OrgWinProc : TWndMethod;
    procedure PanelProc(var Message: TMessage);




procedure TForm1.FormCreate(Sender: TObject);
begin
PanelBmp := TBitmap.Create;
PanelBmp.Canvas.Brush.Color := clRed {Panel1.Color};
  // set PanelBmp to same size as Panel1
PanelBmp.Width := Panel1.Width;
PanelBmp.Height := Panel1.Height;

OrgWinProc := Panel1.WindowProc;
// get and set the Panel1 WindowProc
Panel1.WindowProc := PanelProc;
end;


procedure TForm1.FormDestroy(Sender: TObject);
begin
FreeAndNil(PanelBmp);
end;


procedure TForm1.PanelProc(var Message: TMessage);
var
PaintS: TPaintStruct;
begin
case message.Msg of
 WM_PAINT:
   begin
   BeginPaint(Panel1.Handle, PaintS);
   BitBlt(PaintS.hdc, PaintS.rcPaint.Left, PaintS.rcPaint.Top,
           PaintS.rcPaint.Right, PaintS.rcPaint.Bottom, PanelBmp.Canvas.Handle,
           PaintS.rcPaint.Left, PaintS.rcPaint.Top, SRCCOPY);
   EndPaint(Panel1.Handle,PaintS);
   message.Result := 0;
   Exit;
   end;

 WM_SIZE:
   begin
   PanelBmp.Width := LOWORD(message.lParam);
   PanelBmp.Height := HIWORD(message.lParam);
   end;
 end;

OrgWinProc(Message);
end;


procedure TForm1.but_DrawPanelClick(Sender: TObject);
var
PanDC: HDC;
begin
{this is a button click event, that draws on the Panel1, and then Records
 the new Image of Panel1 to the PanelBmp}

PanDC := GetDC(Panel1.Handle);
Ellipse(PanDC, 5,5, 65,45);
Rectangle(PanDC,10,55,63,88);
ReleaseDC(Panel1.Handle, PanDC);
{the code above will draw on the Panel, you would leave this out and then
place the function that draws with the openGL, , above here instead of that}

{whenever anything is drawn on the panel, you will need to call the
 code below to copy the panel drawing onto the PanelBmp, so it can record
 the drawing and repaint it later}

PanDC := GetDC(Panel1.Handle);
BitBlt(PanelBmp.Canvas.Handle, 0, 0, PanelBmp.Width, PanelBmp.Height, PanDC,
           0, 0, SRCCOPY);
ReleaseDC(Panel1.Handle, PanDC);
end;

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
this is the way I would do it,
ask questions if you need more info
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Tackle projects and never again get stuck behind a technical roadblock.
Join Now