![]() |
TObjectList sehr anfällig?
Versuche die TObjectList anstelle von Collection(VB) zu verwedenden.
Beim start der Anwendung wird ein Button erstellt der aber nicht in die TObjectList aufgenommen wird. Das ergebis ist dann ListIndex überschreitet das Maximum(1) Lasse ich den ersten Button weg und fange bei 0 an kommt die Meldung ListIndex überschreitet das Maximum(0) Langsam bekomme ich einen Anfall und frage mich ob es nicht besser wäre einfach ein normales Array zu verwenden. Ich dachte das es sinnvoll wäre da die Button während der Laufzeit auch wieder entfernt bzw.. ReOrganisiert werden müssen. FColButtons: TObjectList;
Delphi-Quellcode:
function TClsProgBar.Button(Btn: Integer): TClsButtonInfo;
var FSelButton: TObject; begin FSelButton := nil; try try // auch ein FColButtons.Items[Btn- 1]) führt zu einem EListError FSelButton := (FColButtons.Items[Btn]) as TClsButtonInfo; except // end; finally Result := TClsButtonInfo(FSelButton); end; end;
Delphi-Quellcode:
Bedingt durch den Fehler fehlen mir immer irgendwelche Button
function TClsProgBar.ReOrgDisplay(Ctrl: TClsControls; oInit: Bool): Bool;
var Width: Integer; Height: Integer; Btn: Integer; oButton: TClsButtonInfo; begin NewNumButtons := ButtonWidth * ButtonHeight; oButton := nil; // Lösche nicht benötigte Controls if NewNumButtons < FNumButtons then begin // lösche nichtverwendete Tasten, ausgenommen die erste for Btn := NewNumButtons + 1 to FNumButtons do Ctrl.RemoveButton(Btn); end; // lösche nichtverwendete einträge in der TObjectList if NewNumButtons < FColButtons.Count then // Lösche nicht benötigte Tasten, ausgenommen die erste for Btn := NewNumButtons + 1 to FNumButtons do RemoveButton(Btn); // erstelle neue Tasten wenn vorhanden Btn := 0; for Height := 1 to ButtonHeight do begin for Width := 1 to ButtonWidth do begin inc(Btn); if Btn > FNumButtons then Ctrl.AddButton(frmButtonHandle, Btn); Ctrl.PositionButton(Btn, Width, Height); if Btn > FColButtons.Count then begin try oButton := TClsButtonInfo.Create(nil); oButton.Num := Btn; AddButton(oButton); finally oButton := nil; end; end; end; // Width end; // Height // ButtonForm adjustieren Ctrl.Adjust(ButtonWidth, ButtonHeight); if oInit then begin // lösche die 1. Taste oButton := Button(1); if Assigned(oButton) then begin try oButton.BmpFile := ''; oButton.ButtonKey := ''; oButton.ToolTip := ''; oButton.ButtonCmd := ''; finally oButton := nil; end; end; // ProgBar-Properties zurücksetzen ClassNamen := ''; ProgPath := ''; ArbVerz := ''; ProgTitle := ''; ProgToolTips := ''; ProgTrayMenu := ''; Name := ''; FNumButtons := 1; end else FNumButtons := NewNumButtons; if Assigned(SelButton) then SelButton.Free; result := True; end; hier zum beispiel 2 .. sollten 8 sichtbar sein. gruss |
AW: TObjectList sehr anfällig?
Also eine TObjectList ist genauso anfällig wie ein Array, vor allem weil eine TObjectList ein gekapseltes Array ist. Und ein Griff neben die Kiste ( Index < 0 or Index >= Count ) würde auch bei einem Array Probleme geben.
Allerdings findet es eine TObjectList doof, wenn man eine Instanz in der Liste aus dem Speicher wirft, solange diese noch in selbiger verweilt. Aus deinem Code entnehme ich, dass du da die Buttons entfernst und erst dann die Liste bereinigst. Diese Organisation sehe ich als den kritischen Teil an. Denn in der TObjectList sind ja die Verweise auf die Instanzen noch enthalten und wenn OwnsObjects auf true, dann versucht die TObjectList beim Entfernen aus der Liste ein Free auf diese (vermeintlich noch existierende) Instanz. Evtl. ist da die Verantwortlichkeit (wer macht was wann) im Code nicht klar geregelt. Aber zur Beurteilung fehlt da der CodeTeil, der für den Eintrag und das Entfernen der Buttons. |
AW: TObjectList sehr anfällig?
Zitat:
Denn..
Delphi-Quellcode:
"ButtonWidth * ButtonHeight" = 1 * 1
NewNumButtons := ButtonWidth * ButtonHeight;
Da NewNumButtons in dem Fall 1 ist, also nicht weniger wie FColButtons.Count wird hier auch nichts gelöscht. Nachher mag das zutreffend sein dafür muss ich einfach nur die beiden abfragen vertauschen. Obwohl Ctrl.RemoveButton(Btn) nichts mit RemoveButton(Btn) zu tun hat. Zitat:
Delphi-Quellcode:
function TClsProgBar.AddButton(var oButton: TClsButtonInfo): Bool;
begin if ButtonExists(oButton.Num) then RemoveButton(oButton.Num); FColButtons.Add(oButton); FColButtons.Insert(oButton.Num, oButton); Result := True; end;
Delphi-Quellcode:
Beim ersten start kracht es schon (also EListError)
function TClsProgBar.ButtonExists(Btn: Integer): Bool;
begin FOButton := Button(Btn); Result := Assigned(FOButton); end; Notfalls kann ich den Source mal hochladen. gruss |
AW: TObjectList sehr anfällig?
Zitat:
Delphi-Quellcode:
der Button an die Liste angehängt und mit
FColButtons.Add(oButton);
Delphi-Quellcode:
nochmal an der Stelle oButton.Num eingefügt. Er befindet sich jetzt also zweimal in der Liste. Das bringt zumindest die Bedeutung von FColButtons.Count durcheinander.
FColButtons.Insert(oButton.Num, oButton);
|
AW: TObjectList sehr anfällig?
Das ButtonExists würde ich umschreiben oder das Button( Btn : Integer ).
Delphi-Quellcode:
Die genaue Codierung hängt allerdings davon ab, ob du 0 basierend indizierst (so wie die Liste) oder 1 basierend.
function TClsProgBar.ButtonExists( Btn : Integer ) : Bool;
begin Result := ( Btn >= 0 ) and ( Btn < FButtonList.Count ); end; |
AW: TObjectList sehr anfällig?
Zitat:
gruss |
AW: TObjectList sehr anfällig?
Das umschreiben der ButtonExists sorgt zumindest dafür das es zu keinen ElistError mehr kommt.
Wenn ich hingegen irgendeine Zeile von AddButton entferne dann kracht es wieder.
Delphi-Quellcode:
function TClsProgBar.AddButton(var oButton: TClsButtonInfo): Bool;
begin if ButtonExists(oButton.Num) then RemoveButton(oButton.Num); FColButtons.Add(oButton); // kann nicht entfernt werden FColButtons.Insert(oButton.Num, oButton); // Das auch nicht Result := True; end; Wirklich kompiliziert die Collection von VB nach Delphi zu portieren. Hier sind mal die VB Teile dazu.. mcolButtons = Collection und in Delphi halt die TObjectList.
Code:
Public Function AddButton(ByRef roButton As clsButtonInfo) As Boolean
If ButtonExists(roButton.Num) Then RemoveButton roButton.Num mcolButtons.Add roButton, CStr(roButton.Num) End Function
Code:
Public Property Get Button(ByVal vlBtn As Long) As clsButtonInfo
On Error Resume Next Set moSelButton = mcolButtons.Item(CStr(vlBtn)) Set Button = moSelButton Err.Clear End Property
Code:
Nur das ihr den Unterschied sehen könnt.
Private Function ButtonExists(ByVal vlBtn As Long) As Boolean
Dim oButton As clsButtonInfo Set oButton = Button(vlBtn) ButtonExists = CBool(Not oButton Is Nothing) End Function Sorry habe mich noch nie mit der ObjectList beschäftigt. Nebenbei: Es geht hier nicht um Copy/Paste Es ist ein Programm das ich 1999 in VB geschrieben habe was da auf der VB seite abgeht weiss ich und stellt kein problem dar. gruss |
AW: TObjectList sehr anfällig?
Zitat:
Der Code mit Add und Insert ist in jedem Fall falsch. Gib doch bitte mal den kompletten Code mitsamt ButtonExists uhnd RemoveButton, damit man mal den Überblick bekommt. |
AW: TObjectList sehr anfällig?
Zitat:
Da hier zu viele dinge zugehörig sind. Ich habe ihn so klein wie möglich gehalten zwei Skins müssen sein zum gegenprüfen. Die aktuell relevanten teile befinden sich in uProgBar Das ist eine Common Classe die später auch für ProgStart verwendet wird. gruss |
AW: TObjectList sehr anfällig?
Ein paar Dinge gleich nach dem ersten Duchsehen:
|
AW: TObjectList sehr anfällig?
Zitat:
Tja, die Collection in Delphi registriert sich bei ihren enthaltenen TComponents und auch andersrum. Sobald einer er Beteiligten freigegeben wird, wird die aufgebaute Verknüpfung aufgelöst und die Komponenten aus der Liste ausgetragen. Siehe meine Firemonkey-Hints. Da hab ich dieses auch endlich selber mal verwendet. Dort speichere ich mir ja in Variablen Zeiger auf die beteiligten Objekte. Um diese Variablen "sauber" zu halten und keine "tote" Verlinktungen zu erhalten, hab ich meine Ojekte ebenfalls entsprechend registriert und räume bei Benachrichtigung dann entsprechend meine Variablen auf. Wer es nicht schafft seine Verlinkungen sauberzuhalten und eindeutige Besitzverhältnisse sichzustellen (nur Einer darf etwas freigeben ... halt das Highlander-Prinzip "Es kann nur Einen geben") oder es so zu regeln, daß sich alle beteiligten Verantwortlichen untereinander informieren, der sollte besser auf Interfaces umsteigen oder auf andere Managed-Systeme. |
AW: TObjectList sehr anfällig?
Zitat:
|
AW: TObjectList sehr anfällig?
Zitat:
Nja, rückwärtslöschen ist einfacher, aber manchmal kommt es auf die Reihenfolge drauf an, wierum gelöscht wird. |
AW: TObjectList sehr anfällig?
Zitat:
Es scheint so das die ObjectListe damit nicht klar kommt wenn du sagst das ich unbedingt mit 0 anfangen muss. Es dürfte klar sein das wenn man Button zu einem Fenster zur Laufzeit addiert dann muss zumindest 1 vorhanden sein der auch nicht gelöscht werden darf. Dieser repräsentiert den Index 0; Ich habe versucht bei 0 anzufangen in dem ich einfach
Delphi-Quellcode:
FSelButton := (FColButtons.Items[Btn -1]) as TClsButtonInfo;
Btn -1 zugewiesen habe.. Aber auch das habe ich schon angemerkt dann meldet er mir das der ListIndex Maximum(0) überschritten wäre. Fange ich bei eins an meckert er das ListIndex Maximum(1) überschritten ist. Da hab ich noch was zu tun ;) Zitat:
In der Collection VB seite spielte das keine rolle. Danke für die überprüfung. gruss |
AW: TObjectList sehr anfällig?
Das addieren geht jetzt grundsätzlich schon mal
Muss jetzt nur noch das problem mit dem entfernen Korrigieren. Hab da mit der Liste noch nicht den richtigen ansatz gefunden. Habe da mal temporär die Indexes der Button als Caption addiert. gruss |
AW: TObjectList sehr anfällig?
Wäre es nicht näher dran, wenn du statt TObjectList eine eigene
![]() |
AW: TObjectList sehr anfällig?
Zitat:
Beispiel: Bei Add. Da kann man ja nicht groß was übergeben. TObjectList
Delphi-Quellcode:
TCollection:
FColButtons.Add(oButton);
FColButtons.Insert(oButton.Num, oButton);
Delphi-Quellcode:
function Add:
Wie soll ich hier die Classe TClsButtonInfo übergeben? Die ObjektList kam der Collection von VB am nächsten. gruss |
AW: TObjectList sehr anfällig?
Zitat:
Vieles an deinem Code ist offensichtlich aus dem VB Programm übernommen - insofern würde man viele Dinge heute in Delphi von vornherein anders machen. Die implizite Verbindung von TClsButtonInfo.Num zum Index in FColButtons (ob nun -1 oder nicht) bringt m.E. einen überflüssigen Overhead in die Implementation. Ich vermute dort die meisten Macken. |
AW: TObjectList sehr anfällig?
Zitat:
Denke auch wenn ich das heute direkt in Delphi also neu schreiben würde sähe es auch etwas anders aus. Das wäre mir aber dann doch zuviel des guten zumal da ich es schon einmal geschrieben habe. Zitat:
Das mit dem addieren funktioniert jetzt ohne Probleme wie am am Shot erkennen kann. Das entfernen werde ich dann auch noch schaffen. Der vorteil an der ProgBar Klasse ist halt das ich die nur einmal erstellen muss diese wird ja dann von zwei Unterschiedlichen Programmen verwendet. Genauso wie die Klasse ButtonInfo da hab ich mir schon einiges an Arbeit gespart. Das hier ist ja nur das Konfigurations Programm für die Button Das eigentliche Programm ProgStart startet dann die Programme für die von ProgBar erstellten ToolBars. Der sinn und zweck des programms war Hauptsächlich den Desktop sauber zu halten und Programme zu steuern die früher keine eigene ToolBars enthielten so wie NotePad. Aber grundsätzlich ist es schon richtig das man so ein Projekt eigentlich komplett neu aufsetzen sollte. Aber wie schon gesagt zu viel des guten. gruss |
AW: TObjectList sehr anfällig?
oops .. vergessen zu Antworten
Zitat:
Zitat:
Aber es geht um Nonvcl da zählen einige deiner guten Ratschläge leider nicht. Ansonsten würde ich sie verwenden.. kannst mir glauben ;) gruss |
AW: TObjectList sehr anfällig?
Zitat:
|
AW: TObjectList sehr anfällig?
Scheinbar hat hier oButton.Num nichts mit dem Index in der TObjectlist zu tun.
Ursache kann z.B. sein, das die Buttons nicht vollständig, doppelt oder nicht in der richtigen Reihenfolge eingefügt oder nach dem Einfügen nicht sortiert werden. Also sollte man den Index unberücksichtigt lassen, statt dessen nach dem richtigen Button suchen:
Delphi-Quellcode:
Wichtig ist:
type
TMyColButtons = class(TObjectList) private function GetButton(ANum: Integer): TClsButtonInfo; public procedure Add(AButton: TClsButtonInfo); procedure Remove(ANum: Integer); property Button[ANum: Integer]: TClsButtonInfo read GetButton; default; end; function TMyColButtons.GetButton(ANum: Integer): TClsButtonInfo; var i: Integer; begin for i := 0 to Count - 1 do begin Result := TClsButtonInfo(Items[i]); if Result.Num = ANum then Exit; end; Result := nil; end; procedure TMyColButtons.Add(AButton: TClsButtonInfo); begin Remove(AButton.Num); inherited Add(AButton); end; procedure TMyColButtons.Remove(ANum: Integer); var oButton: TClsButtonInfo; begin oButton := Button[ANum]; if Assigned(oButton) then inherited Remove(oButton); end; Wenn ein Button gelöscht werden soll, muss er aus der Liste entfernt werden, bevor er freigegeben wird. |
AW: TObjectList sehr anfällig?
Ahh hab diesbezüglich auch schon Fehler gefunden.
Beim klick auf einen Button werden mir nur ungerade Button korrekt zurückgeliefert. Vielleicht behebt dein Code das problem direkt mit. Werde es mal testen. PS: Ja leider geht nicht alles da VBCollection doch anderes gehandhabt werden. Danke. gruss |
AW: TObjectList sehr anfällig?
Hab mir deinen Code nochmal durchgesehen er hilft mir leider nicht weiter
Trotzdem nochmal Danke. Zitat:
Die gesamten eigenschaften der Classen oder nur der Index des aktuell addierten Button. gruss |
AW: TObjectList sehr anfällig?
In einer TObjectList werden die Instanzen abgelegt, Du hast also vollen Zugriff auf alle Eigenschaften und Methoden der jeweiligen Instanz. Wenn es sich nicht um eine spezialisierte Ableitung bzw. eine generische TObjectList handelt, musst Du diese aber vorher noch auf den entsprechenden Typen casten.
|
AW: TObjectList sehr anfällig?
Zitat:
oButton.Num oButton.BmpFile oButton.ButtonKey oButton.ToolTip oButton.ButtonCmd beispiel für button 1 im feld 0 gespeichert sein? Also der Counter macht mir ärger. Der dritte button wird einfach nicht addiert in die ObjectList
Delphi-Quellcode:
Die ersten beiden werden ordnungsgemäß addiert
if Btn > FColButtons.Count - 1 then
begin try oButton := TClsButtonInfo.Create(nil); oButton.Num := Btn; AddButton(oButton); finally oButton := nil; end; end; aber beim dritten ist der Count immer noch 2 obwohl er eigentlich 3 sein müßte. Die probleme nehmen einfach kein ende mit der Liste ;) Sternchen für OK! 1*, 2* 3, 4*, 5, 6*, 7, 8* Was ist mit den anderen die werden einfach nicht addiert. Der FColButtons.Count erhöht sich nicht nach dem addieren des 2,4,6 usw.. gruss |
AW: TObjectList sehr anfällig?
Wofür braucht du überhaupt die Property "Num"? Die erscheint mir eher redundant, und gerade wenn sie mit dem Index in der Liste immer übereinstimmen muss, auch aufwändig zu pflegen (Man müsste nach jedem Insert in die Liste ggf. alle Buttons anpassen).
Soweit ich deinen (zugegebenermaßen recht eigentümlichen) Code verstehe, willst du doch nicht mehr, als einfach alle Buttons in eine ungeordnete Sammlug werfen. Dann kannst du die doch einfach in die Liste Adden, der Index (also "Num") ergibt sich dann ohnehin nachher implizit über seine Position in der Liste. Warum das gehuddel? Eine Liste speichert ansonten immer auch nur Referenzen auf Objekte.
Delphi-Quellcode:
var
myInstance: TMyClass; aList: TObjectList; begin aList := TObjectList.Create; myInstance := TMyClass.Create; aList.Add(myInstance); // Folgende Zugriffe sind dann vollständig identisch: myInstance.SomeProperty := 'Foo'; TMyClass(aList[0]).SomeProperty := 'Foo'; end; |
AW: TObjectList sehr anfällig?
Darf ich mal ganz doof fragen, was Btn eigentlich ist bzw. welchen Zweck sie erfüllen soll?
|
AW: TObjectList sehr anfällig?
Zitat:
Und ist der index des aktuellen Button. gruss |
AW: TObjectList sehr anfällig?
Also wenn das eine Instanz ist, könntest Du mit IndexOf(Btn) den Index erfragen.
|
AW: TObjectList sehr anfällig?
Zitat:
Anstatt mich weiter durch dieses Durcheinander zu hangeln, hätte ich das schon längst neu gemacht. |
AW: TObjectList sehr anfällig?
Zitat:
Zitat:
Wenn ich da nicht für mich in verbindung mit der Objectlist eine praktikable lösung finde bleibt mir nichts anderes übrig. Es macht keinen sinn auf einige Themen einzugehen solange diese Leute den kompletten Quelltext nicht gesehen haben. Da du dir den ja angesehen hast kennst du ja die probleme. Es ist einfach so das die Listen egal VB Collection/Delhi ObjectList nicht annährend kompatibel sind. Muss mich mit dem Teil nochmal speziell beschäftigen. Na ja hab noch genug zu tun kann mich mit dem Thema zur gegebenen Zeit nochmal auseinander setzen. Danke an alle die mir mit Ratschlägen weiterhelfen wollten/haben. gruss |
AW: TObjectList sehr anfällig?
Nur für die Leute die meinen ich brauche das oButton.Num nicht.
Delphi-Quellcode:
Was macht es für einen sinn den Index des Button aus der Objectlist zu verwenden.
WM_RBUTTONDOWN:
begin case LoWord(wP) of // Button steuerung ID_BTN_BUTTON_FIRST..ID_BTN_BUTTON_LAST: begin oButton := goProgBar.Button(wp-ID_BTN_BUTTON_FIRST); If not Assigned(oButton) then begin Result := 0; Exit; end; if frmKeysHandle = 0 then frmKeysCreate(frmButtonHandle); EnableWindow(frmButtonHandle, False); edKeys.SetWindowText(edKeys.Handle, PWideChar(oButton.ButtonKey)); edTooltips.SetWindowText(edTooltips.Handle, PWideChar(oButton.ToolTip)); edCommand.SetWindowText(edCommand.Handle, PWideChar(oButton.ButtonCmd)); SKAERO_SetCTLText(lblKeyCaption.Handle, 'Knopf' + IntToStr(oButton.Num)); end; end; end; Aber ist ja alles redundant ;) gruss |
AW: TObjectList sehr anfällig?
Emil, dein Design ist einfach dermaßen unübersichtlich und wuschig (ja, auch wenn der Code direkt vor einem sitzt), dass es sich einem nicht unbedingt intuitiv erschließt was für Loopings und Korkenzieher deine Hirnwindungen dabei gemacht haben. Für DICH mag das alles sonnenklar sein, aber dein Code ist halt mal alles andere als selbstdokumentierend. Und selbst mit Beschreibungen sind deine Lösungen noch immer eher ... kurios. Nicht jeder hat die Zeit und Muße sich auch in die unorthodoxesten Dinge einzulesen, manch einer hat aber dennoch den guten Willen und eine Idee um ggf. hilfreich zu sein. Lass deinen Sarkasmus also bitte weg, und schmetter nicht jeden Designvorschlag damit ab, dass das alles ja so sein muss. Abgesehen davon, dass das einfach nicht stimmt, ist es auch eine recht unsympathische Haltung.
Das alles hier, trotz der Gewissheit, dass es wie nicht selten bei an sich mitunter sehr gut gemeinten Tipps und Nachfragen, mit unterschweliger Überheblichkeit des "Pragmatikers über den Akademiker" abgetan wird. Aber du merkst doch selber, dass du dich in deinem Zeug verzettelt hast, und nicht mehr nachvollziehen kannst, was wann wo warum passiert. Das IST ein Designproblem (und nicht nur auf diesen Thread bezogen), und mit kleinschrittigen Lösungen bis "es zumindest kompiliert und ggf. auch zur Runtime keine Fehler wirft" kommst du aus der Nummer sehr wahrscheinlich nicht heraus. Aber ist ja alles nur abfälliges Gefasel, weil du als armes VB Opfer ja nichts dafür kannst. Sorry, aber der Seitenhieb war langsam angebracht. Auch eine Vergangenheit mit VB ist kein Grund, es nicht doch besser machen zu können. (Ich hab ja selber mit QBasic lange Jahre gelernt.) |
AW: TObjectList sehr anfällig?
Geschmacksache!
Ansonsten Daumen runter. Zu dumm irgend etwas davon zu zitieren oder Kommentare drüber abzugeben. gruss |
AW: TObjectList sehr anfällig?
Genau das meinte ich. Viel Erfolg dennoch.
|
AW: TObjectList sehr anfällig?
Zitat:
gruss |
AW: TObjectList sehr anfällig?
Hört uff mit dem Kinderkram.
Also: Was möchtest Du mit der Liste anstellen? Baue Dir eine Klasse 'ButtonList', die genau die Methoden zur Verfügung stellt, die Du benötigst. Wer soll die Button-Instanzen freigeben? Die Buttonliste? Dann verwende als Basis eine TObjectList. Wenn nicht, reicht auch eine TList oder von mir aus ein Array. Erstelle dann eine Testumgebung, die die einzelnen Methoden deiner Buttonliste testet. Läuft der Test durch? Ok. Schmeiss die Testumgebung bloss nicht weg. Nun hast Du dir ein Werkzeug 'Buttonliste' gebaut, mit dem Du dein Problem viel einfacher lösen kannst. Nebenbei verwenden Handwerker individuell hergestellte Werkzeuge, um ihre Probleme zu lösen. Beispielsweise Tischler, die z.B. Schablonen herstellen, um Zapfen identische Abstände zu verpassen etc. Die Kreide, die Du gerade fressen musst, hat JEDER hier im Forum, der meint, programmieren zu können, auch schon durchgekaut. Bei einem gings schneller, beim anderen nicht. Egal. |
AW: TObjectList sehr anfällig?
Zitat:
Von daher habe ich alle Zeit der Welt, von der, die mir noch bleibt. :lol: gruss |
AW: TObjectList sehr anfällig?
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:26 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