![]() |
AW: Event bei Z-Order Änderung o.ä.
Hui, das schaut nett aus. Ich glaube, ich hatte auch einen halben Meter zu kurz gedacht vorhin. Schade, dass Komponenten nicht standardmäßig ihren Index in der Parent-Liste bei sich tragen, weil so muss ich teilweise eine ganze Menge durchnudeln um es zu finden, was in jedem Repaint irgendwie unschön aussieht. Praktisch dürfte das glaube ich aber kaum zu merken sein. Probier ich morgen mal umzusetzen, danke!
Nebenfrage: Die Labels werden mit der Balken-Komponente als Owner erstellt, und bekommen dann den Parent der Balken-Kompo selbst auch als Parent. Tauchen die dann überhaupt in der Controls- bzw. Components-Liste des Formulars auf? Edit: Rote Box - das sollte diese Frage beantwortet haben :) |
AW: Event bei Z-Order Änderung o.ä.
Zitat:
|
AW: Event bei Z-Order Änderung o.ä.
Das kann aber fatal enden, deshalb meine Frage ;)
|
AW: Event bei Z-Order Änderung o.ä.
@DeddyH , nein , danke für den Hinweis, habe es korrigiert.
|
AW: Event bei Z-Order Änderung o.ä.
@Sir Rufo
Zitat:
|
AW: Event bei Z-Order Änderung o.ä.
Problem gelöst! Allerdings ein Eckchen aufwendiger :mrgreen:
Zu erreichen war ja, dass meine Sub-Controls in Z-Richtung immer möglichst nahe an meinem eigentlichen Control (Balken) liegen, zumindest aber so, dass folgendes gewährleistet ist: - alle Lables müssen immer über dem Balken liegen - alle Controls, die den Balken verdecken, sollen auch die Labels verdecken - alle Controls, die durch den Balken verdeckt werden, sollen auch hinter den Labels liegen Letztlich also so, als wären die Labels (und Skalenstriche, die ich ebenfalls als Subkomponente gebaut habe weil sie ausserhalb liegen sollen) fester Bestandteil des Balkens, und lägen in der selben Z-Plane wie dieser. Ärgerlich ist mal wieder, dass CodeGear (ja, D2007 :)) ja recht freizügig mit private-Deklarationen in der VCL war. Um o.g. zu erreichen, wäre die Methode TControl.SetZOrderPosition() ideal gewesen, aber eben leider private. Gut, kann man sich abgucken und kopieren, aber leider ist auch das darin benötigte Feld "FControls", sowie die Methode InvalidateControl() private. Und die Methode PaletteChanged() ist protected :? Also musste ein ekeliger Hack her, womit das ganze erstmal nur gesichert in meiner Version klappt. Das ist zunächst auch okay, weil wir D2007 hier überall haben, und die Komponente nur für den hausinternen Gebrauch ist. Lange Rede, kurzer Pin: Die Hack-Klasse:
Delphi-Quellcode:
Dann waren InvalidateControl() und SetZOrderPosition() zu re-implementieren, und zwar so, dass es als Prozedur/Funktion geht, nicht Methode:
type
// Liegt in der selben Unit wie TKATBalken, wodurch dank Friend-Beziehung Zugriff auf private Felder geht // Feld-Layout ist identisch mit dem von TWinControl THackedControl = class(TControl) private FAlignLevel: Word; FBevelEdges: TBevelEdges; FBevelInner: TBevelCut; FBevelOuter: TBevelCut; FBevelKind: TBevelKind; FBevelWidth: TBevelWidth; FBorderWidth: TBorderWidth; FPadding: TPadding; FBrush: TBrush; FDefWndProc: Pointer; FDockClients: TList; FDockManager: IDockManager; FHandle: HWnd; FImeMode: TImeMode; FImeName: TImeName; FObjectInstance: Pointer; FParentWindow: HWnd; FTabList: TList; FControls: TList; FWinControls: TList; FTabOrder: Integer; FTabStop: Boolean; FCtl3D: Boolean; FShowing: Boolean; FUseDockManager: Boolean; FDockSite: Boolean; FParentCtl3D: Boolean; FOnDockDrop: TDockDropEvent; FOnDockOver: TDockOverEvent; FOnEnter: TNotifyEvent; FOnExit: TNotifyEvent; FOnGetSiteInfo: TGetSiteInfoEvent; FOnKeyDown: TKeyEvent; FOnKeyPress: TKeyPressEvent; FOnKeyUp: TKeyEvent; FOnUnDock: TUnDockEvent; FOnAlignInsertBefore: TAlignInsertBeforeEvent; FOnAlignPosition: TAlignPositionEvent; FMouseInClient: Boolean; FMouseControl: TControl; public function PaletteChanged(Foreground: Boolean): Boolean; override; end; implementation function THackedControl.PaletteChanged(Foreground: Boolean): Boolean; begin result := inherited PaletteChanged(Foreground); end;
Delphi-Quellcode:
Und dann meine Helfer-Methoden:
procedure InvalidateControl(IsVisible, IsOpaque: Boolean; self: TControl; aParent: THackedControl);
var Rect: TRect; function BackgroundClipped: Boolean; var R: TRect; List: TList; I: Integer; C: TControl; begin Result := True; List := aParent.FControls; I := List.IndexOf(Self); while I > 0 do begin Dec(I); C := List[I]; with C do if C.Visible and (csOpaque in ControlStyle) then begin IntersectRect(R, Rect, BoundsRect); if EqualRect(R, Rect) then Exit; end; end; Result := False; end; begin if (IsVisible or (csDesigning in self.ComponentState) and not (csNoDesignVisible in self.ControlStyle)) and (self.Parent <> nil) and self.Parent.HandleAllocated then begin Rect := self.BoundsRect; InvalidateRect(self.Parent.Handle, @Rect, not (IsOpaque or (csOpaque in self.Parent.ControlStyle) or BackgroundClipped)); end; end; procedure SetZOrderPosition(Position: Integer; self: TControl; aParent: THackedControl); var I, Count: Integer; ParentForm: TCustomForm; begin if aParent <> nil then begin I := aParent.FControls.IndexOf(Self); if I >= 0 then begin Count := aParent.FControls.Count; if Position < 0 then Position := 0; if Position >= Count then Position := Count - 1; if Position <> I then begin aParent.FControls.Delete(I); aParent.FControls.Insert(Position, Self); InvalidateControl(self.Visible, True, self, aParent); if not (csLoading in self.ComponentState) then begin ParentForm := ValidParentForm(Self); if csPalette in ParentForm.ControlState then THackedControl(ParentForm).PaletteChanged(True); end; end; end; end; end;
Delphi-Quellcode:
Mit "CorrectZOrders" werden dann genau die o.g. Bedingungen hergestellt. Vor allem aber wird nichts geändert wenn diese schon bestehen, so dass dies nicht mehr zu einer Endlosrekursion wird. Zwar finde ich das ganze im Paint noch immer deutlich zu oft, zumal dann ja zumindest immer noch die Prüfungen laufen, aber es scheint einfach keine bessere Stelle zu geben. Läuft prima, auch auf ziemlich gut gefüllten Forms!
function GetControlParentIndex(aControl: TControl): Integer;
var i: Integer; begin result := -1; if not Assigned(aControl.Parent) then Exit; for i := 0 to aControl.Parent.ControlCount-1 do begin if aControl.Parent.Controls[i] = aControl then begin result := i; Exit; end; end; end; function RectsOverlap(aRect1, aRect2: TRect): Boolean; begin result := not((aRect1.Right < aRect2.Left) or (aRect1.Left > aRect2.Right) or (aRect1.Bottom < aRect2.Top) or (aRect1.Top > aRect2.Bottom)); end; procedure TKATBalken.CorrectSubControlZOrder(aSubControl: TControl; aBaseIndex: Integer); var i, subIndex: Integer; begin subIndex := GetControlParentIndex(aSubControl); if subindex<0 then Exit; if subIndex<aBaseIndex then begin SetZOrderPosition(aBaseIndex+1, aSubControl, THackedControl(Parent)); end else begin for i := 0 to Parent.ControlCount-1 do begin if RectsOverlap(Parent.Controls[i].BoundsRect, aSubControl.BoundsRect) then begin if ((i>aBaseIndex) and (i<subIndex)) or ((i<aBaseIndex) and (i>subIndex)) then begin SetZOrderPosition(aBaseIndex+1, aSubControl, THackedControl(Parent)); Exit; end; end; end; end; end; procedure TKATBalken.CorrectZOrders; var i, selfIndex: Integer; begin selfIndex := GetControlParentIndex(self); CorrectSubControlZOrder(ValueLabel, selfIndex); CorrectSubControlZOrder(ScaleLeft, selfIndex); CorrectSubControlZOrder(ScaleRight, selfIndex); for i := 0 to High(ScaleLabelsLeft) do begin CorrectSubControlZOrder(ScaleLabelsLeft[i], selfIndex); CorrectSubControlZOrder(ScaleLabelsRight[i], selfIndex); end; end; procedure TKATBalken.Paint; begin inherited; CorrectZOrders; // Restlicher Code... Danke nochmals an alle :dp: |
AW: Event bei Z-Order Änderung o.ä.
ich will ja nicht unken, aber ich bin immer noch der Meinung dass es sinnvoller wäre alles in einer Komponente abzufackeln, Alignments, Ausrichtungen und Längen lassen sich ja auch berechnen.
|
AW: Event bei Z-Order Änderung o.ä.
Nicht, wenn die Breite der Skalentexte zur Runtime erst bekannt wird. Dann ist das Control längst platziert, und ich will im Code des eigentlichen Projektes keine Fetzen rumfliegen haben, die die Neuausrichtung machen müssen. Zudem ist es so auch noch etwas gefälliger im Umgang im Designer, da der ja doch recht große Freiraum zwischen den Skalentexten nicht mehr zum Balken gehört, und man die nicht mehr so oft aus Versehen erwischt, wenn man eigentlich ein anderes in der näheren Umgebung haben wollte. Für unsere Zwecke erscheint mir das zunächst als guter Weg, es sei denn da hat noch jemand konkrete Killer-Argumente die ich bisher nicht bedacht habe.
|
AW: Event bei Z-Order Änderung o.ä.
Ich mag TLabeledEdit nicht, weil es sich völlig anders verhält als andere Controls.
Es beansprucht mehr Platz als es die Abfrage (Width,Height) vermuten lässt. Align ist auch nicht sinnvoll möglich. Es ist also ein Konstrukt, was den Benutzer in einigen Punkten überrascht, und solche Ü-Eier gelten im Allgemeinen als schlechter Code. Einen Vorteil kann ich da auch nicht entdecken, nur Faulheit. Es geht nicht darum, dass eine Komponente TLabeledEdit unnütz ist, sondern darum, dass diese schlecht implementiert ist. Die Gründe dafür sind mir egal weil man sich alles schönreden kann. |
AW: Event bei Z-Order Änderung o.ä.
Nun, da das Teil nur für einen sehr speziellen Zweck eingesetzt wird (Prozessvisualisierung, ähnlich WinCC, nur dass wir quasi Formulare+Kompos dazu missgebrauchen), bei dem Alignment ohnehin bestenfalls zu einem unvorhersehbarem Verhalten führen würde, da so viele Einzelteile und Verbindungen zwischen diesen existieren. Praktisch nicht machbar, also auch kein Thema. Vorläufig bin ich auch der einzige, der damit arbeitet. Die Lage der Teile muss auch im Code niemals angefasst werden. Es mag nicht deinem Geschmack entsprechen, aber für Einsatzgebiet empfinde ich das als sehr praktisch. Diese Subjektivität ist für mich jetzt kein Killer-Argument :)
Warum ist Faulheit schlecht? Bzw. an welcher Stelle empfindest du das als faul? Wäre es dir dann lieber in ~10 Formularen mit je 6-30 solcher Balken alle Beschriftungen von Hand mit Labels zu machen, und diese dann auch noch von Hand auf Werte aus einer DB zu setzen UND noch korrekt zu positionieren da die Zahlenbreite sich ggf. ändert? Da es für alle Balken gleich abläuft, ist das so doch der Inbegriff von Modularität und funktional orientierter Kapselung. Ich kann leider echt nicht folgen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:30 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