![]() |
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:
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:
Was passiert:
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); 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ß |
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. |
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 |
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. |
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:
Mit Aufruf DoInvisible wird der überflüssige Tein unsichtbar, mit DoVisible alles sichtbar.
TMyControl = class(TCustomControl)
private FullRgn, PointRgn : THandle; ...... protected procedure DoInvisible; procedure DoVisible; ......
Delphi-Quellcode:
Das kann man so übernehmen.
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;
Delphi-Quellcode:
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.
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; Vergiß nicht im Destructor den Speicher wieder frei zu geben.
Delphi-Quellcode:
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.
destructor TMyControl.Destroy;
begin try DeleteObject(FullRgn); DeleteObject(PointRgn); except end; Gruß oki |
Re: Benötige Hilfe beim Entwickeln einer Komponente
Zitat:
Delphi-Quellcode:
(c) by Schweizer :mrgreen:
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; |
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 |
Re: Benötige Hilfe beim Entwickeln einer Komponente
Zitat:
|
Re: Benötige Hilfe beim Entwickeln einer Komponente
Moin Zusammen,
nicht zu vergessen: OnPaint denn dann wird das Formular gezeichnet... |
Re: Benötige Hilfe beim Entwickeln einer Komponente
Die Reihenfolge ist folgendermaßen :
Delphi-Quellcode:
OnCreate
OnShow OnActivate OnPaint |
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] |
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:
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.
img[i].Canvas.Brush.Style := bsClear;
img[i].Canvas.Brush.Color := clNone; ![]() 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. |
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:
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.
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; ..... BTW. Schatten um die Komponente waäre auch "cool"... |
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:
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...
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; |
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 |
Re: Benötige Hilfe beim Entwickeln einer Komponente
Hi,
reicht das hier:
Delphi-Quellcode:
Gruß
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; |
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 |
Re: Benötige Hilfe beim Entwickeln einer Komponente
Liste der Anhänge anzeigen (Anzahl: 1)
Hier das Bild
|
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 |
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... |
Re: Benötige Hilfe beim Entwickeln einer Komponente
Delphi-Quellcode:
Das Region Handle nach einer Zuweisung mit
SetWindowRgn(Handle, Region, True);
DeleteObject(Region); ![]() 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. |
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.
|
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:
Hier wird nirgens der FullRgn nach SetWindowRgn angefaßt!
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 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 |
Re: Benötige Hilfe beim Entwickeln einer Komponente
Zitat:
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; |
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 |
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. |
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 |
Re: Benötige Hilfe beim Entwickeln einer Komponente
Nein, denn das gilt nur für Region Handles, die mit
![]() |
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 |
Re: Benötige Hilfe beim Entwickeln einer Komponente
Also als Beispiel:
Delphi-Quellcode:
Edit: Fehler ausgebessert :roll:
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; |
Re: Benötige Hilfe beim Entwickeln einer Komponente
Zitat:
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... |
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 |
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:
DeleteObject(FullRgn) nicht löschen, auch net im Desctructor;
procedure TForm1.FormDestroy(Sender: TObject);
begin //Clean up the regions we created DeleteObject(ClientRgn); DeleteObject(FullRgn); DeleteObject(CtlRgn); end; Noch eine Anmerkung, es macht einen Unterschied, ob Du auf einem FOrmular, oder in einer Komponente programmierst. Zb ist FormCreate <> constructor Create... |
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:
Gruß oki
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; |
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... |
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:
Gruß oki |
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:
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.
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; 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... |
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:
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 |
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? |
Re: Benötige Hilfe beim Entwickeln einer Komponente
vor dem Roundrect mach besser folgendes:
Delphi-Quellcode:
Damit wird keine Füllung gezeichnet. dass da Pixwl hervorstehn liegt vermutlich an unterschiedlichen Radien
Canvas.Brush.Style := bsClear;
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:26 Uhr. |
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