![]() |
Dynamischen Wizard realisieren
Ich soll für meine Ausbildungsfirma einen Konfigurationswizard für unser Prozess-Leitsystem erstellen. Nun stehe ich vor folgendem Problem:
Der Wizard muss dynamisch mit Inhalt bestückt werden können. Das heißt, dass sowohl die Anzahl der Wizard-Seiten variabel sein soll (was wohl eher unproblematisch ist), als auch deren Inhalt. Es soll also ein Hauptprogramm geben, das letztendlich nur eine Container-Funktion ausübt, und die eigentliche Funktionalität wird in Plugins (DLLs, Packages) ausgelagert. Als eine der besten Möglichkeiten, einen Wizard zu realisieren, wird ja oft die PageControl in Verbindung mit TabSheets genannt. Also habe ich auch schon mich daran versucht, auf dem Hauptformular nur eine leere PageControl zu platzieren und die TabSheets dann in eine DLL auszulagern. Jedoch scheiterte es daran, das TabSheet anschließend in die PageControl einzubinden, so dass es dort auch sichtbar wird. Ich hab der von der DLL veröffentlichten "CreateTabSheet"-Funktion das Handle der PageControl übergeben, sodass dort ein neues TabSheet mit der PageControl aus dem Hauptformular als Parent kreiert werden kann. Nur reicht das ja noch nicht, um das TabSheet auch dort sichtbar zu machen. Und daran hängts momentan irgendwie. Was ich allerdings auch noch nicht weiß ist, wie kann man in der DLL ein reines TabSheet ohne Formular und PageControl erzeugen kann und dieses dann auch mit Komponenten wie Buttons, Labels etc. bestücken??? Ohne Formular kann man sich doch auch gar nicht so schön eine Oberfläche "zusammenklicken" oder? Ansatz Nummer 2 waren die Packages, in die ich mich anhand von einem Beispiel aus dem Netz einarbeiten wollte. Das Progrämmchen sollte schlicht und einfach per Buttonklick ein andres Formular, das in einem Package ausgelagert ist, modal öffnen. Doch obwohl ich mich strikt an die Anleitung bei der Erstellung des Progrämmchens gehalten habe funktioniert es nicht. Das Problem, an dem es wohl hängt: die Klasse TForm2 wird in der Unit2 (die im Package) im initialization-Teil zwar registriert, jedoch SOFORT wieder unregistriert im finalization-Teil. Initialization und finalization laufen also hintereinander weg durch, was doch eigentlich nicht der fall sein sollte, oder? Hier das Hauptformular:
Delphi-Quellcode:
Hier das Formular 2 aus dem Package:
unit Unit1;
interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); var PackageModule: HModule; AClass: TPersistentClass; begin PackageModule := LoadPackage('Package1.bpl'); if PackageModule <> 0 then begin AClass := GetClass('TForm2'); if AClass <> nil then with TComponentClass(AClass).Create(Application) as TCustomForm do begin ShowModal; Free; end; UnloadPackage(PackageModule); end; end; end.
Delphi-Quellcode:
In der Jedi-VCL gibt es wohl bereits eine Wizard-Komponente, allerdings kommt deren Einsatz für uns wohl nicht in Frage (gibt es da irgendwelche Lizenz-technischen Gründe?). Wobei ich auch nicht weiß, ob die überhaupt so einen dynamischen Aufbau unterstützen würde.
unit Unit2;
interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs; type TForm2 = class(TForm) private { Private-Deklarationen } public { Public-Deklarationen } end; var Form2: TForm2; implementation {$R *.DFM} initialization RegisterClass(TForm2); finalization UnRegisterClass(TForm2); end. Was habt ihr mir für Ratschläge? Wie kann ich das Konzept "Hauptprogramm mit Container" - "Plugins für die Wizard-Seiten" am besten realisieren? Danke schonmal für die Hilfe! |
Re: Dynamischen Wizard realisieren
also das mit den TahSheets ist recht einfach das habe ich bei einem meiner Projekte auch gemacht.
am besten du legst dir dafür 2 Objekte an eine TabSheetList und ein TabSheetItem. Beim TabSheetItem machst du ne Tabsheet property und alles zeug was das tabsheet halt so haben soll, buttons, listviews usw. bei der tabsheetlist gibst du beim erstellen die pagecontrol mit die du dort auch als property speicherst die brauchst du dann. dann nimmst dir ne routine namens createtabsheets und läßt dann von der tabsheetlist welche von TObjectList oder ähnlichem abgeleitet ist die tabsheetitems erstellen und in die liste eintragen. aus einem meiner projekte kann cih dir ja mal den code der tabsheetliste beim erstellen geben.
Delphi-Quellcode:
ja das ist von meinem MovieManager projekt an dem ich schon seit einiger zeit arbeite, da hat man dynamisch viele tabsheets mit listen. drum wird hier auf dem tabsheet auch nur sichtbar die listview erstellt.
for SectionIndex := 0 to Pred(AVideoListenSections.Count) do
begin ANewCreated := False; ATabSheetIndex := TabExists(AVideoListenIniFile.ReadString(AVideoListenSections[SectionIndex], 'Name', '')); if (ATabSheetIndex = -1) then begin ATabSheet := TTabSheet.Create(FPageControl); AListView := TListView.Create(ATabSheet); ATabSheetObjectItem := TTabSheetObjectItem.Create(AListView, ATabSheet); ANewCreated := True; end else //TabSheet Existiert bereits ATabSheetObjectItem := TTabSheetObjectItem(Items[ATabSheetIndex]); ATabSheetObjectItem.LoadFromIniFile(BuildFileName(AApplicationPath, ConstU.VideoListenFileName), AVideoListenSections[SectionIndex]); with ATabSheetObjectItem do begin AIniFile := TIniFile.Create(BuildFileName(MainForm.ApplicationPath, ConstU.MM3SettingsFile)); try if Visible then begin TabSheet.PageControl := FPageControl; TabSheet.Caption := Name; TabSheet.ImageIndex := IconIndex; ListView.Parent := TabSheet; ListView.Align := alClient; ListView.Color := BackgroundColor; ListView.FlatScrollBars := AIniFile.ReadBool('Allgemein', 'FlatScrollBars', False); ListView.Font.Color := LettersColor; ListView.GridLines := ShowGrids; ListView.HideSelection := False; ListView.MultiSelect := True; ListView.PopupMenu := MainForm.OptionsPopupMenu; ListView.ReadOnly := True; ListView.RowSelect := True; ListView.ShowColumnHeaders := ShowHead; ListView.OnColumnClick := ListViewOnColumnClick; MakeListViewHeader; end; vorher wird oben noch einwenig abgefragt ob das zeug schon in der pagecontrol ist und nur aktualisiert werden muss usw. kann man ja gut lesen. ich hoffe ich konnte in dem punkt ein wenig helfen |
Re: Dynamischen Wizard realisieren
Sorry aber das verstehe ich noch nicht ganz. Woher bekomme ich diese 2 Objekte TabSheetList und TabSheetItem? Von welcher Klasse sollen das Instanzen sein? Und hast du das ganze dann als DLL realisiert oder wie? Wenn ja, wie schaut deine Schnittstelle aus? Und wie komme ich von dieser TabSheetListe dann zu meinen TabSheets auf dem Formular???
:wiejetzt: |
Re: Dynamischen Wizard realisieren
Hallo Infect,
evtl. kannst du eine der Klassen verwenden, die Torry.net anbietet: ![]() Wir hatten auf Arbeit auch eine Wizard-Klasse, allerdings erinnere ich mich leider nicht mehr an den Namen :( Ein paar der Komponenten auf Torry sehen aber ziemlich vielversprechend aus... Greetz alcaeus |
Re: Dynamischen Wizard realisieren
-selber schreiben ist immer lehrreicher und macht mehr spaß
sorry ich war arbeiten ergo erst so spät die nächste antwort, also woher bekommst du die objekte ganz einfach du machst ne unit auf muss keine dll sein und erstellst sie. also hier die beiden Objete wie du sie erstellen kannst
Delphi-Quellcode:
so an sich sind dei beiden objekte dann deine schnittstelle zwischen PageControl und TabSheets.
TabSheetItem = class
private protected FName : string; FTabSheet : TTabSheet; public property Name : string read FName write FName; property TabSheet : TTabSheet read FTabSheet write FTabSheet; constructor Create(AOwner : TComponent); //WICHTIG end; TabSheetList = class(TObjectList) private protected FPageControl : TPageControl; public constructor Create(APageControl : TPageControl); property PageControl : TPageControl read FPageControl write FPageControl; procedure LoadTabSheets; end; //DER TABSHEETITEM CONSTRUCTOR IST WICHTIG DAS DAS TABSHEET ERSTMAL DA IST constructor TabSheetItem.Create(AOwner : TComponent); begin inherited; FTabSheet := TTabSheet.Create(AOwner); end; constructor TabSheetList.Create(APageControL : TPageControl); begin inherited Create; FPageControl := APageControl; end; procedure TabSheetList.LoadTabSheets; var AQuellTabSheetNamen : TStringList; ATabSheetItem : TTabSheetItem; ItemIndex : integer; begin AQuellTabSheetNamen := TStringList.Create; try AQuellTabSheetNamen := //ja die ließt du aus irgentnem gespeicherten ort ein z.B. eine INI file //da das bei dir ja variiert könntest du immer paare in die ini schreiben //den Namen und obs ausgeführt wird was vorher dann in die ini geschrieben wird //nach verschiedenen check routinen wovon du deine tabsheets abhänig machst for ItemIndex := 0 to Pred(AQuellTabSheetNamen.Count) do begin ATabSheetItem := TTabSheetItem.Create(FPageControl); with ATabSheetItem do begin //hier setzt du jetzt die eigenschaften des tabsheet items //wichtig sind Parent := FPageControl; Caption := AQuellTabSheetNames[ItemIndex]; end; //jetzt kannst auch die ganzen sachen die noch drauf sollen erstellen non Visuell versteht sich Add(ATabSheetItem); //Das item in die liste aufnehmen end; finally FreeAndNil(AQuellTabSheetNamen); end; end; am besten die TabSheetList erstellst du beim OnFormCreate ereignis deiner MainForm und trägst dort die liste gleich als property in die form mit ein unter public. beim erstellen gibst du dem objekt ja die PageControl die du auf deiner Form hast mit damit hast du in den objekten immer zugang zu dieser Pagecontrol auf der Form und kannst jetzt im hintergrund akkern. so und wie kommst du wenn du auf der form arbeitest immer zu deinen tabsheets? naja die mußt du dann suchen, jedes tabsheet hat doch einen namen was du auch in das tabsheetitem einbaust und danach durchsuchst du einfach die liste so hier zum beispiel als suchroutine für die liste wo du einfach den tabsheet namen mitgibst
Delphi-Quellcode:
so ich schreib jetzt oben noch schnell die tabsheet erstell routine in die liste und dann
function TabSheetList.GetTabSheetWithName(AName : string) : TTabSheetItem;
var ItemIndex : integer begin Result := nil; for ItemIndex := 0 to Pred(Count) do begin if CompareText(TTabSheetItem(Items[ItemIndex]).Name, AName) = 0 then begin Result := TTabSheetItem(Items[ItemIndex]); Break; end; end; end; hast du schon nen recht gut ausgerüstetes gerüst und hast gleich nen bissle objectorientierung gelernt. |
Re: Dynamischen Wizard realisieren
Vielen Dank erstmal für deine ausführliche Hilfe, ich denke, da kann ich mir einiges für mein Projekt herausziehen! Was ich noch nicht ganz verstanden habe, wobei ich mich im Vorfeld vielleicht auch etwas unklar ausgedrückt habe, ist: wie erreichst du durch deine TabSheet-Liste, dass man später wenn das Programm fertig ist, beliebig TabSheets hinzufügen oder entfernen kann, ohne erneut am Quellcode des Programmes etwas ändern zu müssen? Also wenn dir später einfallen sollte, du brauchst an dieser und jener Stelle noch zusätzliche TabSheets, dass du diese dann einbinden kannst (wie z.B. durch eine DLL) ohne das Programm erneut compilieren zu müssen. Ziel ist es eben, dem Kunden und Nutzer des Wizards, wenn dieser neue Funktionalität wünscht, ihm eine fertig compiliertes Zusatz-Modul in die Hand zu drücken, das er nur irgendwo ablegen muss (und wegen mir noch in irgendeiner ini-File was dazuschreiben), und der Wizard dann dieses Zusatzmodul automatisch lädt und einbindet, ohne dass man eben an IHM noch was ändern müsste. In welcher Form würdest du also in deinem Fall dem Benutzer deines Programms diese Zusatzfunktionalität zu Verfügung stellen?
|
Re: Dynamischen Wizard realisieren
naja an sich kann du in der liste doch eine routine deklarieren die dir nen tabsheet
zusammenbaut, nach bestimmten vorgaben. möglich wäre es z.B. das man einfach ne TXT mitgibt wo informationen über das tabsheet aussehen drin stehen. die dann von der routine umgesetzt werden. oder du braust frames die du der routine mitgibst welche diese nur auf das tabsheet setzt das es erstellt. bei mir ist es z.B. eine Typisierte Datei wo infos über die movieliste drin stehen. zB. [Doku] Name=Doku BackgroundColor=clMoneyGreen IconIndex=0 LettersColor=clBlack PWActive=0 ShowHead=1 ShowGrids=1 Visible=1 ich hab eine routine die heißt halt loadtabsheets(afilename : string); der gebe ich den dateinamen dieser typfile mit und dann baut der nen tabsheet auf dem ne listview ist mit bestimmten eigenschaften. du könntest [Name] //des tabsheets TLabel=Label1 Label1Width=xxx usw und dann läßte die routine das so zusammen bauen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:50 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