Delphi-PRAXiS
Seite 2 von 3     12 3      

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/)
-   -   Event bei Z-Order Änderung o.ä. (https://www.delphipraxis.net/171733-event-bei-z-order-aenderung-o-ae.html)

Medium 22. Nov 2012 15:56

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 :)

Sir Rufo 22. Nov 2012 16:14

AW: Event bei Z-Order Änderung o.ä.
 
Zitat:

Zitat von DeddyH (Beitrag 1192418)
Du durchläufst p.ControlCount (Parent-Beziehung) und greifst dann auf p.Components (Owner-Beziehung) zu. Ist das Absicht?

Wohl eher absichtlich unabsichtlich vertippt. ;)

DeddyH 22. Nov 2012 16:57

AW: Event bei Z-Order Änderung o.ä.
 
Das kann aber fatal enden, deshalb meine Frage ;)

Bummi 22. Nov 2012 17:19

AW: Event bei Z-Order Änderung o.ä.
 
@DeddyH , nein , danke für den Hinweis, habe es korrigiert.

Bummi 22. Nov 2012 17:24

AW: Event bei Z-Order Änderung o.ä.
 
@Sir Rufo

Zitat:

Eigentlich könnte man nach dem Label1.BringToFront die OnPaint Methode verlassen
ich hatte kurz über diese Option nachgedacht, dann aber beschlossen sicherheitshalber in jedem Fall zeichnen zu lassen, für den Fall dass das Label kein intersect mit dem control hat, das Label in der zOrder tiefer liegt und erstmalig gezeichnet wird.

Medium 23. Nov 2012 11:36

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:
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;
Dann waren InvalidateControl() und SetZOrderPosition() zu re-implementieren, und zwar so, dass es als Prozedur/Funktion geht, nicht Methode:
Delphi-Quellcode:
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;
Und dann meine Helfer-Methoden:
Delphi-Quellcode:
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...
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!

Danke nochmals an alle :dp:

Bummi 23. Nov 2012 12:22

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.

Medium 23. Nov 2012 12:30

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.

Sir Rufo 23. Nov 2012 13:49

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.

Medium 23. Nov 2012 14:20

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.
Seite 2 von 3     12 3      

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