Discussion:
Ein- und Ausblenden von Panels
(zu alt für eine Antwort)
Florian Hector
2004-12-09 09:46:29 UTC
Permalink
Hallo Leute,

mit welcher Komponente kann ich das Ein- und Ausblenden von Panels ähnlich
einem PageControl -aber ohne die Reiter- erreichen.
Ich habe eine Anwendung, bei der ich ursprünglich ein PageControl eingesetzt
habe. Jetzt werden aber langsam die Pages so zahlreich, daß die Übersicht
verloren geht. Deshalb will ich jetzt so was wie die Outlook Bar einsetzen
und damit die Panels einblenden. Mit normalen Panels wäre das zwar möglich,
ich müßte dann aber bei jedem Wechsel von Hand alle Panels bis auf das
aktive unsichtbar schalten, nicht wirklich elegant. Außerdem ist das
Arbeiten damit während der Entwurfszeit ein Krampf.

Hat da jemand einen Tipp für mich?

Florian
Marian Aldenhövel
2004-12-09 10:28:53 UTC
Permalink
Hi,
Mit normalen Panels wäre das zwar möglich, ich müßte dann aber bei jedem
Wechsel von Hand alle Panels bis auf das aktive unsichtbar schalten,
Du bräuchtest nur das eine gerade aktive unsichtbar schalten, alle anderen
sind bereits unsichtbar:

procedure TForm1.ActivatePanel(aPanel:TPanel);
begin
// Vorhang zu
if Assigned(FActivePanel) then
FActivePanel.Visible:=False;

// Bühne umbauen
FActivePanel:=aPanel:

// Vorhang auf
if Assigned(FActivePanel) then
FActivePanel.Visible:=True;
end;

Aber auch eine Schleife über alle Panels ist kein Problem. Ein Zugriff
auf Visible der nichts ändert kostet auch praktisch nix:

procedure TForm1.ActivatePanel(aPanelTag:integer);
var i:integer;
begin
for i:=Low(FPanels) to High(FPanels) do
FPanels[i].Visible:=(FPanels[i].Tag=aPanelTag);
end;

Ob das wirklich unelegant ist? Die Tag-Eigenschaft habe ich hier nur
verwendet weil es sie schon gibt, besser wäre ein eigener Typ der Deine
Panels aufzählt:

type TPanelType=(ptEingang,ptAusgang,ptHergang,ptGehoergang,..);

Und im Formular dann etwas wie:

private
FPanels:array[TPanelType] of TPanel;

Mit einer Methode, die sie beim Start alle einsammelt:

procedure TForm1.PopulatePanels;
begin
FPanels[ptEingang]:=pnEingang;
..

{$IFOPT ASSERTIONS}
for i:=Low(TPanelType) to High(TPanelType) do
Assert(FPanels[i]<>NIL,Format('Panel für Type %d nicht
zugewiesen.',[ord(i)]));
{$ENDIF}
end;
Außerdem ist das Arbeiten damit während der Entwurfszeit ein Krampf.
Das ist mit einem Formular mit vielen vielen Tabsheets und deshalb
zweimal vielen vielen Komponenten ohnehin ein Krampf.

Als Abhilfe kommt in Frage die Seiten jeweils als eigenes Formular
zu entwerfen und dann das große Formular erst zur Laufzeit
zusammenzubauen. Zum Beispiel so:

procedure TForm1.InitializePages;

function DockForm(aForm:TForm):TForm;
begin
aForm.Parent:=Self;
aForm.Align:=alClient;
aForm.BorderStyle:=bsNone;

Result:=aForm;
end;

begin
FPanels[ptEingang]:=DockForm(TfmEingang.Create(Self));
..
end;

Das lässt sich dann in zweierlei Weise dynamisieren. Erstens muss die
Anzahl und der Typ der einzelnen Seiten zur Übersetzungszeit noch gar
nicht feststehen. Das könnte sich erst zur Laufzeit ergeben - etwa aus
installierten und lizensierten Modulen. Und zweitens kann man die
Erzeugung einer solchen Seite verschieben bis sie das erste Mal
gebraucht wird, damit ist das Fenster schneller instanziiert und
angezeigt, die Zeit verteilt sich dann auf das Aufblättern der anderen
Seiten. Auch in der Summe ist die Zeit aber geringer, weil intern
weniger Notifications auftreten.

Nachteil der Methode ist, daß eine Seite nicht ohne weiteres auf die
Steuerelemente auf anderen Seiten zugreifen kann. Das muss dann jeweils
wohldefiniert und im Einzelfall zugelassen passieren. Ist das wirklich
ein Nachteil? Das kommt darauf an, wie Du es allgemein mit der Kapselung
hältst :-).

Vorteil: Du kannst statt die Seiten hintereinander anzuzeigen diese auch
wahlweise nebeneinander halten. Vielleicht will man eine Seite "abreissen"
und als freies Fenster darstellen?
Hat da jemand einen Tipp für mich?
Dutzende :-).

Ciao, MM
--
Marian Aldenhövel, Rosenhain 23, 53123 Bonn. +49 228 624013.
http://www.marian-aldenhoevel.de
"Flying an An-2 is like making love to a fat lady who's had too much to drink:
there's a lot to work with, it's unresponsive, you're never quite sure when
you're there, and it's big-time ugly."
Joachim Pimiskern
2004-12-10 19:44:43 UTC
Permalink
Guten Abend,
Post by Marian Aldenhövel
function DockForm(aForm:TForm):TForm;
begin
aForm.Parent:=Self;
aForm.Align:=alClient;
aForm.BorderStyle:=bsNone;
Result:=aForm;
end;
das ist ja klasse, das funktioniert ja auch mit Delphi 3.
Ich dachte, da müßte man TFrame nehmen, was es erst ab
höheren Delphis gibt.

Ideal für ein Fenster, wo links z.B. ein Treeview ist und rechts
was durch einen Splitter Abgetrenntes.

Grüße,
Joachim
Marian Aldenhövel
2004-12-11 08:49:23 UTC
Permalink
Hi,
Post by Joachim Pimiskern
das ist ja klasse, das funktioniert ja auch mit Delphi 3.
Jo.

Es gibt natürlich ein paar Kleinigkeiten, zum Beispiel bei der Behandlung
von ModalResult, beim Aufruf von GetParentForm und degleichen. Das merkt
man aber schnell und es gibt saubere naheliegende Lösungen.

Ich mache so etwas immer gerne wenn ich ein Formular habe, das in mehrere
logische Teile zerfällt und in Summe eine gewisse Komplexität zu übersteigen
verspricht.

Schön auch zum Beispiel für "Wizards". Die Seiten leitet man alle von einer
gemeinsamen Klasse ab und bestückt sie mit Steuerelementen. Die
Seitenbasisklasse hat Methoden wie Validate(), die man überschreibt um
festzustellen ob die Seite hinreichend ausgefüllt ist. Dann leitet
man den Wizard von einem Wizard-Basisformular ab das die Prev-, Next- und
Finish-Buttons enthält. Man überschreibt im Wizard eine oder mehrere
Methoden die den Kontrollfluss steuern. Etwa eine

function GetNextPage(CurrentPage:TBaseWizardPage):TBaseWizardPage; virtual;

Und schon hat man Wizards bei denen der Rahmen einheitlich aussieht,
konsistent funktioniert und so weiter.

Allerdings geht das bei großen Anwendungen dann auch ein bisschen nach hinten
los: Man muss es nämlich dann auch für die einfachen Wizards so machen, die
aus drei Seiten mit je einem Edit oder zwei Checkboxen bestehen. So ein
einfacher Wizard verteilt sich dann ohne Not eben auch auf vier Units und
acht Dateien, Basisklasse nicht mitgezählt. In einer Anwendung mit vielen
Wizards ist man dann geneigt jeden in ein eigenes Verzeichnis zu packen.

Ciao, MM
--
Marian Aldenhövel, Rosenhain 23, 53123 Bonn. +49 228 624013.
http://www.marian-aldenhoevel.de
"Flying an An-2 is like making love to a fat lady who's had too much to drink:
there's a lot to work with, it's unresponsive, you're never quite sure when
you're there, and it's big-time ugly."
Tim Westen
2004-12-09 11:15:27 UTC
Permalink
Außerdem ist das Arbeiten damit während der Entwurfszeit ein Krampf.
Neben dem Entwurf als separate Formulare bzw. Frames, bietet
sich noch die Möglichkeit, alle Panels mit Align = alTop in eine
Scrollbox zu packen. So hast Du zur Entwurfszeit bequemen Zugriff
auf die Panels. Zur Laufzeit blendest Du einfach sie Scrollbar aus
und zeigst wie bisher nur das gewünschte Panel an.

Gruß, Tim.
Ralf Kaiser
2004-12-09 15:53:34 UTC
Permalink
"Florian Hector" <***@web.de> schrieb im Newsbeitrag news:***@individual.net...

Hallo,
Post by Florian Hector
mit welcher Komponente kann ich das Ein- und Ausblenden von Panels ähnlich
einem PageControl -aber ohne die Reiter- erreichen.
Wenn du trotzdem bei einem PageControl bleiben willst:

Dann blende die Reiter einfach beim Programmstart aus (irgendwo in Onshow
z.B.)

for i := 0 to PageControlPacecount - 1 do begin
PageControl.Pages[i].TabVisible := false;
end;
PageControl.ActivePageIndex := 0;
Post by Florian Hector
verloren geht. Deshalb will ich jetzt so was wie die Outlook Bar einsetzen
und damit die Panels einblenden. Mit normalen Panels wäre das zwar möglich,
Mit der OutlookBar kannst du beim Klick auf ein Item der Bar dann einfach
mit "PageControlActivePage := newIndex;" umschalten.
Post by Florian Hector
Außerdem ist das Arbeiten damit während der Entwurfszeit ein Krampf.
Während der Entwurfszeit sind die Tabs ja sichtbar, sie werden erst in
OnShow versteckt, du hast also zur Entwurfszeit immer die Möglichkeit
zwischen den Seiten umzuschalten

Ciao,
Ralf
Holger Lembke
2004-12-09 16:27:42 UTC
Permalink
Post by Florian Hector
Ich habe eine Anwendung, bei der ich ursprünglich ein PageControl eingesetzt
habe. Jetzt werden aber langsam die Pages so zahlreich, daß die Übersicht
verloren geht.
Ich lebe ganz gut damit, die einzelnen Panels in Frame zu legen und zur
Laufzeit dynamisch zu erzeugen und dann in das Formular einzuklinken.

Im Formular ist dann nur die Bedienlogik zum Ein- und Ausblenden.

Wirkt sich auch sehr wohltuend auf die Event-Unübersichtlichkeit im
Quellcode aus.
--
mit freundlichen Grüßen ! special bubble --> O
Holgi, +49-531-3497854 !
Florian Hector
2004-12-10 07:06:33 UTC
Permalink
Hallo Leute,

danke für alle guten Tipps.

Das Pagecontrols mit ausgeblendeen Reitern wie von Ralf vorgeschlagen ist
das, was mir vorgestellt habe. Damit hält sich auch der Umstellungsaufwand
in Grenzen.

Florian
Loading...