Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - Gebrauch von TComponents
Gerhard_S - Sa 27.07.13 23:33
Titel: Gebrauch von TComponents
Aus lauter Faulheit habe ich mir gedacht, ich könnte den folgenden Code
Quelltext
1: 2: 3: 4: 5: 6:
| Shape3.Left := Shape2.Left+Shape2.Width; Shape4.Left := Shape3.Left+Shape3.Width; Shape5.Left := Shape4.Left+Shape4.Width; Shape6.Left := Shape5.Left+Shape5.Width; Shape7.Left := Shape6.Left+Shape6.Width; Shape8.Left := Shape7.Left+Shape7.Width; |
abkürzen durch:
Quelltext
1: 2: 3: 4:
| for j := 3 to 8 do begin TShape(Components[j]).Left := TShape(Components[j-1]).Left + TShape(Components[j-1]).Width; end; |
Leider unterscheiden sich die Ergebnisse stark voneinander; genauer: die kurze Schreibweise liefert Mist.
Kann mir das jemand erklären?
IhopeonlyReader - Sa 27.07.13 23:49
Lass dir mal
Components[j].Name ausgeben.. Denn components[3] ist nicht automatisch shape 3..
Schau dir mal die Funktion getcomponent an ;) soviel ich weiß muss der Komponenten Name übergeben werden und du bekommst die Komponente zurück.. Diese dann in ein shape casten und anpassen..
Delete - So 28.07.13 09:09
- Nachträglich durch die Entwickler-Ecke gelöscht -
Gerhard_S - So 28.07.13 11:01
Ich glaube, ich muss den vollständigen Code zeigen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32:
| for i := 0 to ComponentCount - 1 do begin if Components[i] is TShape then begin if (TShape(Components[i]).Brush.Color = clHighlight) and (TShape(Components[i]).Visible = true) then begin if TShape(Components[i]).Name = 'Shape1' then begin if MessageDlg('Wollen Sie das wirklich?', mtConfirmation, [mbYes, mbNo], 0, mbYes) = mrYes then begin Shape1.Visible := false; Label2.Visible := false; Shape2.Left := Shape1.Left; for j := 3 to 8 do begin if Components[j] is TShape then TShape(Components[j]).Left := TShape(Components[j-1]).Left + TShape(Components[j-1]).Width; end; Label3.BoundsRect := Shape2.BoundsRect; Label4.BoundsRect := Shape3.BoundsRect; Label5.BoundsRect := Shape4.BoundsRect; Label6.BoundsRect := Shape5.BoundsRect; Label7.BoundsRect := Shape6.BoundsRect; Label8.BoundsRect := Shape7.BoundsRect; Label9.BoundsRect := Shape8.BoundsRect; end else Exit; end; end; end; end; |
Die Aufgabe ist einfach: Hat der Benutzer Shape1 ausgewählt (woraufhin dieser seine Farbe nach clHighlight ändert), rücken alle anderen Shapes incl. ihrer Labels um eine Shape-Breite nach links.
Bei obigem Code wird Shape1 unsichtbar gemacht, die Anweisung Shape2.Left := Shape1.Left wird aber ebensowenig ausgeführt wie die Anweisung in der for-j-Schleife.
Das verstehe ich nicht.
Moderiert von
Martok: Code- durch Delphi-Tags ersetzt
jaenicke - So 28.07.13 11:07
Und die for-Schleife muss über alle Components laufen usw.
Aber das ist ja auch nicht das gewünschte Ergebnis, denn die Durchnummerierung richtet sich nach der Erstellung, nicht nach dem Namen. j-1 ist also kaum das gewünschte andere Shape.
In diesem Fall ist das Problem, dass du direkt auf den Komponenten als Datenspeicher arbeitest statt diese nur zur Anzeige zu nutzen. Dadurch wird der Quelltext umständlich, riesig und langsam. Viel sinnvoller wäre, im Hintergrund dir zu merken was in der Anzeige ist und dann das anzuzeigen. So richtig kann ich mir nicht vorstellen wie das aussehen soll und was du damit im Programm erreichen möchtest, sonst könnte ich auch mehr sagen.
Gerhard_S - So 28.07.13 19:59
Sinn der Übung ist folgende:
Die Shapes repräsentieren die nebeneinander liegenden Items eines Menüs. Der Benutzer soll Items löschen, verschieben, hinzufügen können (so wie die "Kacheln" in Win 8). Da Shapes kein OnClick-Ereignis haben, behelfe ich mir mit einem Trick: auf jedem Shape sitzt ein Label gleicher Größe (z.B. Label3.BoundsRect := Shape2.BoundsRect;), das über ein OnClick-Ereignis verfügt.
Im angeführten Code geht's um die Folgen des "Löschens" (=unsichtbar machen) einer linksaußen sitzenden "Kachel": wird sie unsichtbar gemacht, sollen alle rechts von ihr stehenden "Kacheln" eine Shape-Breite nach links rücken.
Delete - So 28.07.13 23:11
- Nachträglich durch die Entwickler-Ecke gelöscht -
Gerhard_S - So 28.07.13 23:19
Frühlingsrolle schrieb: "Dem Shape kann man in so einer Situation das OnClick Ereignis vererben".
Das ist leider nur die halbe Miete. Das Shape braucht auch noch eine Beschriftung.
IhopeonlyReader - So 28.07.13 23:29
Canvas.textout, onpaint, StringVariable
Diese 3 Begriffe sollten reichen ;)
Hobby-Programmierer - Mo 29.07.13 01:01
Vielleicht könntest du stattdessen auf ein TPanel o.ä. ausweichen.
jaenicke - Mo 29.07.13 06:30
Viel sinnvoller ist wirklich wie ich eingangs schrieb die Daten von der Darstellung zu trennen...
Du hast also fünf Einträge, die du anzeigen willst? Nun, dann zeige sie auf den ersten fünf an und blende die anderen aus. Dann brauchst du nicht den ersten Eintrag ausblenden und mühsam die Positionen zu verändern.
Blup - Mo 29.07.13 15:50
Man kann sich das Leben leichter machen, wenn man den Zugriff auf die Komponenten kapselt.
Der Code wird übersichtlicher und man kann sich auf die eigentliche Aufgabe konzentrieren:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43:
| function TForm1.GetColShape(ACol: Integer): TShape; begin Result := FindComponent('Shape' + IntToStr(ACol)) as TShape; end;
function TForm1.GetColLabel(ACol: Integer): TLabel; begin Result := FindComponent('Label' + IntToStr(ACol + 1)) as TLabel; end;
procedure TForm1.ShapeUpdate; var i, iLeft: Integer; Sh: TShape; Lb: TLabel; begin iLeft := 0; for i := 1 to 6 do begin Sh := GetColShape(i); Lb := GetColLabel(i); Sh.Visible := Lb.Visible; if Sh.Visible then begin Sh.Left := iLeft; Lb.Left := iLeft; Inc(iLeft, Sh.Width); end; end; end;
procedure TForm1.LabelClick(Sender: TObject); begin if Sender is TLabel then begin if MessageDlg('Wollen Sie das wirklich?', mtConfirmation, [mbYes, mbNo], 0, mbYes) = mrYes then begin TLabel(Sender).Visible := False; ShapeUpdate; end; end; end; |
Gerhard_S - Mo 29.07.13 22:49
Hobby-Programmierer hat folgendes geschrieben : |
Vielleicht könntest du stattdessen auf ein TPanel o.ä. ausweichen. |
Gute Idee, damit erspare ich mir die Huddelei mit den Labels.
Gerhard_S - Mo 29.07.13 22:54
Blup hat folgendes geschrieben : |
Man kann sich das Leben leichter machen, wenn man den Zugriff auf die Komponenten kapselt.
|
Vollkommen einverstanden. Leider gibt Zeile 23 (Sh.Visible := Lb.Visible;) eine AV, wenn i = 6 ist (6 ist die Anzahl der Shapes); nach Klick auf OK sieht es so aus, als ob nur die Labels gewandert sind, denn das letzte Shape rechts außen hat kein Label mehr.
Wenn i maximal Shapeanzahl -1 erreichen darf, gibt es keine AV; das letzte - ohnehin überflüssige - Shape rechts außen hat weiterhin kein Label mehr.
Auch das lässt sich lösen:
direkt hinter die for-Schleife (hinter Zeile 30, vor Zeile 31) schreiben wir:
Quelltext
1: 2: 3:
| Sh := GetColShape(i); Lb := GetColLabel(i); if Sh.Visible then Sh.Visible := false; |
Danke an alle fürs Kümmern.
Gerhard_S - Mo 29.07.13 22:58
jaenicke hat folgendes geschrieben : |
Viel sinnvoller ist wirklich wie ich eingangs schrieb die Daten von der Darstellung zu trennen...
Du hast also fünf Einträge, die du anzeigen willst? Nun, dann zeige sie auf den ersten fünf an und blende die anderen aus. Dann brauchst du nicht den ersten Eintrag ausblenden und mühsam die Positionen zu verändern. |
Es soll aber so aussehen, wie die Schlange vorm Freibad: hat der erste in der Schlange das Freibad betreten, rücken alle anderen einen Schritt nach vorn - um mal einen jahreszeitlich angepassten Vergleich zu bringen.
jaenicke - Di 30.07.13 05:55
Gerhard_S hat folgendes geschrieben : |
Es soll aber so aussehen, wie die Schlange vorm Freibad: hat der erste in der Schlange das Freibad betreten, rücken alle anderen einen Schritt nach vorn - um mal einen jahreszeitlich angepassten Vergleich zu bringen. |
Eben, aber dafür brauchst du ja nicht die Komponenten verschieben, sondern es reicht das zu ändern, was sie anzeigen.
Bei Kacheln erinnere ich mich an ein Beispiel-Programm von mir, das damit durchaus Ähnlichkeit hat:
http://www.delphi-forum.de/viewtopic.php?p=557541
Ich glaube eine Umsetzung in der Richtung würde besser aussehen und ließe sich auch einfacher umsetzen als visuelle Komponenten, die auf dem Formular umherwandern. Das wäre bei dir auch viel einfacher, da du gar nicht verschiedene Raster hast wie bei mir.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!