![]() |
Grid, Listview oder was auch immer nehmen
Hallo zusammen,
Ich hab ein kleines Tool, für die Anzeige von .CSV Inhalten. Das hat sich jetzt an ein paar tausend Datensätzen (nicht genügend Speicher) verschluckt. Ich bräuchte also eine möglichst (speicher)sparsame Anzeigekomponente oder müßte mir selbst etwas basteln. Was aber u.U. die Neuerfindung des Rades wäre. Könnt Ihr mir da etwas empfehlen? gruß K-H |
AW: Grid, Listview oder was auch immer nehmen
Hallo,
also das ganz normale TStringGrid sollte da keine Probleme haben bei "ein paar 1000 Einträgen". Sicher, dass die Anzeige des Problem ist, und nicht die Komponente, die die CSV-Datei lädt? Falls es doch klemmt, wäre dann noch das TDrawGrid. Wie hast Du es denn bisher gelöst? |
AW: Grid, Listview oder was auch immer nehmen
Unter groß kann man sich viel vorstellen. Eine CSV mit ca. 36000 Zeilen wird in ca. 300ms eingelesen und dann fix präsentiert.
(Kann man insgesamt auch schöner machen - aber für eine Demo reicht es ja)
Delphi-Quellcode:
und die Form
unit CsvViewer.Classes;
interface uses System.Classes, System.SysUtils, System.Generics.Collections, Data.DB, Datasnap.DBClient, Spring; // ACHTUNG! Spring4D wird benötigt! type TCsvContent = class( TList < TArray < string >> ) private FHeader: TArray<string>; FHasHeader: Boolean; public property Header: TArray<string> read FHeader write FHeader; property HasHeader: Boolean read FHasHeader write FHasHeader; end; TCsvReader = class public const DefaultBufferSize = 4096; DefaultDetectBOM = false; DefaultQuoteChar = Char( '"' ); DefaultSeparatorChar = Char( ',' ); private FQuoteChar: Char; FSeparatorChar: Char; FEncoding: TEncoding; FDetectBOM: Boolean; FBufferSize: Integer; FFirstRowContainsHeader: Boolean; public constructor Create; property BufferSize: Integer read FBufferSize write FBufferSize; property DetectBOM: Boolean read FDetectBOM write FDetectBOM; property Encoding: TEncoding read FEncoding write FEncoding; property FirstRowContainsHeader: Boolean read FFirstRowContainsHeader write FFirstRowContainsHeader; property QuoteChar: Char read FQuoteChar write FQuoteChar; property SeparatorChar: Char read FSeparatorChar write FSeparatorChar; function Read( const Filename: TFilename ): IShared<TCsvContent>; end; implementation { TCsvReader } constructor TCsvReader.Create; begin inherited; FBufferSize := DefaultBufferSize; FDetectBOM := DefaultDetectBOM; FEncoding := TEncoding.UTF8; FQuoteChar := DefaultQuoteChar; FSeparatorChar := DefaultSeparatorChar; end; function TCsvReader.Read( const Filename: TFilename ): IShared<TCsvContent>; var streamReader: IShared<TStreamReader>; line: string; stringList: IShared<TStringList>; firstRow: Boolean; I: Integer; Header: TArray<string>; function ReadNextLine( ): Boolean; var separatorCharCount: Integer; begin line := string.Empty; while not streamReader.EndOfStream do begin line := line + streamReader.ReadLine( ); separatorCharCount := line.CountChar( QuoteChar ); if separatorCharCount mod 2 = 0 then Exit( True ); end; Result := false; end; begin Result := Shared.New( TCsvContent.Create( ) ); streamReader := Shared.New( TStreamReader.Create( Filename, Encoding, DetectBOM, BufferSize ) ); stringList := Shared.New( TStringList.Create ); stringList.QuoteChar := QuoteChar; stringList.Delimiter := SeparatorChar; stringList.StrictDelimiter := True; firstRow := True; while ReadNextLine( ) do begin stringList.DelimitedText := line; if firstRow then try if FirstRowContainsHeader then begin Result.Header := stringList.ToStringArray( ); Result.HasHeader := True; Continue; end; finally firstRow := False; end; Result.Add( stringList.ToStringArray( ) ); end; end; end.
Delphi-Quellcode:
und die dfm zur Form
unit CsvCiewer.Forms.MainForm;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, System.Actions, System.ImageList, System.Diagnostics, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.ActnList, Vcl.StdActns, Vcl.ImgList, Vcl.ToolWin, Spring, CsvViewer.Classes; type TMainForm = class( TForm ) ListView1: TListView; ToolBar1: TToolBar; ToolButton1: TToolButton; ActionList1: TActionList; ImageList1: TImageList; FileOpen1: TFileOpen; StatusBar1: TStatusBar; procedure FileOpen1_Accept( Sender: TObject ); procedure ListView1_Data( Sender: TObject; Item: TListItem ); private FCsvReader: IShared<TCsvReader>; FCsvContent: IShared<TCsvContent>; public procedure AfterConstruction; override; end; var MainForm: TMainForm; implementation {$R *.dfm} { TMainForm } procedure TMainForm.AfterConstruction; begin inherited; FCsvReader := Shared.New( TCsvReader.Create ); FCsvReader.FirstRowContainsHeader := True; end; procedure TMainForm.FileOpen1_Accept( Sender: TObject ); var col: TListColumn; loadingStopwatch, presentingStopwatch: TStopwatch; begin loadingStopwatch := TStopwatch.StartNew( ); FCsvContent := FCsvReader.Read( FileOpen1.Dialog.FileName ); loadingStopwatch.Stop( ); presentingStopwatch := TStopwatch.StartNew(); ListView1.Items.BeginUpdate( ); try ListView1.Items.Count := 0; ListView1.Columns.Clear; while ListView1.Columns.Count < Length( FCsvContent.Items[0] ) do begin col := ListView1.Columns.Add; if FCsvContent.HasHeader then col.Caption := FCsvContent.Header[col.Index] else col.Caption := 'Field ' + ( col.Index + 1 ).ToString( ); end; ListView1.Items.Count := FCsvContent.Count; finally ListView1.Items.EndUpdate( ); end; presentingStopwatch.Stop(); StatusBar1.SimpleText := loadingStopwatch.ElapsedMilliseconds.ToString() + 'ms - '+presentingStopwatch.ElapsedMilliseconds.ToString()+'ms'; end; procedure TMainForm.ListView1_Data( Sender: TObject; Item: TListItem ); var rowData: TArray<string>; idx: Integer; begin rowData := FCsvContent.Items[Item.Index]; Item.Caption := rowData[0]; for idx := 1 to High( rowData ) do begin Item.SubItems.Add( rowData[idx] ); end; end; end.
Delphi-Quellcode:
object MainForm: TMainForm
Left = 0 Top = 0 Caption = 'MainForm' ClientHeight = 411 ClientWidth = 852 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 object ListView1: TListView Left = 0 Top = 29 Width = 852 Height = 363 Align = alClient Columns = <> OwnerData = True ReadOnly = True RowSelect = True TabOrder = 0 ViewStyle = vsReport OnData = ListView1_Data ExplicitTop = 35 ExplicitHeight = 382 end object ToolBar1: TToolBar Left = 0 Top = 0 Width = 852 Height = 29 Caption = 'ToolBar1' Images = ImageList1 TabOrder = 1 ExplicitLeft = 360 ExplicitTop = 208 ExplicitWidth = 150 object ToolButton1: TToolButton Left = 0 Top = 0 Action = FileOpen1 end end object StatusBar1: TStatusBar Left = 0 Top = 392 Width = 852 Height = 19 Panels = <> ExplicitLeft = 432 ExplicitTop = 216 ExplicitWidth = 0 end object ActionList1: TActionList Images = ImageList1 Left = 496 Top = 200 object FileOpen1: TFileOpen Category = 'File' Caption = #214'&ffnen...' Dialog.DefaultExt = '.csv' Dialog.Filter = 'CSV-Dateien (*.csv)|*.csv' Hint = #214'ffnen|Vorhandene Datei '#246'ffnen' ImageIndex = 0 ShortCut = 16463 OnAccept = FileOpen1_Accept end end object ImageList1: TImageList Left = 568 Top = 208 Bitmap = { 494C010101000500040010001000FFFFFFFFFF00FFFFFFFFFFFFFFFF424D3600 0000000000003600000028000000400000001000000001002000000000000010 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000008080000080 8000008080000080800000808000008080000080800000808000008080000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000FFFF00000000000080 8000008080000080800000808000008080000080800000808000008080000080 8000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FFFFFF0000FFFF000000 0000008080000080800000808000008080000080800000808000008080000080 8000008080000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000FFFF00FFFFFF0000FF FF00000000000080800000808000008080000080800000808000008080000080 8000008080000080800000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FFFFFF0000FFFF00FFFF FF0000FFFF000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000FFFF00FFFFFF0000FF FF00FFFFFF0000FFFF00FFFFFF0000FFFF00FFFFFF0000FFFF00000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FFFFFF0000FFFF00FFFF FF0000FFFF00FFFFFF0000FFFF00FFFFFF0000FFFF00FFFFFF00000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000FFFF00FFFFFF0000FF FF00000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000424D3E000000000000003E000000 2800000040000000100000000100010000000000800000000000000000000000 000000000000000000000000FFFFFF00FFFF000000000000FFFF000000000000 001F000000000000000F00000000000000070000000000000003000000000000 00010000000000000000000000000000001F000000000000001F000000000000 001F0000000000008FF1000000000000FFF9000000000000FF75000000000000 FF8F000000000000FFFF000000000000} end end |
AW: Grid, Listview oder was auch immer nehmen
@Schokohase
Danke für die Mühe aber da ich noch antik (D7) unterwegs bin, für mich wohl nicht umsetzbar. Zitat:
Zitat:
Da muß ich mich nochmal aufmachen und suchen. Zitat:
vielen Dank K-H |
AW: Grid, Listview oder was auch immer nehmen
![]() |
Dieses Thema wurde am "07. Nov 2018, 18:52 Uhr" von "Luckie" aus dem Forum "Sonstige Fragen zu Delphi" in das Forum "GUI-Design mit VCL / FireMonkey / Common Controls" verschoben.
|
AW: Grid, Listview oder was auch immer nehmen
@Redeemer
Danke für den Hinweis, jetzt hab ich sie auch gefunden. Ich muß die Mengenangabe etwas Korrigieren es sind 890.000 Datensätze mit netto ca 90 MB Dateigröße. Gruß K-H |
AW: Grid, Listview oder was auch immer nehmen
Wenn wirklich die Anzeige und nicht das Laden, Parsen etc. der Datei den Flaschenhals darstellt, könnte man mal den VST ins Auge fassen. Die Lernkurve ist zwar etwas steil und man muss auch vergleichsweise viel Code schreiben, dafür kann das Ding so ziemlich alles und ist pfeilschnell.
|
AW: Grid, Listview oder was auch immer nehmen
Unter Delphi 7 sollte die
Delphi-Quellcode:
auch den virtuellen Modus können (siehe
TListView
![]() Alles andere ist eigentlich überflüssig bzw. lässt sich auch ganz einfach nach Delphi 7 übertragen. Ich habe die vorliegende Datei einfach mal etwas dupliziert um so eine Datei mit ca. 890000 Zeilen und ca. 90MB zu erhalten. Braucht etwas mehr als 6 Sekunden zum Einlesen und 40 Millisekunden zum Anzeigen. Die Anwendung selber benötigt dabei ca. 540MB Speicher |
AW: Grid, Listview oder was auch immer nehmen
Zitat:
Bis jetzt hab ich versucht mir einen Überblick über TDrawGrid zu verschaffen. Schon interessant, daß ich bei den Jedis was dazu gefunden habe und in der D7-Hilfe und den Samples nichts konkretes zu finden ist. Es hat etwas gedauert, bis ich verstanden habe, daß VirtualStringTree Teil von VirtualTreeView ist. Aber jetzt hab ich auch die passende Version gefunden. Geschwindigkeit ist schön, aber ob es jetzt 2 oder 10 sec dauert bis ich eine Anzeige habe ist nicht so wichtig. Hauptsache ich habe alle Daten im Zugriff. Erst einmal allen die mir hier geholfen haben vielen Dank K-H |
AW: Grid, Listview oder was auch immer nehmen
[QUOTE=p80286;1417633]
Zitat:
Musst du wirklich 890.000 Datensätze visualisieren? Alle Daten im Zugriff zu haben, kann auch bedeuten, dass du die nur für die weitere Verarbeitung benötigst. In dem Fall gibt es geeignetere Komponenten. |
AW: Grid, Listview oder was auch immer nehmen
[QUOTE=Jasocul;1417636]
Zitat:
Auf den hab ich gewartet :mrgreen: "Zugriff" war das falsche Wort! Ich hol mal ein wenig aus. Ich hab auf meinem Rechner eine CSV-Datei mit einen etwas kryptischen Namen gefunden (TecoACDC.csv). Also hab ich diese erst einmal Open Office zum Fraß vorgeworfen, was sich prompt daran verschluckt hat (ja,es war eine ältere Version). Also hab ich aus meinem eigenen Fundus was heraus gekramt, das ich jetzt so gut es geht wetterfest machen will. Und ein einfaches "der Speicher reicht nicht" ist mir da zu wenig, vor allem wenn noch ein paar GB zur Verfügung stehen. Gruß K-H |
AW: Grid, Listview oder was auch immer nehmen
Zitat:
Wenn ich dafür sorge, dass bei einem gleichen String auch immer nur eine String-Referenz verwendet wird, dann sinkt bei meiner Test-Datei sogar der Speicherbedarf der Anwendung auf ca. 90MB. Die Zeit zum Einlesen erhöht sich allerdings dabei um ca. 30%. |
AW: Grid, Listview oder was auch immer nehmen
Ich habe selbst eine Anwendung, die ein paar 100.000 Zeilen darstellt. Das war in der Entwicklungsphase gut, um die Verarbeitung zu prüfen. Da es für mich ebenfalls keine Rolle spielt, wie lange die Verarbeitung dauert, habe ich das auch nie umgestellt.
Da ich bisher auch an keine Grenzen gestoßen bin, war ich zu faul, etwas zu ändern. Das ist aber bei dir anders. Deswegen musste ich den Klassiker loswerden. :wink: |
AW: Grid, Listview oder was auch immer nehmen
:thumb:
K-H |
AW: Grid, Listview oder was auch immer nehmen
890.000 Datensätze?
Und die müssen alle zusammen anzeigbar sein? Da wird scrollen zu einer bestimmten Position schon recht schwierig, irgendwie klingt das für mich nach einem falschen Ansatz! Ciao Stefan |
AW: Grid, Listview oder was auch immer nehmen
Delphi 7
ODBC-Treiber für CSV-Dateien auf das Verzeichnis mit Deiner Datei einrichten. TAdoConnection mit diesem Treiber verbinden Anzeige per TAdoTable -> TDataSource -> TDBGrid Eventuell geht auch: Anzeige per TAdoQuery -> TDataSource -> TDBGrid und Datenmenge per Select einschränken? |
AW: Grid, Listview oder was auch immer nehmen
Zitat:
Wenn von 890.000 Datensätzen die an einer bestimmten Position nicht da sind, dann wird das Scrollen zu der bestimmten Position sogar unmöglich. |
AW: Grid, Listview oder was auch immer nehmen
Was genau willst Du eigentlich mit der Anzeige erreichen?
Nur mal reinschauen, was in der Datei steht? ![]() Der zeigt Dir zumindest mal den Text komplett an, bietet aber weder Suchfunktionen noch Darstellung in Spalten. Der Source könnte evtl. in Delphi 7 compilieren, habe ich aber nicht überprüft. |
AW: Grid, Listview oder was auch immer nehmen
Aus meiner Sicht sollte es mit guten Controls technisch möglich sein, eine beliebige große Datenmenge an eine Listbox oder Grid zu binden.
Ob scrollen durch die Menge Sinn macht hängt von dem Anwendungsfall ab. Für einfache/temporäre Zwecke reicht das ggf. völlig aus. Für komfortable Anwendungen und Endnutzer sollte man komfortablere Optionen bereit stellen. Pauschalisieren würde ich das keinesfalls. @Schokohase Was meinst Du mit Deinem letzten Satz? |
AW: Grid, Listview oder was auch immer nehmen
Geht es um diese Datei?
![]() Zitat:
![]() Kommt auch mit großen Dateien zurecht und ist eigentlich immer recht schnell. Nehme ich in meinen Programmen zur Anzeige der Logfiles, von Protokollen ... Zeigt auch mehrere GB große Dateien binnen Sekundenfrist an. |
AW: Grid, Listview oder was auch immer nehmen
Zitat:
Damit ein beliebiger Datensatz durch Scrollen erreicht werden kann muss der Zugang zu jedem Datensatz auch möglich sein. Durch Weglassen geht das nicht. Als Reaktion auf: Zitat:
|
AW: Grid, Listview oder was auch immer nehmen
@Schokohase
Ich beziehe mich auf Virtualisierung. Wenn eine Datenmenge 1Mio Einträge hat und eine Listbox oder ein Grid z.B. 20 Einträge darstellen kann, dann soll sich das Control die Daten von 20 Datensätzen abholen und diese darstellen. Die Scrollbar soll allerdings für 1Mio Einträge bereitgestellt werden. Beim Scrollen zur Mitte muss das Control nur die 20 Einträge aus der Mitte der Datensätze zeichnen. Problematisch ist das nur, wenn die Einträge unterschiedliche Höhen haben können. Dann ist das mit pixelgenauem Scrollen über die Scrollbar etwas schwieriger. [PS: Ich hatte Dir kürzlich mal eine pm geschickt. Hattest Du die gesehen? Thematisch passt das auch hierzu. Bei Interesse schicke ich Dir mal was.] |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:29 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