onPaint Canvas Parameter

Forum für alles rund um die MSEide und MSEgui
Antworten
Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1432
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

onPaint Canvas Parameter

Beitrag von fliegermichl »

Ich komme schon ganz gut voran. Meine Hauptunit cadtypes.pas mit fast 60000 Zeilen compiliert schon in der mseide.
Jetzt stecke ich beim zeichnen fest.

Der Event TPaintbox.onPaint verlangt einen Parameter Canvas. Die Paintbox hat aber gar keinen Canvas.

Da habe ich wohl noch ein grundsätzliches Verständnisproblem.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: onPaint Canvas Parameter

Beitrag von mse »

Die MSEgui Haupt-Zeichenfunktion ist

Code: Alles auswählen

 
 twidget = class(tactcomponent,iscrollframe,iface,iassistiveclient)
[...]
   procedure paint(const canvas: tcanvas); virtual;
 

Normalerweise wird twidget.paint() für das top-level-widget von twindow.internalupdate() aufgerufen. twindow.internalupdate() stellt ein canvas-Objekt zur Verfügung.

Code: Alles auswählen

 
function twindow.internalupdate: boolean; //false if nothing is painted
var
 bo1: boolean;
 bmp: tbitmap;
 rect1: rectty;
 po1: pointty;
 reg1: regionty;
begin
 result:= false;
 if (ws_visible in fownerwidget.fwidgetstate) and (fupdateregion.region <> 0) then begin
  checkwindow(false); //ev. reposition window
  fcanvas.reset;
  fcanvas.clipregion:= fupdateregion.region; //canvas owns the region
  {
  bo1:= appinst.caret.islinkedto(fcanvas) and
   testintersectrect(fcanvas.clipbox,appinst.caret.rootcliprect);
  }

  bo1:= false;
  if appinst.caret.islinkedto(fcanvas) and appinst.fcaret.active and
      testintersectrect(fcanvas.clipbox,appinst.caret.rootcliprect) then begin
   reg1:= fcanvas.copyclipregion;
   fcanvas.regintersectrect(reg1,appinst.caret.rootcliprect);
   bo1:= not fcanvas.regionisempty(reg1);
   fcanvas.destroyregion(reg1);
   if bo1 then begin
    tcaret1(appinst.fcaret).remove;
   end;
  end;
  include(fstate,tws_painting);
  if flushgdi then begin
   try
    fupdateregion.region:= 0;
    result:= true;
    fownerwidget.paint(fcanvas);
   finally
    if bo1 then begin
     tcaret1(appinst.fcaret).restore;
    end;
    fcanvas.endpaint;
   end;
  end
  else begin
   bmp:= tbitmap.create(bmk_rgb,fgdi);
   try
    if intersectrect(fcanvas.clipbox,
            makerect(nullpoint,fownerwidget.widgetrect.size),rect1) then begin
     bmp.size:= rect1.size;
     bmp.canvas.clipregion:= bmp.canvas.createregion(fupdateregion.region);
     po1.x:= -rect1.x;
     po1.y:= -rect1.y;
     tcanvas1(bmp.canvas).setcliporigin(po1);
     bmp.canvas.origin:= nullpoint;
     fupdateregion.region:= 0;
     result:= true;
     fownerwidget.paint(bmp.canvas);
     bmp.paint(fcanvas,rect1);
    end
    else begin
     fupdateregion.region:= 0;
    end;
   finally
    bmp.Free;
    if bo1 then begin
     tcaret1(appinst.fcaret).restore;
    end;
   end;
  end;
  exclude(fstate,tws_painting);
 end;
 

twidget.paint() ruft die paint() Prozeduren der Kinder unter Weitergabe des canvas Parameters auf:

Code: Alles auswählen

 
procedure twidget.paint(const canvas: tcanvas);
[...]
 if (widgetcount > 0) then begin
  if (fframe <> nil) and not (ow_nochildpaintclip in foptionswidget) then begin
   fframe.checkstate;
   canvas.intersectcliprect(fframe.fpaintrect);
  end;
  rect1:= canvas.clipbox;
  for int1:= 0 to widgetcount-1 do begin
   widget1:= twidget(fwidgets[int1]);
   with widget1 do begin
    if isvisible and testintersectrect(rect1,fwidgetrect) then begin
     saveindex:= canvas.save;
     if not (ow_nochildclipsiblings in self.foptionswidget) then begin
      for int2:= int1 + 1 to self.widgetcount - 1 do begin
       with self.fwidgets[int2],tcanvas1(canvas) do begin
        if visible and testintersectrect(widget1.fwidgetrect,fwidgetrect) then begin
             //clip higher level siblings
         if (ws_opaque in fwidgetstate) then begin
          subcliprect(fwidgetrect);
         end
         else begin
          reg1:= msegui.createregion(self.window.fgdi);
          addopaquechildren(reg1);
          subclipregion(reg1.region);
          msegui.destroyregion(reg1);
         end;
        end;
       end;
      end;
     end;
     if not canvas.clipregionisempty then begin
      canvas.move(fwidgetrect.pos);
      paint(canvas);
     end;
     canvas.restore(saveindex);
    end;
   end;
  end;
 end;
[...]
 

Um ein Neuzeichnen der tpaintbox auszulösen, rufe "tpaintbox.invalidate()" auf, MSEgui kümmert sich dann um den Rest.
Soll ein twidget in eine bitmap gezeichnet werden, kann

Code: Alles auswählen

 
 <twidget>.paint(<tbitmap>.canvas);
 

verwendet werden. Die Printer Komponenten besitzen ebenfalls eine canvas Property.
Falls ein tcanvas Objekt ausserhalb der paint()-Prozedur benötigt wird, z.B. zur Berechnung von Textabmessungen, gibt es "twidget.getcanvas()". "twidget.getcanvas()" sollte nicht zum Zeichnen verwendet werden.

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1432
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: onPaint Canvas Parameter

Beitrag von fliegermichl »

Danke, ich brauchte es nur um die Paintbox neu zeichnen zu lassen, wenn eine CAD Komponente verändert wurde.
Also reicht ja dann das Paintbox.invalidate;

Antworten