:: Home :: Sitemap :: Downloads :: Shop :: Impressum :: Newsletter |
||
Support |
:: NEWS ::
NShape 2.3.0 wurde veröffentlicht mit Unterstützung von eingebetteten
Bildern in NShape-Dateien, Verschieben von Diagrammen per Maus, einer
deutlichen Erhöhung der Anzahl verfügbarer Layer und vielen weiteren
Funktionen und Verbesserungen. Die Liste aller Änderungen finden Sie
hier... |
|
Kylix und der dritte WegLinux-Anwendungen legen ihre persistenten Daten für gewöhnlich entweder in einfachen Dateien oder in Datenbank-Servern ab. Was Aufwand und Leistungsfähigkeit betrifft, stellen diese Alternativen in einem großen Spektrum an technischen Möglichkeiten die Extremfälle dar. Dazwischen liegt unter anderem die Option der Datei-basierten relationalen Datenbank, die gerade für Kylix-Entwickler sehr interessant ist. Dieser Artikel erklärt die Grundlagen und demonstriert sie anhand eines voll funktionsfähigen Datenbank-basierten E-Mail-Clients. Was bedeutet im Zusammenhang mit Datenbanken das Wort Datei-basiert? Speichern Datenbank-Server ihre Daten denn nicht in Dateien? Selbstverständlich tun sie das und insofern ist diese Bezeichnung etwas irreführend. Gemeint ist, dass bei dieser Art von Datenbanken jeder Client direkt auf die Datenbank-Dateien zugreift. Dem gegenüber öffnet ein Datenbank-Server nur selbst die Files und kommuniziert mit den Clients dann z.B. über Sockets.
Bei Datei-basierten Datenbanken greifen alle Client-Applikationen direkt auf die Datenbank-Dateien zu.
Datenbank-Server sind eigenständige Prozesse, öffnen die Datenbank-Dateien exklusiv und beantworten Anfragen über Sockets. Direkter DateizugriffDieser Ansatz birgt zunächst einmal eine Reihe von Vorteilen. Vor allem ist damit die Erstellung und Auslieferung von Datenbank-basierten Anwendungen extrem einfach. Die Datenbank-Funktionen werden eingebunden und aufgerufen. Nach dem Übersetzen ergibt sich eine einzige ausführbare Datei. Das bedeutet, dass der Einsatz einer Datenbank für den Endanwender völlig transparent ist. Er braucht weder zu wissen, welche Datenbank verwendet wird, noch dass überhaupt eine eingesetzt wurde. Vor allem ist wie bei der Ablage in flachen Dateien beim Anwender keine Pflege der Datenbank erforderlich. Diese Vorteile machen Datei-basierte Datenbanken zur idealen Lösung für Desktop-Applikationen. Deshalb werden sie häufig auch als Desktop-Datenbanken bezeichnet. Ein weiterer Vorteil dieser Datenbank-Kategorie besteht darin, dass sie Index-sequentiellen Zugriff erlauben. Das bedeutet, dass die Datenbank-Bibliothek neben den mengenorientierten Abfragen auch Funktionen nach dem Muster GetFirstRecord, GetNextRecord, GetPriorRecord und GetLastRecord anbietet, mit denen sich das Anwendunsprogramm mit Hilfe eines zuvor gesetzten Index durch die Datensätze "hangelt". Diese Vorgehensweise fällt vielen Entwicklern leichter als das mengenorientierte Konzept bei SQL. Natürlich bring diese Einfachheit auch einige Schattenseiten mit sich. Dateibasierte-Datenbanken haben zwei Nachteile, die in der Konsequenz dazu führen, dass sie für Applikationen für mehr als zehn Benutzer nicht geeignet sind. Zum einen ist da die tendenzmäßig höhere Netzwerklast. Da die Clients ihre Abfragen selbst bearbeiten, werden alle dazu benötigten Seiten über das Netzwerk transportiert. Im schlimmsten Fall (der allerdings praktisch nicht vorkommt), liest ein Client 1.000.000 Datensätze à 100 kB über das Netzwerk in seinen eigenen Speicher, um schließlich einen einzigen auszuwählen und anzuzeigen. Dieser Extremfall wäre zwar ein krasser Design-Fehler bei der Entwicklung und wird normalerweise durch die Verwendung von Indexen vermieden bzw. zumindest drastisch reduziert. Aber er demonstriert das Problem. Der zweite Nachteil hat mit der Koordination der gleichzeitigen Zugriffe auf die Datenbank-Dateien zu tun. Diese Dateien werden ja von allen Clients geöffnet, gelesen und beschrieben. Damit nicht zwei Client gleichzeitig den selben Datensatz mit unterschiedlichen Werten beschreiben und damit zerstören, muss mit Datei- und Satzsperren gearbeitet werden. Diese verlangsamen den Datei-Zugriff und begrenzen so die Anzahl der Clients, die vernünftigerweise gleichzeitig auf die Datenbank zugreifen können. Gleichzeitig sind die Dateisperren der Grund, warum Datei-basierte Datenbanken sich anders als unter Windows für Linux bisher nicht durchsetzen konnten. Rechner-übergreifendes File Locking war lange Zeit nicht möglich und funktioniert erst mit den neuesten kernel lock daemons. Trotz dieser beiden Minuspunkte, haben Datei-basierte Datenbanken ihre Berechtigung in Anwendungen mit kleinen bis mittelgroßen Datenbeständen (bis ca. 10 MB pro Tabelle ohne Blobs) für Arbeitsgruppen bis ca. zehn Mitglieder. In etlichen Fällen ist eine Datei-basierte Datenbank sogar die ideale Lösung, wie in den folgenden Szenarien gezeigt wird. Einsatz-SzenarienSzenario 1: E-Mail Client Szenario 2: Reifen-Katalog auf CD Szenario 3: Kassen-Programm Szenario 4: Portierung einer Windows-Applikation Kylix Datenbank-KomponentenWenn wie in Kylix Komponenten-basiert entwickelt wird, ergibt sich noch ein zusätzlicher Aspekt für die Verwendung einer Datei-basierten Datenbank gegenüber einfachen flat files. Die Schnittstelle für den Datenbank-Zugriff ist in Form der Basis-Klasse TDataSet standardisiert. Diese Komponente kann sowohl die Ergebnismenge einer Abfrage aufnehmen als auch einen direkten Zugriff auf eine Datenbank-Tabelle gewährleisten. Sie enthält unter anderem Methoden für die Navigation (First, Last, Prior, Next) und für den komfortablen Zugriff auf die einzelnen Felder eines Records. Auf diese Schnittstelle setzen eine Vielzahl von weiteren Komponenten auf, die als data-aware bezeichnet werden. Dabei handelt es sich einerseits um Controls zur Darstellung der Satzmenge in Form von Eingabefeldern, Listen oder Tabellen und andererseits um Komponenten für die Manipulation von Daten z.B. zur Berichterstellung oder zur Konvertierung aus und in eine Vielzahl von Formaten. Deshalb bedeutet die Datenablage in einer solchen Datenbank-Komponente nicht nur weniger Kodierungs-Aufwand, höhere Performanz und größere Leistungsfähigkeit. Darüberhinaus erschließt sie sofort eine Vielfalt an möglichen Zusatzfunktionen, die in Form der Daten-sensiblen Komponenten verfügbar sind. Im folgenden Abschnitt wird der geschilderte Sachverhalt anhand eines einfachen E-Mail-Clients namens TurboMail demonstriert. Diese Anwendung setzt massiv auf Wiederverwendung durch vorhandene Komponenten und greift dazu in der Hauptsache auf die Indy-Komponenten für die Kommunikation mit dem Mail-Server und die TurboDB-Komponenten für den Datenbank-Zugriff zu. Während die Indy-Komponenten mit Kylix mitgeliefert werden, handelt es sich bei den TurboDB-Komponenten um ein Produkt des Borland Development Partners dataweb GmbH aus Aicha bei Passau. Diese Datenbank-Komponenten unterstützen in etwa den selben Funktionsumfang wie die Borland Database Engine mit dBase-Dateien unter Windows, sind aber als bisher einzige Datenbank-Komponenten-Sammlung für Kylix und Delphi gleichermaßen verfügbar. Damit würde unser E-Mail-Client auch sofort für Windows übersetzbar sein. Eine für das Beispielprogramm ausreichende Demo-Version können Sie auf der Produkt-Web-Site der Firma herunterladen (http://www.turbodb.de/linuxenterprise/). Die gezeigten Konzepte und der gesamte Quelltext würden auch für andere Datei-basierte Kylix-Datenbank funktionieren (und tun es unter Windows auch). Ein Mail-Client für VielschreiberUm das Beispiel einfach zu halten, legen wir die E-Mails in einer einzigen Tabelle mit dem Namen EMails ab. Sie erhält die Spalten Betreff, Absender, Empfänger, Text, Datum und Ordner. (Als deutsches Datenbank-Produkt kann TurboDB Umlaute in Feldnamen verarbeiten.)
Die E-Mail-Tabelle wird mit TurboDB Viewer angelegt. Als Typ für das Datum wird DateTime gewählt, damit das Feld auch die Uhrzeit speichern kann. Inhalt muss auch längere Texte aufnehmen können und erhält deswegen den Typ Memo, was in SQL einem textuellen BLOB entspricht. Die Spalte Ordner enthält den Namen des Ordners, in den die E-Mail gehört. Alle Operationen werden im Hilfsprogramm TurboDB Viewer ausgeführt, das nach erfolgreicher Installation der Komponenten in der IDE unter Tools zu finden ist. Als Typ für das Datum wird DateTime gewählt, damit das Feld auch die Uhrzeit speichern kann. Inhalt muss auch längere Texte aufnehmen können und erhält deswegen den Typ Memo, was in SQL einem textuellen BLOB entspricht. Die Spalte Ordner enthält den Namen des Ordners, in den die E-Mail gehört. Alle Operationen werden im Hilfsprogramm TurboDB Viewer ausgeführt, das nach erfolgreicher Installation der Komponenten in der IDE unter Tools zu finden ist. Damit in der fertigen Anwendung eine schnelle Sortierung möglich ist, legt man ebenfalls im TurboDBViewer unter Table/Indexes... fünf Indexe an: EMailBetreff mit den Feldern Betreff und Datum, EMailAbsender mit den Feldern Absender und Datum, EMailEmpfänger mit den Feldern Empfänger und Datum sowie EMailDatum mit Datum als einzigem Feld.
Im TurboDB Viewer werden die Indexe zur schnellen Sortierung der E-Mails angelegt. Nun stellen wir die benötigten Komponenten für die Oberfläche zusammen. Die Anwendung soll ähnlich wie bei Netscape oder KMail links eine Liste der Ordner anzeigen, daneben eine Liste der E-Mails und darunter die ausführlichen Angaben zum selektierten Eintrag. Diese Oberfläche besteht aus einem TreeView namen FolderTreeView für die Ordner, einem DBGrid genannt EMailDBGrid für die Liste der E-Mails und einem Bereich für die Detailinformationen. Dieser Bereich wird als Panel realisiert und erhält den Namen DetailsPanel. Das DBGrid und das DetailsPanel liegen gemeinsam wiederum auf einem zweiten Panel namens MainPanel, damit das Layout wie gewünscht funktioniert. Zwischen dem TreeView und dem MainPanel wird ein Splitter eingefügt, damit man die Breite der Ordnerliste einstellen kann. Ebenso zwischen dem DBGrid und dem DetailsPanel. Das DetailsPanel nimmt DBEdit-Elemente für Absender, Empfänger und Betreff auf sowie ein DBMemo für den Text der E-Mail.
Die Oberfläche von TurboMail wird ohne eine Zeile Programmcode zusammengestellt. Zum Anschluss der Daten-sensiblen Steuerelemente wird eine TdbTable-Komponente und eine DataSource benötigt. Die Eigenschaft DatabaseName der Datenbank-Tabelle wird auf das Verzeichnis der Tabelle gerichtet und die Eigenschaft TableName erhält den Wert EMails. Die DataSource wird mit der Tabelle verknüpft (Eigenschaft DataSet) und alle Daten-sensiblen Komponenten, also das DBGrid, die drei DBEdit-Elemente und das DBMemo mit der DataSource. Bei den Detail-Elementen muss man dann noch die Feldnamen korrekt setzen. Durch Doppelklick auf die TreeView-Komponente kann man die vorgegebenen Ordner eintragen: inbox, archive, outbox, sent-mail und trash. Für die Datenbank-Tabelle erzeugt man durch Doppelklick und die Funktion Add All Fields alle Datenbankfelder, die in der Tabelle vorhanden sind als Komponenten im Formular. Für das DBGrid werden nun die Spalten definiert, indem man auch hier mit Doppelklick den Komponenten-Editor öffnet. Für eine schnelle Übersicht genügen Betreff, Absender, Empfänger und Datum. Die Breiten dieser Spalten werden mit der Eigenschaft Width passend eingestellt. Eine einfache MainMenu-Komponente soll die notwendigen Befehle aufnehmen. Auch dieser Editor wird mit einem Doppelklick auf die Komponente geöffnet. Die Menüpunkte sind an KMail angelehnt und heißen: File/Check Mail, File/Send Queued, File/Close, Edit/Delete, View/Sort By, Folder/Empty, Message/New Message und Message/Move To. Move To erhält fünf Unterpunkten entsprechend den Ordner-Namen.
Der Menüeditor in Aktion. Zu sehen sind alle Hauptmenüeinträge sowie die Untermenüs für den Befehl Move To mit allen Eigenschaften im Objekt-Inspektor. Wenn der Anwender einen Ordner im Ordnerbaum selektiert, soll die Anzeige der E-Mail-Liste auf die Mails aus dem entsprechenden Ordner beschränkt werden. Dies erreicht man durch Setzen eines passenden Filters in der Methode SwitchToFolder. Hier wird zuerst der Filter ausgeschaltet, dann ein neuer Filter gesetzt und schließlich der Filter wieder aktiviert. Damit es am Bildschirm nicht allzu stark flackert, sind diese Anweisung durch das Pärchen EnableControls und DisableControls eingeschlossen. procedure TMainForm.SwitchToFolder(const FolderName: string); begin EMailTable.DisableControls; EMailTable.Filtered := False; EMailTable.Filter := Format('Ordner = "%s"', [FolderName]); EMailTable.Filtered := True; EMailTable.EnableControls; end; Diese Methode wird im Handler für das OnChange-Ereignis des TreeViews aufgerufen, um die Selektion der Ordner zu realisieren. procedure TMainForm.FolderTreeViewChange(Sender: TObject; Node: TTreeNode); begin SwitchToFolder(Node.Text); end; Wenn der Anwender eine neue Mail schreiben möchte, wird ein Datensatz an die Tabelle angefügt und als Ordnername outbox eingetragen. Für den Absender nimmt das Beispiel einen festen Wert an, der in einer echten Anwendung aus den Einstellungen übernommen würde. Als Datum der Mail wird der aktuelle Zeitpunkt verwendet. Prinzipiell wird der Zugriff auf die Datenbankfelder über die Feld-Komponenten (EMailTableOrdner, EMailTableDatum usw.) abgewickelt und nicht über die Items-Liste, weil auf diese Weise Schwierigkeiten mit der Konvertierung von Varianten vermieden werden. procedure TMainForm.NewMessageClick(Sender: TObject); begin FolderTreeView.Selected := FolderTreeView.Items[1]; FolderTreeViewChanged(FolderTreeView, FolderTreeView.Selected); EMailTable.Append; EMailTableOrdner.AsString := 'outbox'; EMailTableAbsender.AsString := 'gaby@mustermann.de'; EMailTableDatum.AsDateTime := Now; end; Der neuen Datensatz wird zwar angelegt (EMailTable.Append) aber nicht abgeschickt, weil Empfänger, Betreff und Text noch einzutragen sind. Den nötigen Aufruf von EMailTable.Post setzt das DBGrid automatisch ab, wenn eine andere Mail ausgewählt wird. Die ersten beiden Zeilen der Methode schalten die Ansicht auf die outbox um. (Das ist der zweite Eintrag im Baum.) Zugriff auf den Mail-ServerZum Senden der E-Mails greift TurboMail auf die mitgelieferten Indy-Komponenten zu. IdMessage repräsentiert eine E-Mail und IdSMTP den SMTP-Client. Letzterer benötigt Grundeinstellungen für Host, UserId und Password, die entsprechend dem verwendeten Mail-Server gesetzt werden. Der Befehl File/Send Queued ist leicht zu realisieren, da die Komponenten mit der Methode Send einen denkbar einfachen Zugriff bietet. Zuvor werden die Eigenschaften der E-Mail-Komponente mit den entsprechenden Werten aus der Datenbank belegt. procedure TMainForm.SendQueuedClick(Sender: TObject); begin SwitchToFolder('outbox'); Smtp.Connect; try EMailTable.First; while not EMailTable.EOF do begin // Daten aus Tabelle in IdMessage-Komponente schreiben EMail.Clear; EMail.Subject := EMailTableBetreff.AsString; EMail.Date := EMailTableDatum.AsDateTime; EMail.Recipients.Add.Address := EMailTableEmpfaenger.AsString; EMail.From.Address := EMailTableAbsender.AsString; EMail.Body.Text := EMailTableText.AsString; Smtp.Send(EMail); // E-Mail als gesendet kennzeichnen EMailTable.Edit; EMailTableOrdner.AsString := 'sent-mails'; EMailTable.Post; EMailTable.Next; end; finally // Bei Problemen trotzdem vom Server abmelden Smtp.Disconnect; end; // Ansicht aktualisieren, outbox muss leer sein EMailTable.Filtered := False; EMailTable.Filtered := True; end; Erfolgreich abgesendete E-Mails werden automatisch in den ordner sent-mails verschoben. Das Abmelden vom SMTP-Server steht in einem finally-Block, man weiß ja nie... Wenn alles gutgegangen ist, liegen jetzt einige Test-Mails auf dem Server und warten auf Abholung. Der dazu nötige POP3-Client befindet sich ebenfalls in der Indy-Komponenten-Palette und benötigt wie der SMTP-Client Angaben für Host, UserId und Password. Empfangene E-Mails werden an die Tabelle angehängt und in den Ordner inbox verteilt. procedure TMainForm.CheckMailClick(Sender: TObject); var MessageCount, i, p: Integer; begin Pop3.Connect; try MessageCount := Pop3.CheckMessages; for i := 0 to MessageCount-1 do begin // Mail in IdMessage schreiben... EMail.Clear; Pop3.Retrieve(i, EMail); // ...und als neuen Datensatz eintragen EMailTable.Append; EMailTable['Betreff'] := EMail.Subject; // Exception bei undefiniertem Datum verhindern try EMailTableDatum.AsDateTime := EMail.Date; except end; EMailTableAbsender.AsString := EMail.From.Address; for p := 0 to EMail.MessageParts.Count-1 do begin if (EMail.MessageParts.Items[p] is TIdText) then EMailTableText.Value := (EMail.MessageParts[p] as TIdText).Body.Text; end; EMailTable['Ordner'] := 'inbox'; EMailTable.Post; end; finally Pop3.Disconnect; end; end; Vorteile des dritten WegsDie restlichen Methoden des E-Mail-Clients sind recht einfach und werden ohne weiteren Kommentar wiedergegeben. Nur zum Verschieben (MessageMoveToClick) noch folgende Anmerkung. Hier wird eine einzige Methode für die Behandlung aller fünf Verschiebe-Befehle benutzt, um Schreibarbeit zu sparen. Zur Bestimmung des gewünschten Zielordners wird der Text des Menüpunkts analysiert, der deshalb exakt mit dem Ordnernamen übereinstimmen muss. Damit Kylix hier nicht querschießt und von sich aus Abkürzungstasten mit dem &-Zeichen einbaut, muss die Eigenschaft AutoHotKeys des Untermenüs auf maManual stehen. // Aktuellen Ordner leeren procedure TMainForm.EmptyClick(Sender: TObject); begin if MessageDlg('Empty Folder', 'Do you really want to delete all messages in the current folder?', mtConfirmation, mbOkCancel, 0) = mrOk then begin // Alle E-Mails im aktuellen Ordner löschen while EMailTable.RecordCount > 0 do EMailTable.Delete; end; end; // Aktuelle Mail löschen procedure TMainForm.EditDeleteMItmClick(Sender: TObject); begin if EMailTableOrdner.AsString = 'trash' then // Mails im trash werden tatsächlich gelöscht EMailTable.Delete else begin // Andere Mails werden in den trash verschoben EMailTable.Edit; EMailTableOrdner.AsString := 'trash'; EMailTable.Post; // Filter neu berechnen um Anzeige aufzufrischen EMailTable.Filtered := False; EMailTable.Filtered := True; end; end; // E-Mail in einen anderen Ordner verschieben procedure TMainForm.MessageMoveToClick(Sender: TObject); begin EMailTable.Edit; EMailTableOrdner.AsString := (Sender as TMenuItem).Caption; EMailTable.Post; EMailTable.Filtered := False; EMailTable.Filtered := True; end; // Sortiert nach Betreff, andere Sortierungen analog procedure TMainForm.SortBySubjectMItmClick(Sender: TObject); begin EMailTable.IndexName := 'EMailBetreff.ind'; end;
Der fertige E-Mail-Client mit einem Blick auf die Inbox. Damit sind die Grundfunktionen des E-Mail Client fertiggestellt. Durch den Einsatz einer Datei-basierten Datenbank-Komponente wurden gleich mehrere Fliegen mit einer Klappe geschlagen:
Das hier beschriebene Beispielprojekt stellt natürlich nur einen ersten Schritt auf dem Weg zum Alltags-fähigen E-Mail-Client dar. Die Weiterentwicklung ist im Kylix-Forum unter http://www.kylix-forum.de zu besichtigen. Hier besteht die Möglichkeit, den Quelltext herunterzuladen oder selbst an der Entwicklung teilzunehmen. Der Autor ist Diplom-Physiker und arbeitet seit über
15 Jahren als Coach, Software-Architekt und Verfasser von Fachartikeln.
Er hat im Jahre 1998 die dataweb GmbH gegründet, welche Software-Tools
für Datenbankentwickler erstellt und vertreibt. Das aktuelle Projekt
von dataweb ist eine Multi-User-Datenbank-Komponente für Kylix.
|