Delphi-PRAXiS
Seite 3 von 4     123 4      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Benötige Hilfe beim Entwickeln einer Komponente (https://www.delphipraxis.net/98560-benoetige-hilfe-beim-entwickeln-einer-komponente.html)

Alter Mann 6. Sep 2007 15:53

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Hi torud,

zum zentrierten Text:

Nehme für 'TLayout' TTextLayout aus der Unit StdCtrls, einfach in den Uses-Abschnitt aufnehmen.

Dann fügst Du diesen Teil von oki's code ein:
Zitat:

case TextAlign of
taCenter : myAlignment := DT_CENTER;
taLeftJustify : myAlignment := DT_LEFT;
taRightJustify : myAlignment := DT_RIGHT;
end;

IF FWordWrap then myAlignment := myAlignment or DT_WORDBREAK;
Dann lesen wir in der Hilfe nach was da zu den Flags von DrawText steht -> DT_CALCRECT
und nutzen es auch gleich um uns über OffsetRect schlau zu machen.

Nach der Lektüre ergänzen wir den Code um folgende Passage:
Delphi-Quellcode:
    if FLayout <> tlTop then
    begin
      CalcRect := TextRect;
      DrawText(Canvas.Handle, PChar(FText), -1, CalcRect, myAlignment or DT_CALCRECT);
      if FLayout = tlBottom then OffsetRect(TextRect, 0, Height - CalcRect.Bottom)
                            else OffsetRect(TextRect, 0, (Height - CalcRect.Bottom) div 2);
    end;
    DrawText(Canvas.Handle, PChar(FText), -1, TextRect, myAlignment);
Was passiert:
Durch den Aufruf von 'DrawText(..., CalcRect, myAlignment or DT_CALCRECT)' wird die Weite und
Höhe des Textes berechnet und in CalcRect zurückgegeben.
Anschließend wird mit 'OffsetRect' das TextRect so verschoben, dass der Text entsprechend der
Layoutvorgabe mittels DrawText ausgegeben werden kann.

Das war es.

Gruß

torud 6. Sep 2007 16:48

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Vielen Dank für die Erklärungen und die Unterstützung.
Es funktioniert nun alles!

Wenn ich den Code fertig und sauber habe, kann ich ihn gern nochmals posten, für diejenigen, die ihn nutzen wollen.

oki 6. Sep 2007 17:08

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Hi torud,

wenn du 'ne saubere Lösung für die runden Ecken fertig hast, daran wäre ich interessiert. :stupid:
Gruß oki

torud 6. Sep 2007 17:46

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
:-D :-D sehe ich sehr undeutlich...
Nicht das ich nicht bereit wäre den Code herzuzeigen, aber ich sehe es mehr als undeutlich, dass ich den Code hinbekomme. Ich werde aber, da ich hier in der OpenSource-Sektion etwas in der Richtung gesehen habe, etwas in fremden Code schnüffeln, wie die das gelöst haben.

oki 6. Sep 2007 19:40

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Hi torud,

ein paar Tipps kann ich dir geben.

Als Member der Klasse und zwei Methoden:
Delphi-Quellcode:
  TMyControl = class(TCustomControl)
  private
    FullRgn, PointRgn : THandle;
......
  protected
    procedure DoInvisible;
    procedure DoVisible;
......
Mit Aufruf DoInvisible wird der überflüssige Tein unsichtbar, mit DoVisible alles sichtbar.

Delphi-Quellcode:
procedure TMyControl.DoVisible;
begin
  if FullRgn <> 0 then
    DeleteObject(FullRgn);
  FullRgn := CreateRectRgn(0, 0, Width, Height);
  CombineRgn(FullRgn, FullRgn, FullRgn, RGN_COPY);
  SetWindowRgn(Handle, FullRgn, TRUE);
end;
Das kann man so übernehmen.

Delphi-Quellcode:
procedure TMyControl.DoInvisible;
begin
  //gesamten Clientbereich erfassen
  if FullRgn <> 0 then
    DeleteObject(FullRgn);
  FullRgn := CreateRectRgn(0, 0, Width, Height);
  //'Mask' alles unsichtbar
  CombineRgn( FullRgn, FullRgn, FullRgn, RGN_DIFF );

  // alle sichtbaren Bereiche einblenden
  PointRgn := CreateRectRgn( X, Y, Width, Hight);  // das ist ein Bereich im Rect der eingeblendet wird
  CombineRgn( FullRgn, FullRgn, PointRgn, RGN_OR );
  DeleteObject(Pointrgn);

  // alles Kombiniert und fertig
  SetWindowRgn(Handle, FullRgn, TRUE);
end;
Das Teilstück von PointRgn bis DeleteObject kann beliebig wiederholt werden. Somit kann mann mehrere Clientbereiche auf den FullRgn kombinieren. Hier ist beispielhaft ein RectRgn verwendet. Das gibt es auch für Polygon usw. Einfach in die MS-Hilfe schauen.

Vergiß nicht im Destructor den Speicher wieder frei zu geben.
Delphi-Quellcode:
destructor TMyControl.Destroy;
begin
  try
    DeleteObject(FullRgn);
    DeleteObject(PointRgn);
  except end;
Ach so, wenn es ein fester Bereich ist, reicht es einmal DoInvisible (zum Bsp. im CreateWnd) aufzurufen. Dann sollte man das immer wieder tun, wenn sich die Größe ändert. Erst DoVisible und dann DoInvisible.

Gruß oki

Hansa 6. Sep 2007 20:12

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Zitat:

Zitat von oki
Hi torud,

wenn du 'ne saubere Lösung für die runden Ecken fertig hast, daran wäre ich interessiert. :stupid:
Gruß oki

Gehen die runden Ecken immer noch nicht ? :shock:

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
const
  bgcolor = $00FFDDEE;
  linecolor = $00554366;
var
  img: array of TImage;
  reg: hrgn;
  i: Integer;
begin
  for i := 0 to ComponentCount - 1 do
  begin
    if Components[i].ClassName = 'TPanel' then
    begin
      setlength(img, Length(img) + 1);
      img[i] := TImage.Create(Self);
      img[i].Width := (Components[i] as TPanel).Width;
      img[i].Height := (Components[i] as TPanel).Height;
      img[i].Parent := (Components[i] as TPanel);
      img[i].Canvas.Brush.Color := bgcolor;
      img[i].Canvas.pen.Color := bgcolor;
      img[i].Canvas.Rectangle(0,0,img[i].Width, img[i].Height);
      img[i].Canvas.pen.Color := linecolor;
      img[i].Canvas.RoundRect(0,0,img[i].Width - 1,img[i].Height - 1,20,20);
      reg := CreateRoundRectRgn(0,0,(Components[i] as TPanel).Width,
        (Components[i] as TPanel).Height, 20,20);
      setwindowrgn((Components[i] as TPanel).Handle, reg, True);
      deleteobject(reg);
    end;
  end;
end;
(c) by Schweizer :mrgreen:

oki 6. Sep 2007 20:34

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Hi Hansa,

auf deutsch, beim creieren der Form alle vorhandenen Panels die Ecken abrunden.
Dann muss das aber auch ins OnResize!?

Gruß oki

Hansa 6. Sep 2007 22:51

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Zitat:

Zitat von oki
Dann muss das aber auch ins OnResize!?

Erstens : probieren geht über studieren. :mrgreen: Create scheint mir allerdings auch nicht sehr geeignet. Es gibt aber auch noch OnShow, OnActivate usw. 8)

Christian Seehase 6. Sep 2007 23:21

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Moin Zusammen,

nicht zu vergessen:

OnPaint

denn dann wird das Formular gezeichnet...

Hansa 6. Sep 2007 23:41

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Die Reihenfolge ist folgendermaßen :

Delphi-Quellcode:
OnCreate

OnShow

OnActivate

OnPaint

oki 7. Sep 2007 06:10

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Moin,

also wenn schon im OnPaint, dann sind imho die anderen Stellen überflüssig. Wenn sich aber das "ParentWindow" der Panels mittels Überzeichnen um die runden Ecken der Panels kümmert (und nicht die Panels selber), ist es einfach nur entscheidend, was sich im Fenster ändern kann. Ist kein Splitter oder ähnliches im Fenster und somit eine andere Positionnierung der Panels nur bei Größenänderung möglich, so würde ich es ins OnCreate (oder OnShow) und OnResize legen.

Mein Vorschlag:

OnCreate

OnResize

oder ausschließlich

OnPaint

Da torud aber an einer neuen Komponente bastelt frage ich mich, was daran schlecht ist, der Kompo selber runde ecken mit Transparenz außerhalb dieser zu verpassen. Hätte halt den Vorteil, dass sich die Kompos selbst um ihr Aussehen kümmern und man das nicht von oben im Form machen muß.

Gruß oki

[edit] Viele Edits, ist für korrekte Rechtschreibung noch zu früh :oops: [/edit oki]

torud 7. Sep 2007 07:09

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Liste der Anhänge anzeigen (Anzahl: 1)
Erstmal vielen Dank für den Code. Ich habe es mir angesehen und getestet, aber nicht wirklich für gut befunden. Ich habe in die Procedure noch eine Variable für Rundung der Ecken eingefügt, um besser damit spielen zu können und diese Einstellung schneller ändern zu können.

Leider gibt es auch hier das Problem der Kantenglättung, für das scheinbar noch keiner eine Lösung gefunden hat, denn wenn man eine grössere abgerundete Ecke vorgibt, sieht es nicht wirklich schön aus.

Desweiteren habe ich ja in meiner Komponente die Möglichkeit ein Bild zu laden, einen Gradienten zu zeichnen oder einen Text anzeigen zu lassen. Ich habe es nicht hinbekommen, den Canvas transparent zeichnen zu lassen. Ich dachte, dass es damit gehen könnte:

Delphi-Quellcode:
img[i].Canvas.Brush.Style := bsClear;
img[i].Canvas.Brush.Color := clNone;
Dem war aber nicht so. Also wenn ich das so in meinen Code übernehme, müsste es zum einen transparent sein und zum anderen müsste eine Kantenglättung durchgeführt werden. Hierzu habe ich einen Thread bei der Konkurrenz gefunden.

http://www.delphi-forum.de/viewtopic...751&highlight=

Dort gibt es zum einen die Möglichkeit eine Line zu glätten, oder aber auch eine Ellipse. Vielleicht könnte man das noch etwas verfeinern...!? Aber der Thread scheint dort auch tot zu sein...

Auf jeden Fall danke ich Euch sehr für Eure Ideen und Mitwirkung!
Im Anhang mal ein Bild mit den bisherigen Möglichkeiten.

torud 7. Sep 2007 09:08

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Ich habe mal einfacherweise versucht folgenden Code in die Komponente zu implemtieren, da es mir als passend erschien, um die runden Ecken zu realisieren. Aber soo einfach solls wohl doch nicht sein :) , denn leider werden die runden Ecken zum einen nicht realisiert und zum anderen hat die Komponente natürlich dann Probleme beim zeichnen des Borders.

Delphi-Quellcode:
private
    FCornerUse:boolean;
    FCornerWidth:integer;
published
    property CornerUse : boolean read FCornerUse  write FCornerUse;
    property CornerWidth : integer read FCornerWidth  write FCornerWidth;

procedure TmyPanel.Paint;
var
  reg: hrgn;
begin
  .....
    if CornerUse and (CornerWidth > 0) then
      begin
        reg := CreateRoundRectRgn(0,0,self.Width,
          self.Height, CornerWidth,CornerWidth);
        setwindowrgn(self.Handle, reg, True);
        deleteobject(reg);
      end;
  .....
Ich habe es mir deswegen soo einfach gemacht, weil dieser Code bei dem Beispiel mit dem Panel aich ohne Image funktioniert hatte. Vielleicht muss man ja doch den Umweg mit dem Image in Kauf nehmen oder es so angehen, wie von OKI angedacht!? Ich spiele noch ein wenig mit dem Code rum.

BTW. Schatten um die Komponente waäre auch "cool"...

torud 7. Sep 2007 10:58

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
So, die Version mit dem Panel-BeispielCode lief also gar nicht! Wahrscheinlich lags daran, dass es ein TCustomControl ist...

Nun habe ich OKI´s Code mal implementiert und sehe zumindest transparenzen...Allerdings keine runden Ecken. Ich habe den Code so wie er war eingebunden und völlig sorgenfrei in OnPaint einfach aufgerufen...(war vielleicht etwas blauäugig :shock: )

DoVisible habe ich nicht angerührt, aber in DoInvisible habe ich folgendes versucht...
Delphi-Quellcode:
procedure TmyPanel.DoInvisible;
begin
  //gesamten Clientbereich erfassen
  if FullRgn <> 0 then
    DeleteObject(FullRgn);
  FullRgn := CreateRectRgn(0, 0, Width, Height);
  //'Mask' alles unsichtbar
  CombineRgn( FullRgn, FullRgn, FullRgn, RGN_DIFF );

  // alle sichtbaren Bereiche einblenden
  PointRgn := CreateRectRgn( CornerWidth, CornerWidth, Width, Height);  // aus 0 wurde CornerWidth
  CombineRgn( FullRgn, FullRgn, PointRgn, RGN_OR );
  DeleteObject(Pointrgn);

  // alles Kombiniert und fertig
  SetWindowRgn(Handle, FullRgn, TRUE);
end;
Also ich glaube, dass ich es nicht einfach beides im OnPaint aufrufen sollte, da es selbst schon zur DesignTime einiges an Ressourcen zu fressen scheint... => naja und so wie ich es jetzt versucht habe, funzt es auch noch nicht...ich bleibe am Ball...

oki 7. Sep 2007 12:09

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Hi, also ich denke immer noch, dass Doinvisible ab besten im createWnd und in den Ereignissen für Rezise aufgehoben ist. Zu den runden Ecken; das ist sicher etwas anspruchsvoller da den "rahmenden" Bereich zu finden.

aber deshalb bin ich ja auch an dem Code interessiert. :wink:

Gruß oki

Alter Mann 7. Sep 2007 14:46

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Hi,

reicht das hier:
Delphi-Quellcode:
procedure TmyPanel.Paint;
var
  R     : TRect;
  Region : hRgn;
begin
  R := GetClientRect;
  with Canvas do
  begin
    Pen.Color := FBorderColor;
    Region := CreateRoundRectRgn(0, 0, R.Right, R.Bottom, 20, 20);
    FrameRgn(Canvas.Handle, Region, Canvas.Pen.Handle, R.Right, R.Bottom);
    SetWindowRgn(Handle, Region, True);
    DeleteObject(Region);

    Region := CreateRoundRectRgn(FBorderWidth, FBorderWidth, R.Right - FBorderWidth, R.Bottom - FBorderWidth, 20, 20);
    FillRgn(Canvas.Handle, Region, Canvas.Brush.Handle);
    SetWindowRgn(Handle, Region, True);
    DeleteObject(Region);
  end;
end;
Gruß

oki 7. Sep 2007 15:08

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Joop,

CreateRoundRectRgn müßte es bringen. Kannst du mal einen ScreenShot liefern wie es damit aussieht?

Gruß oki

Alter Mann 7. Sep 2007 15:34

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hier das Bild

oki 7. Sep 2007 15:45

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Liste der Anhänge anzeigen (Anzahl: 1)
Jo,

ich denk mal, damit kann man doch für's erste leben.
Also wenn Tom das nicht reicht, dann weis ich auch nicht.

[OT] Bei mir ist es etwas komplizierter. Meine Verbinder sind in allen Bereichen zur Laufzeit änderbar. Alles neben den Linien ist transparent und durchklickbar. (Bild im Anhang) [/OT]

Gruß oki

torud 7. Sep 2007 18:39

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Hätte mich gewundert, wenn ich es hinbekommen hätte. :shock:

In meinem ersten Versuch waren die Ecken abgerundet, aber der normale Border war auch noch da. Alles was ich danach geändert habe hatte nur noch zum Erfolg, dass jetzt gar nichts mehr zu sehen ist, wenn ich mein Beispielprojekt öffne.

Mein Code im OnPaint sieht nun so aus. Da ich morgen nach Österreich muss, kann ich noch etwas im stillen Kämmerlein probieren, bevor ich mir den Strick nehme. Dabei das es schon soo gut aus auf dem Bild vom "Jungen Freund"...

Delphi-Quellcode:
procedure TmyPanel.Paint;
var
  myRect,TextRect,CalcRect,R : TRect;
  myBorderWidth,myBorderWidthRightBottom:Integer;
  myAlignment : Cardinal;
  Region: hrgn;
begin
    if CornerUse and (CornerWidth > 0) then
      begin
        R := GetClientRect;
        with Canvas do
        begin
          Pen.Color := FBorderColor;
          Region := CreateRoundRectRgn(0, 0, R.Right, R.Bottom, 20, 20);
          FrameRgn(Canvas.Handle, Region, Canvas.Pen.Handle, R.Right, R.Bottom);
          SetWindowRgn(Handle, Region, True);
          DeleteObject(Region);

          Region := CreateRoundRectRgn(FBorderWidth, FBorderWidth, R.Right - FBorderWidth, R.Bottom - FBorderWidth, 20, 20);
          FillRgn(Canvas.Handle, Region, Canvas.Brush.Handle);
          SetWindowRgn(Handle, Region, True);
          DeleteObject(Region);
        end;
        DoVisible;
        DoInvisible;
      end;

  myRect := GetClientRect;
    Canvas.FillRect(myRect);
    Canvas.Brush.Style := bsSolid;
    Canvas.Brush.Color := FBgColorFrom;

    Canvas.Pen.Mode   := pmCopy;
    Canvas.Pen.Style  := BorderStyle;
    Canvas.Pen.Width  := BorderWidth;
    Canvas.Pen.Color  := BorderColor;
    self.Canvas.Font.Assign(Font);

    //zeichnen des gradients
    if PaintGradient then
      DrawGradient(Canvas, BgColorFrom, BgColorTo, myRect, GradientDirection);

    //zeichnen des bildes, wenn vorhanden
    if Picture <> nil then
      if PictureStretched then
        Canvas.StretchDraw(myRect,Picture.Graphic)
      else
        Canvas.Draw(0,0,Picture.Graphic);

    //berechnen und zeichnen des rahmens
    if BorderWidth > 0 then
      begin
        case BorderWidth of
          1    : begin
                   myBorderWidth := 0;
                   myBorderWidthRightBottom := 1;
                 end;
          else  begin
                   myBorderWidth := BorderWidth div 2;
                   myBorderWidthRightBottom := BorderWidth div 2;
                 end;
        end;

        Canvas.MoveTo(0 + myBorderWidth,0);
        Canvas.LineTo(myRect.Left + myBorderWidth,myRect.Bottom);

        Canvas.MoveTo(0,0 + myBorderWidth);
        Canvas.LineTo(myRect.Right,myRect.Top + myBorderWidth);

        Canvas.MoveTo(self.Width-myBorderWidthRightBottom,0);
        Canvas.LineTo(myRect.Right-myBorderWidthRightBottom,myRect.Bottom);

        Canvas.MoveTo(0,self.Height-myBorderWidthRightBottom);
        Canvas.LineTo(myRect.Right,myRect.Bottom-myBorderWidthRightBottom);
      end;

    //schreiben des textes
    TextRect := Rect(BorderWidth + TextMargin, BorderWidth + TextMargin, self.Width-BorderWidth - TextMargin, self.Height-BorderWidth - TextMargin);
    SetBkMode(Canvas.Handle, TRANSPARENT);

    //init
    myAlignment := 0;

    case TextAlign of
      taCenter      : myAlignment := DT_CENTER;
      taLeftJustify : myAlignment := DT_LEFT;
      taRightJustify : myAlignment := DT_RIGHT;
    end;

    IF FTextWordwrap then myAlignment := MyAlignment or DT_WORDBREAK
    else myAlignment := MyAlignment or DT_SINGLELINE;

    if FLayout <> tlTop then
        begin
          CalcRect := TextRect;
          DrawText(Canvas.Handle, PChar(FText), -1, CalcRect, myAlignment or DT_CALCRECT);
          if FLayout = tlBottom then OffsetRect(TextRect, 0, Height - CalcRect.Bottom)
                                else OffsetRect(TextRect, 0, (Height - CalcRect.Bottom) div 2);
        end;
        DrawText(Canvas.Handle, PChar(FText), -1, TextRect, myAlignment);
end;

Ich weiss, dass da noch ein wenig durcheinander ist und dass ich da durchaus Ordnung schaffen muss, aber ich hatte heute leider nur wenig zeit Zum Testen...Aber ich bring das auch bald in Ordnung...

Sunlight7 8. Sep 2007 01:59

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Delphi-Quellcode:
SetWindowRgn(Handle, Region, True);
DeleteObject(Region);
Das Region Handle nach einer Zuweisung mit MSDN-Library durchsuchenSetWindowRgn nicht mehr verwenden oder gar löschen :warn:

Im MSDN steht geschrieben:
After a successful call to SetWindowRgn, the operating system owns the region specified by the region handle hRgn. The operating system does not make a copy of the region. Thus, you should not make any further function calls with this region handle. In particular, do not close this region handle.

torud 8. Sep 2007 08:38

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Danke für die info. Gelöscht wird es ja, aber es wird komischerweise in dem Code nach dem Löschen noch einmal verwendet. Bei mir funzt es jedenfalss nicht. Warum auch immer.

oki 8. Sep 2007 13:01

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Um das noch mal in Erinnerung zu bringen, hier der Code den ich gepostet habe
Delphi-Quellcode:
procedure TMyControl.DoInvisible;
begin
  //gesamten Clientbereich erfassen
  if FullRgn <> 0 then
    DeleteObject(FullRgn);
  FullRgn := CreateRectRgn(0, 0, Width, Height);
  //'Mask' alles unsichtbar
  CombineRgn( FullRgn, FullRgn, FullRgn, RGN_DIFF );

  // alle sichtbaren Bereiche einblenden
  PointRgn := CreateRectRgn( X, Y, Width, Hight);  // das ist ein Bereich im Rect der eingeblendet wird
  CombineRgn( FullRgn, FullRgn, PointRgn, RGN_OR );
  DeleteObject(Pointrgn);

  // alles Kombiniert und fertig
  SetWindowRgn(Handle, FullRgn, TRUE);
end;
Hier wird nirgens der FullRgn nach SetWindowRgn angefaßt!

Das einzige, was gelöscht wird ist PointRgn. PointRgn wird aber nur für die Kombination der Sichtbaren Bereiche(PointRgn; heisst bei mir so, weil das Rect-Bereiche von Eckpunkten sind) auf den FullRange verwendet. Das dann in einer Schleife.

Ob in meinem ersten Bereich das DeleteObject auf FullRange jetzt korrekt ist, keine Ahnung, bin ich jetzt auch etwas unsicher. Dort wird auf jeden Fall erst mal das ganze Control/Form unsichtbar gemacht.

Im mittleren Abschnitt werden alle sichtbaren Bereiche auf FullRgn kombiniert und im letzten Abschnitt alles gesetzt.

Das was Tom macht ist den letzten Teil meines (auch hier dem Forum entlehnt) Codes herauszunehmen. Der Anfangs- und Mittelteil fehlt völlig und der Rest ist inkorrect!

Kein Wunder, dass nichts mehr geht.

Gruß oki

Sunlight7 8. Sep 2007 13:22

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Zitat:

Zitat von oki
Delphi-Quellcode:
procedure TMyControl.DoInvisible;
begin
  //gesamten Clientbereich erfassen
  if FullRgn <> 0 then
    DeleteObject(FullRgn);
  FullRgn := CreateRectRgn(0, 0, Width, Height);
  //'Mask' alles unsichtbar
  CombineRgn( FullRgn, FullRgn, FullRgn, RGN_DIFF );

  // alle sichtbaren Bereiche einblenden
  PointRgn := CreateRectRgn( X, Y, Width, Hight);  // das ist ein Bereich im Rect der eingeblendet wird
  CombineRgn( FullRgn, FullRgn, PointRgn, RGN_OR );
  DeleteObject(Pointrgn);

  // alles Kombiniert und fertig
  SetWindowRgn(Handle, FullRgn, TRUE);
end;

Ich weiß jetzt nicht, wo Du FullRgn deklariert hast, ich nehme mal an als Private, aber wenn Du DoInvisible mehr als 1 x aufrufst löscht Du das Region Handle nach SetWindowRgn...

Delphi-Quellcode:
// 1. Aufruf, FullRgn = 0 (vermutlich)
procedure TMyControl.DoInvisible;
begin
  //gesamten Clientbereich erfassen
  if FullRgn <> 0 then
    DeleteObject(FullRgn);
  ...
  // alles Kombiniert und fertig
  SetWindowRgn(Handle, FullRgn, TRUE);
end;
Delphi-Quellcode:
// 2. Aufruf, FullRgn <> 0, wurde mit SetWindowRgn gesetzt, wird aber gelöscht
procedure TMyControl.DoInvisible;
begin
  //gesamten Clientbereich erfassen
  if FullRgn <> 0 then
    DeleteObject(FullRgn);
   ...
  // alles Kombiniert und fertig
  SetWindowRgn(Handle, FullRgn, TRUE);
end;

Richtig wäre:
Delphi-Quellcode:
procedure TMyControl.DoInvisible;
   var FullRgn:HRgn;
begin
  FullRgn := CreateRectRgn(0, 0, Width, Height);
  //'Mask' alles unsichtbar
  CombineRgn( FullRgn, FullRgn, FullRgn, RGN_DIFF );

  // alle sichtbaren Bereiche einblenden
  PointRgn := CreateRectRgn( X, Y, Width, Hight);  // das ist ein Bereich im Rect der eingeblendet wird
  CombineRgn( FullRgn, FullRgn, PointRgn, RGN_OR );
  DeleteObject(Pointrgn);

  // alles Kombiniert und fertig
  SetWindowRgn(Handle, FullRgn, TRUE);
  // FullRgn nicht mehr antasten
end;

oki 8. Sep 2007 13:46

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Hi Sunlight7,

richtig, FullRgn ist privat deklariert.

Nun ist es aber doch so, dass bei einem CreateRectRgn ein handle erzeugt und somit Speicher reserviert wird. Wenn sich das Aussehen oder die Größe ändert, dann muß der Range ja neu gesetzt werden.
Rufe ich nun für FullRgn ein weiteres Mal CreateRectRgn auf, so wird imho doch ein neues Handle erzeugt und neuer Speicher reserviert. Damit würde ich dann doch ohne DeleteObject auf das alte Handle ein Speicherleck erzeugen. Oder nicht?

Gruß oki

Sunlight7 8. Sep 2007 13:56

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Hi Oki,

Nein wüdest Du nicht, da sich das OS bei einem Aufruf von SetWindowRgn das Handle und alles damit verbundene unter die Finger krallt und sich auch um die Entsorgung kümmert, wenn es nicht mehr gebraucht wird.

oki 8. Sep 2007 14:05

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Das heißt dann auch, dass das Handle für die PointRgn nicht mit DeleteObject frei gegeben werden muß?

Gruß oki

Sunlight7 8. Sep 2007 14:19

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Nein, denn das gilt nur für Region Handles, die mit Delphi-Referenz durchsuchenSetWindowRgn einem Fenster zugewiesen werden.

oki 8. Sep 2007 16:48

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Hi Sunlight7,

ich glaub dir das schon, aber ein komisches Gefühl hab ich dabei doch. Denn wenn ich für die Variable FullRgn die mein mit SetWindowRgn zugewiesenes Handle enthält eine neue Zuweisung mit CreateRectRgn tätige, wird das enthaltene Handle doch überschrieben. Oder wird das alte Handle bei der Zuweisung des neuen mit SetWindowRgn vom OS frei gegeben?

Gruß oki

Sunlight7 8. Sep 2007 17:08

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Also als Beispiel:

Delphi-Quellcode:
procedure TMyControl.Foo;
   var Rgn1, Rgn2:HRgn;
begin
  Rgn1:=CreateRectRgn(0, 0, Width, Hight);  
  SetWindowRgn(Handle, Rgn1, TRUE);
  // Jetzt hat das OS die Kontrolle über das Handle in Rgn1

  Rgn2:=CreateRectRgn(0, 0, Width, Hight);
  SetWindowRgn(Handle, Rgn2, TRUE);
  // Jetzt hat das OS die Kontrolle über das Handle in Rgn2 und Rgn1 wurde gelöscht

  SetWindowRgn(Handle, 0, TRUE);
  // Und nu is auch Rgn2 gelöscht
end;
Edit: Fehler ausgebessert :roll:

torud 8. Sep 2007 20:04

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Zitat:

Zitat von oki
Um das noch mal in Erinnerung zu bringen, hier der Code den ich gepostet habe
Das was Tom macht ist den letzten Teil meines (auch hier dem Forum entlehnt) Codes herauszunehmen. Der Anfangs- und Mittelteil fehlt völlig und der Rest ist inkorrect!

Kein Wunder, dass nichts mehr geht.
Gruß oki

Hallo Oki,

ich war eigentlich ziemlich froh, dass Du mir so derart unter die Arme gegriffen hast und mir so viel Code zur Verfügung gestellt und erklärt hast. Um so enttäuschter bin ich selbst von meiner eigenen Leistung. Was ich aber nicht ganz verstehen kann ist Deine Behauptung, dass ich irgendwelchen Code weglassen würde. Dies war nämlich nicht der Fall! Ich will hier nicht rumzicken, möchte aber durchaus unterstreichen, dass ich eigentlich immer recht sorgsam mit externem Code umgehe! So, dass dazu...

Ich bin sicher keine grosse Leuchte, aber ich bin durchaus versucht das zu verbessern und das Problem, auch wenns mir keiner mehr glaubt, zu lösen, denn ich will das Ergebnis auch mal sehen. Will sagen, nach weiteren Versuchen läuft es immer noch nicht. Ich habe zwischenzeitlich mal den angerundeten Border schimmern sehen - mehr nicht. Ich habe DoVisible mal im Create gehabt, mal im Paint am Anfang, aber es wird nicht wirklich was. Nun dachte ich mir, dass es vielleicht günstig wäre es im Create und OnResize zu haben!? Aber dazu müsste ich OnResize erstmal haben in der Komponente. Falls das Sinn macht, würde ich mich über ein Wink freuen. Ich weiss, dass ich manchmal nervig bin und nen dummen Eindruck hinterlasse, aber ich würde mich freuen nochmals eine Antwort zu erhalten.

Ich poste jetzt nicht den Ganzen Code, weil ich weiss, dass sich das eh keiner ansieht...

Ich finds nur komisch, dass der "Alte Mann" einen Code postet, der bei Dir "Oki" zu funktionieren scheint, bei mir aber wirkungslos bleibt.

Steht denn dieser Code im Zusammenhang mit den proceduren DoVisible und DoInvisible?
Du schriebst, du würdest DoInvisible im CreateWnd aufrufen? Was meinst Du damit? Es im OnCreate der Komponente selbst aufrufen? Das habe ich ja versucht...

Ich weiss nicht wirklich weiter...

oki 8. Sep 2007 20:21

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hi Tom,

erst mal sorry, wenn sich mein letzter Beitrag so abfällig angehört hat. Das war nicht meine Absicht :oops: !!!!

Ich erkläre es noch mal Stück für Stück so wie ich es verstanden habe (mache das nämlich auch erst seit kurzem).
Ich leg dir mal ein Beispielprojekt in den Anhang das ich selber mal gezogen hab.

DoVisible ist dafür, um alles wieder sichtbar zu machen.

Eigentlich interessiert nur DoInvisible. Glaub ich jedenfalls. Jetzt werd ich auch schon unsicher. :pale:

Ich hab noch mal nachgeschaut. DoVisible muß vor der Neuberechnung nicht aufgerufen werden.
Schau dir mal das Beispiel im Anhang an. Dann ist bestimmt einiges klarer.

Gruß oki

Sunlight7 8. Sep 2007 20:23

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Im Create Constructor macht es wenig Sinn, da das Fenster Handle noch nicht da is.
Es wäre zu empfehlen, die Methode Loaded zu überschreiben und es da zu machen, bzw., auch im Resize;

Edit: Rote Kästen wären Toll :roll:

Hab mal reingeguckt:

Delphi-Quellcode:
procedure TForm1.FormDestroy(Sender: TObject);
begin
  //Clean up the regions we created
  DeleteObject(ClientRgn);
  DeleteObject(FullRgn);
  DeleteObject(CtlRgn);
end;
DeleteObject(FullRgn) nicht löschen, auch net im Desctructor;

Noch eine Anmerkung, es macht einen Unterschied, ob Du auf einem FOrmular, oder in einer Komponente programmierst.
Zb ist FormCreate <> constructor Create...

oki 8. Sep 2007 20:44

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Hi sunlight,

zum Thema OnCreate habe ich mich schon weiter vorne geäußert und dort immer von CreateWnd gesprochen. Das Beispiel soll Tom nur zeigen wie es geht und ihm ein funzendes Bsp. in die Hand geben, mit dem er testen kann.

Nochmal, das Bsp. ist nicht von mir!!!

@Tom:

ungeprüfte Überarbeitung deiner Paint-Procedure. Ich habe nur die Thematik Ausblenden des äußeren Bereiches eingearbeitet. Ums Zeichnen hab ich mich nicht gekümmert!

Delphi-Quellcode:
procedure TmyPanel.Paint;
var
  myRect,TextRect,CalcRect,R : TRect;
  myBorderWidth,myBorderWidthRightBottom:Integer;
  myAlignment : Cardinal;
  Region: hrgn;
begin
  myRect := GetClientRect;
    Canvas.FillRect(myRect);
    Canvas.Brush.Style := bsSolid;
    Canvas.Brush.Color := FBgColorFrom;

    Canvas.Pen.Mode   := pmCopy;
    Canvas.Pen.Style  := BorderStyle;
    Canvas.Pen.Width  := BorderWidth;
    Canvas.Pen.Color  := BorderColor;
    self.Canvas.Font.Assign(Font);

    //zeichnen des gradients
    if PaintGradient then
      DrawGradient(Canvas, BgColorFrom, BgColorTo, myRect, GradientDirection);

    //zeichnen des bildes, wenn vorhanden
    if Picture <> nil then
      if PictureStretched then
        Canvas.StretchDraw(myRect,Picture.Graphic)
      else
        Canvas.Draw(0,0,Picture.Graphic);

    //berechnen und zeichnen des rahmens
    if BorderWidth > 0 then
      begin
        case BorderWidth of
          1    : begin
                   myBorderWidth := 0;
                   myBorderWidthRightBottom := 1;
                 end;
          else  begin
                   myBorderWidth := BorderWidth div 2;
                   myBorderWidthRightBottom := BorderWidth div 2;
                 end;
        end;

        Canvas.MoveTo(0 + myBorderWidth,0);
        Canvas.LineTo(myRect.Left + myBorderWidth,myRect.Bottom);

        Canvas.MoveTo(0,0 + myBorderWidth);
        Canvas.LineTo(myRect.Right,myRect.Top + myBorderWidth);

        Canvas.MoveTo(self.Width-myBorderWidthRightBottom,0);
        Canvas.LineTo(myRect.Right-myBorderWidthRightBottom,myRect.Bottom);

        Canvas.MoveTo(0,self.Height-myBorderWidthRightBottom);
        Canvas.LineTo(myRect.Right,myRect.Bottom-myBorderWidthRightBottom);
      end;

    //schreiben des textes
    TextRect := Rect(BorderWidth + TextMargin, BorderWidth + TextMargin, self.Width-BorderWidth - TextMargin, self.Height-BorderWidth - TextMargin);
    SetBkMode(Canvas.Handle, TRANSPARENT);

    //init
    myAlignment := 0;

    case TextAlign of
      taCenter      : myAlignment := DT_CENTER;
      taLeftJustify : myAlignment := DT_LEFT;
      taRightJustify : myAlignment := DT_RIGHT;
    end;

    IF FTextWordwrap then myAlignment := MyAlignment or DT_WORDBREAK
    else myAlignment := MyAlignment or DT_SINGLELINE;

    if FLayout <> tlTop then
        begin
          CalcRect := TextRect;
          DrawText(Canvas.Handle, PChar(FText), -1, CalcRect, myAlignment or DT_CALCRECT);
          if FLayout = tlBottom then OffsetRect(TextRect, 0, Height - CalcRect.Bottom)
                                else OffsetRect(TextRect, 0, (Height - CalcRect.Bottom) div 2);
        end;
        DrawText(Canvas.Handle, PChar(FText), -1, TextRect, myAlignment);

  // und jetzt machen wir den Rahmen unsichtbar
  if CornerUse and (CornerWidth > 0) then begin
    R := GetClientRect;
    FullRgn := CreateRectRgn(0, 0, Width, Height);
    CombineRgn( FullRgn, FullRgn, FullRgn, RGN_DIFF );

    // alle sichtbaren Bereiche einblenden
    Region := CreateRoundRectRgn(FBorderWidth, FBorderWidth, R.Right - FBorderWidth, R.Bottom - FBorderWidth, 20, 20);
    CombineRgn( FullRgn, FullRgn, Region, RGN_OR );
    DeleteObject(Region);

    // alles Kombiniert und fertig
    SetWindowRgn(Handle, FullRgn, TRUE);
  end else DoVisible;
end;
Gruß oki

torud 8. Sep 2007 21:53

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Servus Oki,

vielen Dank für Deinen Code. Erstens es läuft!!! Zweitens es fehlt der Rahmen. Kann ich den noch mit in die "if CornerUse and (CornerWidth > 0) then"-Bedingung mit einbauen? Die Antwort wird sicher sein ja, aber wie muss ich das anstellen? soll ich den Code dazu mit in die Bedingung einbringen und über den Canvas zeichnen lassen?

Sicher ja!?

Was mir noch aufgefallen ist, ist das der Radius der Ecken eigentlich immer gleich bleibt, es aber so aussieht, als würde das gesamte Control mit zunehmendem Radius sich verkleinern, so als o man einen Padding angibt, aber keinen Radius. Da scheint noch was nicht ganz korrekt zu sein. Ich spiel wieder etwas mit dem Code, danke Dir aber von Herzen!!!

//edit
Ich habe es mir nochmals angesehen. Ich denke, dass ich "oben" noch eine Bedingung um das Zeichnen des Borders legen sollte, da dieser bis jetzt immer gezeichnet wird, dies aber nicht wirklich nötig ist, wenn der Radius für die abgerundeten Ecken angegeben wurde. Der von mir angesprochene Padding ergibt sich auch aus der angegebenen BorderWidth. Der Radius selbst bleibt bisher starr...

oki 8. Sep 2007 23:01

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Hi Tom,

ja,

ja. :lol:

Wo du den Code für den Rahmen unter bringst ist eigentlich egal. In der "IF CornerUse" -Anweisung ist es wohl am passensten. Und ja, auf den Canvas zeichnen. Entweder durch eine Canvas- oder Win-API-Methode.

Noch mal Zum Verständnis. Du kannst zeichnen soviel du willst und was du willst. Zuerst ist alles unsichtbar, und jede Region die du mit RGN_OR kombinierst wird sichtbar. Bei dir ist das jetzt so, dass du eine Region als Rechteck mit abgerundeten Ecken in den von dir vorgegebenen Dimensionen creierst und durch die kombination mit deinem FullRgn sichtbar machst. Somit ist also alles innerhalb dieser Region sichtbar, und alles was du in diesen Bereich zeichnest auch.

Zeichne also einen Rahmen mit abgerundeten Ecken innerhalb deiner Region und alles müsste klappen.
Mit CreateRoundRectRgn habe ich leider auch keine Erfahrungen. Die Win32-Hilfe sagt dazu aber folgendes:
Zitat:

The CreateRoundRectRgn function creates a rectangular region with rounded corners.

HRGN CreateRoundRectRgn(

int nLeftRect, // x-coordinate of the region's upper-left corner
int nTopRect, // y-coordinate of the region's upper-left corner
int nRightRect, // x-coordinate of the region's lower-right corner
int nBottomRect, // y-coordinate of the region's lower-right corner
int nWidthEllipse, // height of ellipse for rounded corners
int nHeightEllipse // width of ellipse for rounded corners
);


Parameters

nLeftRect

Specifies the x-coordinate of the upper-left corner of the region.

nTopRect

Specifies the y-coordinate of the upper-left corner of the region.

nRightRect

Specifies the x-coordinate of the lower-right corner of the region.

nBottomRect

Specifies the y-coordinate of the lower-right corner of the region.

nWidthEllipse

Specifies the width of the ellipse used to create the rounded corners.

nHeightEllipse

Specifies the height of the ellipse used to create the rounded corners.
Damit müsste alles klar sein.

Gruß oki

torud 9. Sep 2007 16:11

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Oki,

ich habe jetzt wieder mal mit dem Code etwas experimentiert und versucht...

Das Gute ist, dass der Border nun auch gezeichnet wird. Was allerdings nicht funktioniert und das verstehe ich leider nicht ganz, ist , dass der Gradient nicht mehr gezeichnet wird und auch das Bild nicht mehr gezeichnet wird. Dies passiert nur, wenn ich die Variante mit den abgerundeten Ecken wähle.

Folgender Code wird in dem Falle ausgeführt, wobei die Reihenfolge die gleiche ist und myRect des Canvas durch R aus deinem Code ersetzt wurde.

Delphi-Quellcode:
  if CornerUse and (CornerWidth > 0) then begin
    R := GetClientRect;
    FullRgn := CreateRectRgn(0, 0, Width, Height);
    CombineRgn( FullRgn, FullRgn, FullRgn, RGN_DIFF );

    // alle sichtbaren Bereiche einblenden
    Region := CreateRoundRectRgn(0, 0, R.Right, R.Bottom, FCornerWidth, FCornerWidth);
    CombineRgn( FullRgn, FullRgn, Region, RGN_OR );
    DeleteObject(Region);

    // alles Kombiniert und fertig
    SetWindowRgn(Handle, FullRgn, TRUE);

    R := GetClientRect;
    //jetzt bitte Gradient zeichnen
    if PaintGradient then
      DrawGradient(Canvas, BgColorFrom, BgColorTo, R, GradientDirection);

    //wenn bild vorhanden bild zeichnen
    if Picture <> nil then
      if PictureStretched then
        Canvas.StretchDraw(R,Picture.Graphic)
      else
        Canvas.Draw(0,0,Picture.Graphic);

    //bitte den border zeichnen
    if BorderWidth > 1 then
      Canvas.RoundRect(0 + (BorderWidth div 2), 0 + (BorderWidth div 2), width - (BorderWidth div 2),height - (BorderWidth div 2),FCornerWidth,FCornerWidth)
    else
      Canvas.RoundRect(0, 0, width-1, height-1,FCornerWidth,FCornerWidth);

    //und zum schluss noch den text drauf
    if FText <> '' then
      DrawText(Canvas.Handle, PChar(FText), -1, TextRect, myAlignment);
  end else DoVisible;
Der Border, wenn auch etwas unsauber ist mit abgerundeten Ecken zu sehen. Der Text ist auch auf dem Control. Es fehlen der Gradient, respektive das Bild. Ist kann ja immer nur eines von beiden zu sehen sein. Es wird aber komischerweise, wenn der Gradient auf True steht nur komplett mit schwarz oder der Farbe aus BGColorTo gefüllt und richtigerweise, wenn PaintGradient auf false steht, mit BgColorFrom gefüllt. Das heisst, dass der Gradient nicht korrekt ausgeführt wird. Ich habe, nur um sicher zu gehen, nochmals R := GetClientRect; ausgeführt, was aber nichts brachte.

Ich vermute mal, dass der Canvas sich irgendwie verändert hat, nach der Modifikation, was zur Folge hat, dass man nicht mehr so einfach ohne weiteres wie vorher drauf rummalen kann. Muss ich hierbei wieder etwas besonderes beachten?

Interessant ist auch, dass der Border bei den abgerundeten Ecken links und rechts oben "ausgefranst" aussieht, wenn ich PaintGradient auf false stehen habe. :? Ansonsten bin ich einigermaßen zufrieden und werde hier noch versuchen das Beste rauszuholen...Ein Bild hängt an...

oki 9. Sep 2007 18:41

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Hi Tom,

deine letzte Aktion vor dem Text schreiben ist RoundRect.

Hier mal ein Auszug aus der Delphi Hilfe:
Zitat:

Mit RoundRect können Sie unter Verwendung des aktuellen Stifts ein Rechteck mit abgerundeten Ecken zeichnen. Das Rechteck wird mit dem aktuellen Pinsel gefüllt.
Das hab ich jetzt direkt aus der Hilfe kopiert. Auch ich habe jetzt erst nachgelesen, was RoundRect macht.

Wenn das Rechteck mit dem aktuellen Pinsel gefüllt wird, dann müssen doch alle vorherigen Zeichenoperationen (Gradient) auf dem Canvas übermalt werden. Oder nicht?

Gruß oki

torud 9. Sep 2007 19:12

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
Ciao Oki,

rum wie nu, würde meine Schwester sagen, denn wenn ich den Gradient nachschiebe, wird er zwar gezeichnet, aber dann ist der Border weg. Ich dachte eigentlich, dass ich den Border zeichnen kann, indem ich nur den Pen benutzen und das Brush auch leer zeichnen kann...!?

Welche Möglichkeiten habe ich jetzt noch?

cruiser 9. Sep 2007 19:28

Re: Benötige Hilfe beim Entwickeln einer Komponente
 
vor dem Roundrect mach besser folgendes:

Delphi-Quellcode:
Canvas.Brush.Style := bsClear;
Damit wird keine Füllung gezeichnet. dass da Pixwl hervorstehn liegt vermutlich an unterschiedlichen Radien


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:26 Uhr.
Seite 3 von 4     123 4      

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz