Bilder und binäre Dateien

Transcription

Bilder und binäre Dateien
11
Bilder und
binäre Dateien
Probleme mit dem Speichern von Dateien und insbesondere von Bildern in Dateien
gehören in den Newsgroups und Foren zum täglichen Leben. Access bietet mit dem
Datentyp OLE-Objekt die Möglichkeit, auch Dateien in einer Tabelle zu speichern.
Leider gab es bisher in Access keine eingebaute einfache Funktion, um Dateien ohne
Weiteres in einem solchen Feld abzulegen – zumindest keine, die nicht früher oder später die Größe der Datenbankdatei explodieren ließ. Mit Access 2007 kam die Wende:
Microsoft hat die Access-Gemeinde erhört und nicht nur einen neuen Felddatentyp namens Anlage, sondern auch noch ein neues Steuerelement zum Anzeigen von Bildern
in Formularen und Berichten spendiert. Und dabei können Sie im Anlage-Feld sogar
Dateien speichern, und sogar mehrere pro Datensatz. Access 2010 schließlich bringt
weitere Verbesserungen wie etwa eine Systemtabelle zum Speichern von Bildern, die
innerhalb der Anwendung verwendet werden können. Und mit unserem Standardmodul
Kapitel 11 Bilder und binäre Dateien
zum Verwenden von Bilddateien in allen Teilen einer Access-Anwendung machen Sie
aus der langweiligen Benutzeroberfläche mit Office 97-Charm endlich eine Software,
deren Bedienung auch für die Augen des Benutzers eine Freude ist. In diesem Kapitel
lernen Sie aber nicht nur, wie das Anlage-Feld und das passende Steuerelement funktionieren, sondern auch alternative Techniken kennen. Au­ßer­dem finden Sie einige VBAModule, die wichtige Tech­ni­ken für den Umgang mit Bildern und binären Daten lie­fern.
Die Module stammen aus der Feder von Sascha Trowitzsch, der auch bei der Erstellung
der Beispiele maß­geb­lich beteiligt war.
Die Beispiele in diesem Kapitel drehen sich ausschließlich um Bilder, weil dies wohl der
primäre Einsatzbereich für das Speichern von Dateien und binären Daten in Tabellen
ist. Tatsächlich können Sie die Techniken, die sich nicht explizit auf Bilder beziehen,
auch für das Speichern und Wiederherstellen von normalen Dateien verwenden. Ein
Einsatzzweck abseits der bunten Welt der Bilder ist etwa das Speichern von Dateien, die
Sie für die Ausführung einer Datenbankanwendung benötigen, und das Wiederherstellen
solcher Dateien zur Laufzeit. So können Sie zum Beispiel für den Ablauf notwendige
DLL-Dateien mitliefern, ohne dass der Benutzer sich mit zusätzlichen Dateien herumschlagen muss.
BEISPIELDATENBANK
Die Beispieldatei zu diesem Kapitel finden Sie unter dem Namen BilderUndBinaere­
Dateien.accdb auf www.acciu.de/aeb2010.
11.1 Bilder für Formulare und Berichte
Access 2010 bietet ein neues Feature: Sie können im Entwurf von Formularen und
Berichten Bilder in der Datenbank speichern, die dann in Formularen und Berichten
verwendet werden können. Das Hinzufügen erfolgt beispielsweise über den entsprechenden Ribbon-Eintrag in der Entwurfsansicht (siehe Abbildung 11.1).
Das Feature ist natürlich vor allem für die Kompatibilität mit Webdatenbanken gedacht.
Die zentral gespeicherten und von Formularen, Berichten und Steuerelementen aus referenzierbaren Bilder lassen sich schließlich wesentlich leichter auf einen Webserver
transferieren als eine Mischung aus eingebetteten, verknüpften und in Tabellen gespeicherten Bildern.
Sollten Sie planen, eine Access-Datenbank mit Access 2010 zu entwickeln und diese
auch unter Access 2007 einzusetzen, müssen Sie die Bilder auf eine der anderen in
diesem Kapitel besprochenen Arten speichern. Unter Access 2007 werden über die
Bildergalerie eingebundene Bilder nicht angezeigt.
642
Bilder für Formulare und Berichte
Abbildung 11.1: Hinzufügen von Bildern zu einer Datenbank
Wenn Sie ein Bild zur Bildergalerie hinzugefügt haben, können Sie dieses auf verschiedene Arten verwenden:
»» Wählen Sie das Bild aus der Galerie aus und klicken Sie an eine freie Stelle im
Formular. Access legt ein neues Bildsteuerelement an und stellt dessen Eigenschaft
Bild auf den Namen der Bilddatei ohne Dateiendung ein.
»» Oder ändern Sie das in einem Bildsteuerelement angezeigte Bild, indem Sie seine Eigenschaft Bild anklicken und über das Kombinationsfeld eines der in der
Bildergalerie gespeicherten Bilder auswählen. Auf die gleiche Weise verfahren Sie
mit weiteren Steuerelementen, die über die Bild-Eigenschaft verfügen.
Bilder zur Bildergalerie hinzufügen
Wenn Sie bereits Bilder für Schaltflächen, Bildsteuerelemente et cetera festgelegt haben, können Sie auch diese in die Bildgalerie der Anwendung überführen. Dazu wählen
Sie das betroffene Steuerelement aus und stellen für die Eigenschaft Bildtyp den Wert
Freigegeben ein (siehe Abbildung 11.2). Access fügt das Bild zur Bildergalerie hinzu und
gibt diesem den Namen des Steuerelements, aus dem das Bild stammt. Hier ist also
noch ein wenig Nacharbeit erforderlich.
Leider hat Microsoft dies nicht optimal gelöst: Sie können die Bezeichnungen von
Bildern in der Bildergalerie zwar über den entsprechenden Kontextmenüeintrag ändern, aber der neue Name wird nicht automatisch in die betroffenen Steuerelemente
übernommen.
Bilder aktualisieren
Sie können jedoch ein in der Bildergalerie gespeichertes Bild durch ein anderes Bild
ersetzen. Dazu verwenden Sie den Kontextmenüeintrag Aktualisieren des jeweiligen
Elements der Bildergalerie. Access zeigt hier auch gleich das aktuelle Bild im Formular
oder Bericht an.
643
Kapitel 11 Bilder und binäre Dateien
Abbildung 11.2: Hinzufügen eines eingebetteten Bildes zur Bildergalerie
Bilder aus anderen Datenbanken
Wenn Sie ein Formular oder einen Bericht aus einer anderen Datenbank importieren,
werden die darin verwendeten Bilder ebenfalls zur aktuellen Datenbank hinzugefügt.
Im Hintergrund
Die zur Bildergalerie hinzugefügten Bilddateien landen in einer zwar ausgeblendeten,
aber ungeschützten Systemtabelle namens MSysResources. Diese enthält ein AnlagenFeld sowie einige weitere Felder zum Speichern des Namens und der Endung der Bild­
datei (siehe Abbildung 11.3).
Weiter unten unter »Mehrere Bilder gleichzeitig zur Bildergalerie hinzufügen« ab Seite
655 stellen wir eine Funktion vor, mit der Sie mehr als eine Datei gleichzeitig zu dieser Tabelle hinzufügen können. Sie können damit beispielsweise ein komplettes IconVerzeichnis einlesen und brauchen dies nicht für jedes Icon einzeln zu erledigen.
Bilder per VBA zur Bildergalerie hinzufügen
Das Access-Objektmodell bietet eine neue Methode des Objekts CurrentProject beziehungsweise CodeProject, mit dem Sie per VBA schnell eine Bilddatei zur Bildergalerie
hinzufügen können. Die Methode heißt AddSharedImage und verwendet zwei Parameter:
»» SharedImageName: Name, der in der Bildergalerie angezeigt werden soll
»» Filename: Name der Quelldatei
Der folgende Aufruf fügt beispielsweise eine im gleichen Verzeichnis gespeicherte Datei
namens cats.jpg unter den Namen Katzen zur Bildergalerie hinzu:
CurrentProject.AddSharedImage "Katzen", CurrentProject.Path & "\cats.jpg"
644
Bilder und Dateien als Anlage speichern
Abbildung 11.3: Die Tabelle MSysResources speichert die Bilder der Bildergalerie
Auf die gespeicherten Resourcen greifen Sie dann über die Auflistung Resources der
Objekte CurrentProject beziehungsweise CodeProject zu. Die folgenden Anweisungen
geben beispielsweise alle Resourcen mit Name und Typ aus:
Dim objSharedResource As SharedResource
For Each objSharedResource In CurrentProject.SharedResources
With objSharedResource
Debug.Print .Name, .Type
End With
Next objSharedResource
Die Eigenschaft Type kann die folgenden beiden Werte annehmen:
»» acResourceTheme (0): Schema
»» acResourceImage (1): Bilddatei
Sie können die Elemente der Bildergalerie auch löschen, und zwar mit der Delete-Me­
tho­de des jeweiligen SharedResource-Objekts.
11.2 Bilder und Dateien als Anlage speichern
Die einfachste und naheliegendste Möglichkeit zum Speichern von Bildern bietet der
neue Datentyp Anlage. Abbildung 11.4 zeigt eine Tabelle mit einem Anlage-Feld in der
Entwurfsansicht. In Aktion sieht dieser neue Felddatentyp wie in Abbildung 11.5 aus.
Statt eines Feld­na­mens zeigt die Tabelle ein Büroklammer-Symbol an, das Sie aber
durch die Angabe eines Wertes für die Eigenschaft Bezeichnung überschreiben können.
Im Feld selbst sehen Sie das gleiche Symbol, gefolgt von einer in Klammern eingefassten Zahl. Diese gibt die Anzahl der enthaltenen Anhänge an. Klicken Sie doppelt auf das
Feld, erscheint der Dialog Anlagen, mit dem Sie Folgendes erledigen können:
»» Anlagen hinzufügen
»» Anlagen entfernen
645
Kapitel 11 Bilder und binäre Dateien
»» Eine Anlage öffnen
»» Eine Anlage aus dem Anlage-Feld auf der Festplatte speichern
»» Alle Anlagen auf der Festplatte speichern
Abbildung 11.4: Eine Tabelle mit einem Anlage-Feld in der Entwurfsansicht
Abbildung 11.5: Das Anlage-Feld in Aktion
Diese Aktionen sind sämtlich selbsterklärend, weshalb das Buch an dieser Stelle
nicht weiter darauf eingeht. Als Hinweis nur dies: Als Anlage können Sie beliebige
Dateien aufnehmen, bis auf jene, die aus Sicherheitsgründen verboten sind und von
Access blo­ckiert werden. Dabei ist ausschließlich die Dateiendung von Belang. Welche
Endungen das sind, erfahren Sie in der Onlinehilfe von Access unter Anlagen|Anfügen
von Da­
teien|Referenzinformationen zu Anlage|Blockierte Dateiformate. Wie Sie später erfahren werden, lässt sich diese Limitierung mit VBA-Tricks umgehen (siehe
»Importieren von Dateien in Anlage-Felder« ab Seite 653).
646
Bilder und Dateien als Anlage speichern
Eigenschaften des Anlage-Steuerelements
Das neue Anlage-Steuerelement finden Sie in der Entwurfsansicht von Formularen und
Be­richten im Ribbon Entwurf|Steuerelemente|Anlage (Büroklammer). Neben den üblichen Ei­genschaften, die auch andere Steuerelemente besitzen, sind die folgenden erwähnenswert:
»» Standardbild (VBA: DefaultPicture): Laden Sie über diese Eigenschaft eine Bilddatei,
die das Steuerelement standardmäßig anzeigen soll. Die Eigenschaft wirkt sich immer dann aus, wenn das Anlage-Feld des angezeigten Datensatzes leer ist – also
auch beim Anlegen eines neuen Datensatzes.
»» Hintergrundart (BackStyle): Kann die Werte Normal (1) oder Transparent (0) annehmen.
Wenn Transparenz eingestellt ist, scheint der Formularhintergund durch transparente Bereiche von Bildern (32bit) hindurch.
»» Ereignis On Attachment Current (AttachmentCurrent): Das Ereignis wird ausgelöst,
wenn per Kontextmenü oder mit dem beim Klicken des Bildes erscheinenden Na­vi­
gationsbar auf eine andere Anlage des Datensatzes geschaltet wird. Das ist nützlich,
weil damit etwa der Dateiname des aktuell angezeigten Bildes wie im folgenden Lis­
ting in einem Bezeichnungsfeld oder einem anderen Steuerelement angezeigt werden kann:
Private Sub Bildanlage_AttachmentCurrent()
Me!lblFilename.Caption = Me!Bildanlage.FileName
End Sub
Die folgenden Eigenschaften stehen nur unter VBA zur Verfügung:
»» FileName: Dateiname der aktuell angezeigten Anlage (schreibgeschützt)
»» FileData: Binärdaten der aktuell angezeigten Anlage (Byte-Array, ebenfalls schreibgeschützt)
»» AttachmentCount: Anzahl der im Datensatz gespeicherten Anlagen
»» CurrentAttachment: Index der aktuell angezeigten Anlage
»» PictureDisp (versteckte schreibgeschützte Eigenschaft): Gibt bei Bildanhängen das
Picture-Objekt des aktuell angezeigten Bildes zurück. Dieses können Sie dann zur
weiteren Verarbeitung in VBA verwenden.
»» Back, Forward: Mit diesen Methoden schalten Sie per VBA zwischen den einzelnen
Anhängen eines Datensatzes um. Unter Zuhilfenahme der Eigenschaften Attach­ment­
Count und CurrentAttachment können Sie diese Methoden dazu verwenden, um über
selbst gebaute Navigationsschaltflächen zwischen den Bildern eines Datensatzes zu
na­vigieren.
647
Kapitel 11 Bilder und binäre Dateien
»» SizeToFit: Die Methode weist das Anlage-Feld an, sich den Ausmaßen des angezeigten Bildes anzupassen. Stellen Sie die Eigenschaft AutoHeight des Detailbereichs
außerdem auf True, dann passt Access auch die Formulargröße dem Bild an.
11.3 Bilder aus Anlage-Feldern in Formularen
­anzeigen
In Formularen zeigt sich das neue Anlage-Steuerelement genauso benutzerfreundlich
wie in der Datenblattansicht von Tabellen. Sie brauchen für ein jungfräuliches Formular
nur eine Tabelle mit einem Anlage-Feld als Datensatzquelle auszuwählen und das Feld
Bildanlage dieser Tabelle in den Formularentwurf zu ziehen (siehe Abbildung 11.6). Mit
diesem Entwurf erhalten Sie beispielsweise die Formularansicht aus Abbildung 11.7.
Abbildung 11.6: Hinzufügen des Primärschlüssels und des Anlage-Feldes zu einem Formular
Abbildung 11.7: Über das Kontextmenü des Anlage-Feldes können Sie den Anlagen-Dialog öffnen
oder, wenn mehrere Anlagen vorhanden sind, darin blättern
648
Bilder aus Anlage-Feldern in Formularen a
­ nzeigen
Es geht aber auch anders als im ersten Beispiel: Vielleicht möchten Sie einmal direkt durch alle im Anlage-Feld verschiedener Datensätze enthaltenen Bilder blättern.
Dann ziehen Sie nicht das komplette Anlage-Feld, sondern die in der dahinter verborgenen Tabelle enthaltenen Felder aus der Feldliste in den Formularentwurf (siehe
Abbildung 11.8). Das Ergebnis sieht ähnlich aus (siehe Abbildung 11.9), unterscheidet
sich aber in zwei wesentlichen Punkten:
»» Sie können direkt im Formular durch alle Bilder blättern, egal, ob mehrere Bilder im
Anlage-Feld eines einzigen Datensatzes verborgen sind.
»» Sie können so nicht auf den Anlage-Dialog zugreifen.
Abbildung 11.8: Entwurf eines Formulars mit Anlage-Feld
Abbildung 11.9: Ein Bild im Anlage-Steuerelement in einem Formular
649
Kapitel 11 Bilder und binäre Dateien
Sie müssen beachten, dass Access einen Datensatz mit mehreren Bildern hier wie zwei
verknüpfte Tabellen behandelt: Eine Tabelle mit den Basisdaten (also den Daten aus
den Feldern, die nicht die Anlage enthalten) und eine Tabelle mit den im Anlage-Feld
enthaltenen Dateien.
Diese sind über eine 1:n-Beziehung miteinander verknüpft. Wenn die oben verwendete Tabelle tblBildanlagen also im ersten Datensatz zwei Bildanlagen enthält, zeigt das
Formular zwei Datensätze mit den gleichen Basisdaten, aber unterschiedlichen Anlagen
beziehungsweise Anlage-Informationen an.
11.4 Bilder aus Anlage-Feldern in Berichten
­anzeigen
In Berichten funktioniert dies genauso einfach: Sie stellen die passende Tabelle als
Datensatzquelle des Berichts ein und fügen das Anlage-Feld selbst zum Bericht hinzu.
Das Ergebnis überzeugt nicht – zumindest nicht in der Seitenansicht: Der Bericht zeigt
nur das jeweils erste Bild zu jedem Datensatz an (siehe Abbildung 11.10).
Abbildung 11.10: Berichte zeigen nur je ein Bild eines Anlage-Feldes pro Datensatz an, auch
wenn dieses mehrere Bilder enthält
Wenn Sie alle Bilder der enthaltenen Datensätze in der Seitenansicht des Berichts ausgeben möchten, fügen Sie wiederum das dem eigentlichen Anlage-Feld untergeordne-
650
Bilder aus Anlage-Feldern in Berichten a
­ nzeigen
te <Name des Anlage-Felds>.FileData-Feld zum Berichtsentwurf hinzu. Auch hier zeigt
Access die Grunddaten von Datensätzen, die mehr als ein Bild enthalten, jeweils doppelt
an (siehe Abbildung 11.11). Dem können Sie entgegenwirken, indem Sie die Eigenschaft
Duplikate ausblenden für solche Steuerelemente, die je Datensatz nur einfach angezeigt
werden sollen, auf Ja einstellen und – falls diese Steuerelemente sich allein in einer
Zeile befinden – mit dem Wert Ja für die Eigenschaft Verkleinerbar dafür sorgen, dass
keine unschönen Lücken entstehen.
Abbildung 11.11: Alle Bilder eines Anlage-Felds in der Berichtsansicht eines Berichts
Komfortabler geht dies mit einer Gruppierung nach dem Primärschlüssel der Tabelle
mit dem Anlage-Feld. Das kann im Entwurf etwa so wie in Abbildung 11.12 aussehen.
Dass die Berichtsansicht so wie in Abbildung 11.13 aussieht, ist ein weiteres Indiz dafür,
dass Access die Anlagen intern in einer verborgenen Tabelle speichert.
Abbildung 11.12: Entwurf eines nach dem Primärschlüssel der Datensatzquelle gruppierten Be­
richts mit Bildanlagen ...
651
Kapitel 11 Bilder und binäre Dateien
11.5 Bilder und Dateien aus Anlage-Feldern auf der
Festplatte speichern
Das Speichern von Anlagen aus dem Anlage-Feld ist äußerst trivial: Sie öffnen einfach
den Anlagen-Dialog per Doppelklick auf das jeweilige Feld im Formular und führen dort
die erforderlichen Schritte aus. Das funktioniert aber leider nur, wenn Sie das AnlageFeld wie in der ersten in »Bilder aus Anlage-Feldern in Formularen ­anzeigen« ab Seite
648 beschriebenen Methode anlegen.
Abbildung 11.13: ... der in der Seitenvorschau so aussieht
11.6 Dateien per VBA in Anlage-Felder importieren
und exportieren
Natürlich können Sie Bilder und Dateien auch per VBA in einem Anlage-Feld speichern
und von dort aus wieder ins Dateisystem exportieren.
BEISPIELDATENBANK
Die Prozeduren dieses Abschnitts finden Sie im Modul mdlBLOBs0710 der Beispiel­
daten­bank DAO2010.accdb auf www.acciu.de/aeb2010.
652
Dateien per VBA in Anlage-Felder importieren und exportieren
11.6.1 Importieren von Dateien in Anlage-Felder
Die nachfolgend vorgestellte Funktion können Sie universell für das Importieren beliebiger Dateien in Anlage-Felder verwenden. Sie erwartet die folgenden Parameter:
»» strFileName: Verzeichnis und Name der zu importierenden Datei
»» strTable: Name der Tabelle, in der sich das Anlage-Feld befindet
»» strFieldAttach: Name des Anlage-Feldes
»» boolEdit: Gibt an, ob die Anlage in einem bestehenden Datensatz gespeichert werden
soll
»» strIDField: Name des Primärschlüsselfeldes der Tabelle
»» varID: Wert des Primärschlüsselfeldes für den Datensatz, zu dem eine Anlage hinzugefügt werden soll
»» strAttachment: Name des Attachments, das gegebenenfalls überschrieben werden
soll
Wenn Sie eine Datei in einem neuen Datensatz speichern möchten, verwenden Sie etwa
diesen Aufruf:
StoreBLOB0710 CurrentProject.Path & "\Bilder_01.tif", "tblAnlagen", "Anlagen"
Zum Anfügen einer Datei in einem vorhandenen Datensatz setzen Sie diese Anweisung
ab – wobei 2 der Primärschlüsselwert des Zieldatensatzes ist:
StoreBLOB0710 CurrentProject.Path & "\Bilder_01.tif", "tblAnlagen", "Anlagen", True,
"AnlageID", 2
Schließlich können Sie auch ein Attachment mit einem bestimmten Dateinamen in der
Tabelle überschreiben. Auch dies erfordert die Angabe des Datensatzes und zusätzlich
den Namen des bereits vorhandenen Attachments:
StoreBLOB0710 CurrentProject.Path & "\Bilder_02.tif", "tblAnlagen", "Anlagen", True,
"AnlageID", 2, "Bilder_01.tif"
Die Routine hat übrigens noch ein weiteres Feature, das eine völlig unverständliche
Eigenschaft von Anlage-Feldern ausschaltet: Und zwar dürfen nur Dateien mit bestimmten Dateiendungen importiert werden. Und das ist wörtlich zu nehmen: Der
Inhalt der Datei spielt keine Rolle, Sie brauchen die Datei nur vor dem Speichern im
Anlage-Feld umzubenennen und dies anschließend wieder rückgängig zu machen.
Und genau das macht diese Funktion auch, indem sie den beim Speichern einer
Datei mit einer nicht erlaubten Dateiendung auftretenden Fehler entsprechend behandelt.
653
Kapitel 11 Bilder und binäre Dateien
Der Zugriff auf die Anlagen erfolgt mit DAO. Der grundlegende Ablauf ist, dass Sie zunächst ein Recordset-Objekt auf Basis der Tabelle mit dem Anlage-Feld erstellen und
ein weiteres auf Basis der Value-Eigenschaft des Anlage-Feldes. Letzteres muss unbedingt ein Recordset2-Objekt sein, ebenso wie das Field-Objekt mit dem Anlage-Feld die
neue Version Field2 braucht.
Die Prozedur sieht wie folgt aus:
Function StoreBLOB0710(strFilename As String, strTable As String, µ
strFieldAttach As String, Optional boolEdit As Boolean, µ
Optional strIDField As String, Optional varID As Variant, µ
Optional strAttachment As String) As Boolean
Dim fld2 As DAO.Field2
Dim rstDAO As DAO.Recordset2
Dim rstACCDB As DAO.Recordset2
On Error GoTo ErrHandler
Set rstDAO = CurrentDb.OpenRecordset("SELECT * FROM [" & strTable & "]", µ
dbOpenDynaset)
If boolEdit Then
If IsNull(varID) Then Err.Raise vbObjectError + 1, , µ
"Keine Datensatz-ID angegeben!"
rstDAO.FindFirst "CStr([" & strIDField & "])='" & CStr(varID) & "'"
If rstDAO.NoMatch Then Err.Raise vbObjectError + 2, , µ
"Datensatz mit ID " & varID & " nicht gefunden!"
rstDAO.Edit
Else
rstDAO.AddNew
End If
Set rstACCDB = rstDAO(strFieldAttach).Value
If boolEdit Then
If rstACCDB.EOF Then 'Fall 1: Es gibt noch keine Anlagen; > neue Anlage
rstACCDB.AddNew
Else
Do While Not rstACCDB.EOF
rstACCDB.MoveNext
Loop
rstACCDB.FindFirst "[FileName]='" & strAttachment & "'"
'Fall2: Es gibt keine Anlage mit dem Namen in sAttachment: > neue Anlage
'Fall3: Anlage gefunden; dann editieren
If rstACCDB.NoMatch Then rstACCDB.AddNew Else rstACCDB.Edit
End If
Else
654
Dateien per VBA in Anlage-Felder importieren und exportieren
rstACCDB.AddNew
End If
Set fld2 = rstACCDB.Fields!FileData
On Error Resume Next
fld2.LoadFromFile (strFilename)
If Err.Number = -2146697202 Then
'Unerlaubte Dateiendung! Spezialbehandlung...
On Error GoTo ErrHandler
Name strFilename As strFilename & ".dat"
'Datei mit Endung ".dat" anfügen
fld2.LoadFromFile (strFilename & ".dat")
'Datei laden
Name strFilename & ".dat" As strFilename
'Umbenennung rückgängig machen
'Anlagename setzen
rstACCDB.Fields!FileName = Mid(strFilename, InStrRev(strFilename, "\") + 1
rstACCDB.Update
Else
On Error GoTo ErrHandler
rstACCDB.Update
End If
rstDAO.Update
StoreBLOB0710 = True
'Rückgabe True = Alles ok.
Finally:
On Error Resume Next
rstACCDB.Close
rstDAO.Close
Set rstACCDB = Nothing
Set rstDAO = Nothing
Set fld2 = Nothing
Exit Function
ErrHandler:
MsgBox Err.Description, vbCritical
Resume Finally
End Function
Listing 11.1: Flexibles Speichern von Dateien im Anlage-Feld
Mehrere Bilder gleichzeitig zur Bildergalerie hinzufügen
Die Bildergalerie von Access 2010, die wir weiter oben vorgestellt haben, hat einen entscheidenden Nachteil: Es lassen sich nicht mal eben mehrere Bilder gleichzeitig hinzufügen. Das ist insbesondere ärgerlich, weil der Dialog zur Auswahl eines Bildes immer
wieder den Ordner der aktuellen Datenbank anzeigt. Mit der obigen Funktion und einer
kleinen Erweiterung fügen Sie schnell beliebig viele Bilder eines Verzeichnisses zur
Bildergalerie hinzu. Dazu brauchen Sie zunächst eine Funktion, die einen Dateidialog
655
Kapitel 11 Bilder und binäre Dateien
zur Auswahl der hinzuzufügenden Dateien öffnet und für jede ausgewählte Datei eine
weitere Funktion aufruft:
Public Sub BilderEinfuegen()
Dim objFiledialog As FileDialog
Dim obj As Object
Dim i As Integer
Set objFiledialog = Application.FileDialog(msoFileDialogFilePicker)
With objFiledialog
.AllowMultiSelect = True
.Filters.Add "Images", "*.png; *.gif; *.jpg; *.jpeg", 1
.Show
For i = 1 To .SelectedItems.count
BildEinfuegen .SelectedItems.Item(i)
Next i
End With
End Sub
Die zweite Funktion erwartet schlicht den Namen der einzulesenden Bilddatei. Sie verwendet dann die oben vorgestellte Prozedur StoreBLOB0710, um das Bild in einem neuen Datensatz der Tabelle MSysResources zu speichern.
Zu unserem Glück fehlen noch ein paar weitere Felder, nämlich Extension, Name und
Type. Um die entsprechenden Werte zum soeben angelegten Datensatz hinzuzufügen,
ermittelt die Funktion zunächst die ID des zuletzt angelegten Datensatzes.
Die folgenden Anweisungen lesen dann den Namen und die Erweiterung aus der kompletten Pfadangabe aus.
Diese Informationen landen dann schließlich per Execute-Anweisung in der Tabelle
MSysResource:
Public Function BildEinfuegen(strBild As String)
Dim db As DAO.Database
Dim lngID As Long
Dim strName As String
Dim strFilename As String
Dim strExtension As String
Set db = CurrentDb
StoreBLOB0710 strBild, "MSysResources", "Data", False
lngID = db.OpenRecordset("SELECT @@IDENTITY").Fields(0)
strFilename = Mid(strBild, InStrRev(strBild, "\") + 1)
strName = Split(strFilename, ".")(0)
strExtension = Split(strFilename, ".")(1)
656
Dateien per VBA in Anlage-Felder importieren und exportieren
db.Execute "UPDATE MSysResources SET Extension = '" & strExtension & "', _
Name = '" & strName & "', Type = 'img' WHERE id = " & lngID, dbFailOnError
End Function
11.6.2 Exportieren von Dateien aus dem Anlage-Feld
Für den umgekehrten Weg gibt es ebenfalls eine passende und universell einsetzbare
Funk­tion. Der Grund, warum die Datei wesentlich kompakter ist als die zum Importieren
von Dateien, ist folgender: Die Routine greift direkt mit einer geeigneten SQL-Abfrage
auf die in der Untertabelle des Anlage-Feldes enthaltenen Felder zu. Die Parameter sind
weit­gehend mit denen der vorherigen Funktion identisch. Auch der Export mit der Me­
thode SaveToFile prüft die Dateiendung, weshalb auch hier ein Work­around eingebaut ist.
Ein Beispielaufruf sieht etwa so aus:
RestoreBLOB0710 "tblAnlagen", "Anlagen", "AnlageID", 20, µ
CurrentProject.Path & "\CatsExportiert.jpg", "cats.jpg"
Die Funktion ist wie folgt aufgebaut:
Function RestoreBLOB0710(strTable As String, strFieldAttach As String, µ
strIDField As String, varID As Variant, strFilename As String, µ
Optional strAttachment As String = "*") As Boolean
Dim rstDAO As DAO.Recordset
Dim rstACCDB As DAO.Recordset2
On Error GoTo ErrHandler
Set rstACCDB = CurrentDb.OpenRecordset("SELECT [" & strFieldAttach & "].FileData µ
FROM " & strTable & " WHERE [" & strIDField & "]=" & varID & " AND [" µ
& strFieldAttach & "].FileName LIKE '" & strAttachment & "'", dbOpenSnapshot)
If rstACCDB.EOF Then
Err.Raise vbObjectError + 3, "RestoreBLOB0710", "Das Anlagefeld ist leer"
End If
If Dir(strFilename) <> "" Then
Kill strFilename
DoEvents
End If
On Error Resume Next
'Fehlerbehandlung ausschalten, da nachfolgende Zeile
'Fehler bei blockierten Dateiendungen erzeugt
rstACCDB(0).SaveToFile strFilename
If Err.Number = (-2146697202) Then
'Spezialbehandlung:
'Datei wird mit Endung .dat versehen, was erlaubte Endung ist
'Anschließend wird wiederhergestellte Datei wieder korrekt umbenannt
657
Kapitel 11 Bilder und binäre Dateien
rstACCDB(0).SaveToFile strFilename & ".dat"
DoEvents
Name strFilename & ".dat" As strFilename
End If
RestoreBLOB0710 = True
Finally:
On Error Resume Next
Set rstACCDB = Nothing
rstDAO.Close
Set rstDAO = Nothing
Exit Function
ErrHandler:
MsgBox Err.Number & "/" & Err.Description, vbCritical
Resume Finally
End Function
Listing 11.2: Speichern von Anlagen im Dateisystem
11.7 Bilder und Dateien im OLE-Feld einbetten oder
verknüpfen
Dieses Thema ist andernorts so oft besprochen und beschrieben worden, dass hier nur
kurz auf die Vor- und Nachteile eingegangen werden soll. Damit keine Verwechslungen
mit der nachfolgend beschriebenen Vorgehensweise zum Speichern von Bildern und
Dateien im binären Format in der Datenbank auftreten: Mit »Einbetten« und »Ver­
knüpfen« sind die Methoden der Benutzeroberfläche – etwa von gebundenen Objekt­
feldern – gemeint, um externe Dateien in einem OLE-Feld zu speichern oder damit
zu verknüpfen. Der Einsatz des OLE-Feldes zum Einbetten oder Verknüpfen etwa von
Office-Dateien macht beispielsweise Sinn, wenn Sie diese Dateien nur in der Datenbank
speichern und gegebenenfalls mit der passenden Anwendung bearbeiten möchten.
Nachteile beim Speichern von Bildern in OLE-Feldern
Einmal in ein OLE-Feld eingebettete Dateien lassen sich dort nicht ohne Weiteres wieder
herausholen. Es gibt zwar verschiedene Verfahren, aber der Aufwand ist relativ hoch.
Sie könnten das Objekt etwa per Doppelklick in der dafür vorgesehenen Anwendung
öffnen und dann speichern, aber wenn Sie diesen Vorgang mehrere hundert oder gar
tausend Mal durchführen müssen, um beispielsweise Ihre Urlaubsbildersammlung auf
CD zu brennen, werden Sie wünschen, die Dateien niemals in der Datenbank untergebracht zu haben.
658
Bilder und Dateien als Binärstrom im OLE-Feld speichern
Außerdem kann es hier weitere Probleme geben: Dateien, die über die Objekt einfügenFunktion von Access in ein Tabellenfeld eingefügt wurden, benötigen einen OLE-Server,
um bearbeitet oder wieder in eine Datei umgewandelt werden zu können. Das ist genau
die Anwendung, die auf dem aktuellen Windows-System für die jeweilige Dateiendung
zuständig ist.
Wenn keine für diese Dateiendung passende Anwendung eingetragen ist, wird die
Datei als »Paket« in dem Feld gespeichert. In diesem Fall ist der »Objekt-Manager«
von Windows der für das Paket zuständige OLE-Server und damit auch für die
Wiederherstellung der Datei verantwortlich.
Das ist der günstigere Fall, denn falls die Datei auf dem Ausgangssystem mit einem
konkreten OLE-Server verknüpft ist, muss die entsprechende Anwendung auch auf anderen Rechnern vorhanden sein, um die Datei öffnen oder speichern zu können.
Bilder lassen die Datenbank wachsen
Wenn es sich bei den zu speichernden Dateien um Bilder handelt, gibt es noch einen
weiteren Nachteil: Bilddateien werden datenbankintern in einem speziellen bitmapähnlichen Format gespeichert, das wesentlich mehr Speicherplatz frisst als etwa das
gängige für Fotos verwendete Format .jpg.
Die Datenbank und die darin enthaltenen Bilder nehmen dann einen um ein Vielfaches
größeren Platz auf der Festplatte ein als die Bilder im Ursprungsformat.
11.8 Bilder und Dateien als Binärstrom im OLE-Feld
speichern
In den folgenden Abschnitten lernen Sie einige Funktionen kennen, mit denen Sie Dateien
in ein Feld einer Access-Datenbank importieren und die Datei wieder im Dateisystem
speichern können.
BEISPIELDATENBANK
Die Prozeduren dieses Abschnitts finden Sie im Modul mdlOLE der Beispieldatenbank
BilderUndBinaereDateien.accdb unter www.acciu.de/aeb2010.
Importieren einer Datei in ein OLE-Feld einer Tabelle
Die Funktion SaveFileToOLEField importiert eine Datei in ein OLE-Feld einer Tabelle. Die
Funktion erwartet folgende Parameter:
659
Kapitel 11 Bilder und binäre Dateien
»» strFilename: Dateiname der zu importierenden Datei
»» strTable: Name der Zieltabelle
»» strOLEField: Name des Zielfelds
»» boolEdit: Angabe, ob die Datei in das OLE-Feld eines bestehenden Datensatzes eingefügt werden soll
»» strIDField: Primärschlüsselfeld der Zieltabelle
»» lngID: Primärschlüsselwert des Zieldatensatzes
Die Routine erzeugt zunächst einen SQL-Ausdruck, der entweder den kompletten oder
einen eingeschränkten Recordset auf die Zieltabelle zurückgibt – das hängt davon ab,
ob boolEdit wahr ist und die Datei somit in das OLE-Feld eines bestimmten Datensatzes
eingefügt werden soll.
Nach einer Prüfung, ob die angegebene Datei vorhanden ist, aktiviert die Funktion
entweder den aktuellen Datensatz zum Bearbeiten oder legt einen neuen Datensatz
an. Schließlich erfolgt das Schreiben der Datei in Form eines Binärstroms in das
Tabellenfeld – siehe auch die Kommentare im Listing.
Public Function SaveFileToOLEField(strFilename As String, strTable As String, µ
strOLEField As String, Optional boolEdit As Boolean, µ
Optional strIDField As String, Optional lngID As Long) As Long
Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim lngFileID As Long
Dim Buffer() As Byte
Dim lngFileLen As Long
Dim strSQL As String
On Error GoTo SaveFileToOLEField_Err
Set db = CurrentDb
strSQL = "SELECT " & strOLEField & " FROM " & strTable
If boolEdit = True Then
strSQL = strSQL & " WHERE " & strIDField & " = " & lngID
End If
'Datensatzgruppe mit dem Zielfeld für die Datei öffnen
Set rst = db.OpenRecordset(strSQL, dbOpenDynaset)
'Meldung, falls Datei nicht vorhanden ist
If Dir(strFilename) = "" Then
MsgBox "Die Datei '" & strFilename & "' existiert nicht."
Exit Function
End If
660
Bilder und Dateien als Binärstrom im OLE-Feld speichern
'Bearbeitung des Datensatzes beginnen
If boolEdit = True Then
rst.Edit
Else
rst.AddNew
End If
'Funktion zum Füllen des Feldes aufrufen
On Error GoTo SaveFileToOLEField_Err
'Dateinummer für die Dateioperationen festlegen
lngFileID = FreeFile
'Zu importierende Datei für den binären Zugriff öffnen
Open strFilename For Binary Access Read Lock Read Write As lngFileID
'Dateigröße ermitteln
lngFileLen = LOF(lngFileID)
'Größe der Variablen für den Dateiinhalt anpassen
ReDim Buffer(lngFileLen)
'Zielfeld leeren
rst(strOLEField) = Null
'Inhalt der Datei in Variable "Buffer" schreiben
Get lngFileID, , Buffer
'Inhalt der Variablen in das Zielfeld schreiben
rst(strOLEField).AppendChunk Buffer
'Recordset aktualisieren
rst.Update
SaveFileToOLEField = True
SaveFileToOLEField_Exit:
On Error Resume Next
Close lngFileID
rst.Close
Set rst = Nothing
Set db = Nothing
Exit Function
SaveFileToOLEField_Err:
SaveFileToOLEField = Err.Number
Resume SaveFileToOLEField_Exit
End Function
Listing 11.3: Funktion zum Importieren einer Datei in ein OLE-Feld einer Tabelle
Das Speichern einer Datei in einen neuen Datensatz erfolgt beispielsweise mit dem folgenden Aufruf:
SaveFileToOLEField CurrentProject.Path & "\bilder_01.tif", "tblOLE", "OLEFeld"
661
Kapitel 11 Bilder und binäre Dateien
Wenn Sie die Datei in einem bestimmten Datensatz speichern wollten, müssen Sie auch
noch die letzten drei Parameter angeben:
SaveFileToOLEField CurrentProject.Path & "\bilder_02.tif", "tblOLE", "OLEFeld", µ
True, "OLEFeldID", 1
Ob das Speichern funktioniert, können Sie zuverlässig nur mit der nachfolgend vorgestellten Funktion feststellen. Die soll nämlich die Datei aus dem OLE-Feld wiederherstellen.
11.9 Bilder und Dateien im binären Format aus
­einem OLE-Feld wiederherstellen
Die Funktion SaveOLEFieldToFile stellt die in der Datenbank gespeicherten Dateien wieder her. Sie ist sehr ähnlich wie die oben beschriebene Funktion aufgebaut und tauscht
im Wesentlichen Quelle und Ziel der Datei gegeneinander aus. Für weitere Informationen
sei daher auf die Kommentare im Quelltext des folgenden Listings verwiesen:
Public Function SaveOLEFieldToFile(strTable As String, strIDField As String, µ
lngID As Long, strOLEField As String, strFilename As String) As Boolean
Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim lngFileID As Long
Dim Buffer() As Byte
Dim lngFileLen As Long
On Error GoTo SaveOLEFieldToFile_Err
Set db = CurrentDb
'Datensatz mit der angegebenen ID öffnen
Set rst = db.OpenRecordset("SELECT " & strOLEField & " FROM " µ
& strTable & " WHERE " & strIDField & " = " & lngID, dbOpenDynaset)
On Error GoTo SaveOLEFieldToFile_Err
'Dateinummer für den Zugriff auf die zu erzeugende Datei ermitteln
lngFileID = FreeFile
'Dateigröße ermitteln
lngFileLen = Nz(LenB(rst(strOLEField)), 0)
'Wenn die Dateigröße größer 0 ist:
If lngFileLen > 0 Then
'Größe der Variable "Buffer" anpassen
ReDim Buffer(lngFileLen)
'Datei zum Schreiben öffnen
Open strFilename For Binary Access Write As lngFileID
662
Bilder von der Festplatte in Formularen und Berichten anzeigen
'Feldinhalt in die Variable "Buffer" schreiben
Buffer = rst(strOLEField).GetChunk(0, lngFileLen)
'Inhalt der Variablen "Buffer" in die Datei schreiben
Put lngFileID, , Buffer
End If
SaveOLEFieldToFile = True
SaveOLEFieldToFile_Exit:
On Error Resume Next
Close lngFileID
rst.Close
Set rst = Nothing
Set db = Nothing
Exit Function
SaveOLEFieldToFile_Err:
SaveOLEFieldToFile = False
Resume SaveOLEFieldToFile_Exit
End Function
Listing 11.4: Die Funktion SaveOLEFieldToFile speichert den Inhalt des angegebenen OLE-Felds
in einer Datei
Beispiele für das Speichern einer als OLE-Objekt vorliegenden Datei
Der nachfolgende Aufruf setzt voraus, dass die Tabelle einen Datensatz enthält, dessen
OLE-Feld eine Datei im binären Format beinhaltet. Er speichert den Inhalt des Feldes
OLEFeld des Datensatzes mit dem Primärschlüsselwert 1 der Tabelle tblOLE in der Datei
ExportOLE.tif im aktuellen Datenbankverzeichnis.
SaveOLEFieldToFile "tblOlE", "OLEFeldID", 1, "OLEFeld", µ
CurrentProject.Path & "\ExportOLE.tif"
Beachten Sie, dass die Prozedur vorhandene Dateien ohne Rückfrage überschreibt.
11.10 Bilder von der Festplatte in Formularen und
Berichten anzeigen
Je nachdem, ob Sie die gewünschten Dateien einfach nur in Formularen oder Berichten
der Datenbank anzeigen, aber nicht in der Datenbank speichern möchten, können Sie
sich mit sehr einfachen Mitteln behelfen. Speichern Sie die Dateien einfach gar nicht
erst in der Datenbank, sondern belassen Sie diese im Dateisystem. Statt der Datei speichern Sie lediglich den Pfad zu der gewünschten Datei und verwenden die Pfadangabe,
um eine Datei in einem entsprechenden Steuerelement zu öffnen. Praktisch ist es da-
663
Kapitel 11 Bilder und binäre Dateien
bei, wenn man die Dateien im Datenbankverzeichnis oder in einem darunter liegenden
Verzeichnis speichert.Auf diese Weise können Sie die Daten zusammen weitergeben
und gleichzeitig sicherstellen, dass die Datenbank die Dateien am gleichen Ort (relativ
zum Datenbankverzeichnis) wie beim Anlegen der Datei findet.
Ab Access 2000 liefert die Funktion CurrentProject.Path den gewünschten Pfad zurück.
Wohin mit dem Dateipfad?
Wenn Sie nur den Dateipfad in der Datenbank speichern, stehen Sie vor der Frage, wie
Sie die enthaltenen Informationen aufteilen. Es gibt verschiedene Varianten:
»» Sie speichern den kompletten Pfad inklusive Dateiname in einem Feld. Nachteil:
Änderungen am Verzeichnis erfordern immer den Einsatz von ZeichenkettenFunktionen.
»» Sie speichern Verzeichnis und Dateiname in zwei Feldern.
»» Sie legen zwei eigene Tabellen für Verzeichnisse und Dateinamen an und verknüpfen diese per 1:n-Beziehung. Vorteil: Änderungen an Verzeichnissen erfolgen auf
einen Schlag. Nachteil: Änderungen an einzelnen Verzeichnissen bereiten mehr
Aufwand.
11.10.1 Anzeigen externer Bilddateien im Formular
Da sich Bilddateien nicht nur für das Speichern in einer Datenbank, sondern besonders
zur Anzeige in Formularen und Berichten eignen, beschäftigt sich das folgende Beispiel
mit der Anzeige von extern gespeicherten Bilddateien.
Die Tabelle aus Abbildung 11.14 enthält neben dem Primärschlüsselfeld BildID nur
ein Feld für eine Bezeichnung des Bildes und eines für den Dateinamen. In das Feld
Dateiname tragen Sie am besten den kompletten Pfad inklusive Dateiname ein oder teilen diese beiden Informationen auf zwei getrennte Felder auf.
Zum Anzeigen der Bilder verwenden Sie ein Formular mit der Tabelle tblVerknuepf­
teBilder als Datensatzquelle. Das Formular soll alle Felder der Tabelle enthalten
und – falls vorhanden – das angegebene Bild anzeigen. Dazu fügen Sie zusätzlich ein
Bildsteuerelement hinzu.
Dabei müssen Sie direkt die anzuzeigende Datei angeben – wählen Sie dazu irgendein
Dummybild aus. Anschließend lassen Sie dieses wieder verschwinden, indem Sie in
der Entwurfsansicht des Formulars die Eigenschaft Bild des Bildsteuerelements leeren.
Stellen Sie außerdem den Namen des Bildsteuerelements auf imgBild ein (siehe
Abbildung 11.15).
664
Bilder von der Festplatte in Formularen und Berichten anzeigen
Abbildung 11.14: Tabelle zum Speichern von Bildverknüpfungen
Abbildung 11.15: Formular mit ungebundenem Bildsteuerelement
Nun müssen Sie noch dafür sorgen, dass das Bildsteuerelement die im Feld Dateiname
angegebene Bilddatei anzeigt.
Das Bildsteuerelement besitzt bereits seit Access 2007 die Ei­genschaft
Steuerelementinhalt, für die Sie direkt das Feld mit dem kompletten Pfad an­ge­ben können. Es zeigt dann automatisch das angegebene Bild an.
Sie brauchen nur noch ein wenig Code, um einen Dialog zum Auswählen der Bilddatei
anzuzeigen:
665
Kapitel 11 Bilder und binäre Dateien
Private Sub cmdDateiOeffnen_Click()
Me!Dateiname = WZHOpenFileName(CurrentProject.Path)
End Sub
Listing 11.5: Aufruf der Prozedur BildAktualisieren durch verschiedene Ereignisprozeduren
Das Bildsteuerelement aktualisiert die angegebene Datei direkt nach dem Ändern des
im Feld Dateiname angegebenen Wertes.
Im Unterschied zu früheren Versionen von Access sind nun übrigens nicht mehr die
Office-Grafikfilter für das Laden der Bilder verantwortlich, sondern das in Access integrierte GDIPlus.
Damit entfällt die lästige bisherige Fortschrittsanzeige beim Laden, die Access manchmal zum Absturz brachte. Sie müssen sich nun auch keine Sorgen mehr machen, dass
auf einem anderen Rechner die erforderlichen Grafikfilter nicht installiert sein könnten.
11.10.2 Anzeige externer Bilddateien in Berichten
In Berichten ist die Vorgehensweise durch die Steuerelementinhalt-Eigenschaft des
Bildsteuerelements ebenfalls viel einfacher geworden (siehe Abbildung 11.16).
Abbildung 11.16: Entwurfsansicht eines Berichts mit verknüpften Bilddateien
Wenn Bilder nicht angezeigt werden wollen …
Manche .jpg-Datei und Bilddatei anderer Formate kann Access nicht in seinem Bild­
steuer­element anzeigen.
Das Problem liegt entweder tatsächlich in einem fehlenden Gra­fik­format oder aber
das Format der Datei entspricht nicht exakt den Spe­zi­fi­kationen. Dann hilft nur das
Konvertieren der Bilder in ein anderes Format.
666
Icons und Co.
11.10.3 Alternative zum Bildsteuerelement von Access
Eine Alternative zum Bildsteuerelement ist das Image-Steuerelement der MSForms-Bib­
liothek, die bei jeder Access-Installation – auch bei Runtimes – mitinstalliert wird. Die­
ses Steuerelement fügen Sie über den Dialog ActiveX-Steuerelement einfügen ein (Rib­
bon-Ein­trag Entwurf|Steuerelemente|ActiveX-Steuerelement einfügen). Damit das Steu­
er­ele­ment die Bilder passend zur Steuerelementfläche zoomt (siehe Abbildung 11.17),
fügen Sie noch zwei Zeilen Code hinzu, sodass die Prozedur aus dem vorherigen Bei­
spiel nun so aus­sieht:
Private Sub Detailbereich_Print(Cancel As Integer, PrintCount As Integer)
Dim strDateiname As String
Dim strPicture As String
Dim objImage As MSForms.Image
'Prüfen, ob Dateiname vorhanden ist
If Not IsNull(Me!Dateiname) Then
strDateiname = Me!Dateiname
'Prüfen, ob das angegebene Bild existiert...
If Not Dir(strDateiname) = "" Then
'... und Bild festlegen
strPicture = strDateiname
End If
End If
'Bildname dem Bildsteuerelement zuweisen
Set objImage = Me!imgBild.Object
objImage.PictureSizeMode = fmPictureSizeModeZoom
Set objImage.Picture = LoadPicture(strDateiname)
End Sub
Listing 11.6: Anzeigen verknüpfter Bilddateien im Image-Steuerelement der MSForms-Biblio­thek
11.11 Icons und Co.
Mittlerweile gibt es verschiedene DLLs für Grafikoperationen. Diese liegen auch noch in
verschiedenen Versionen vor. Welche Sie auf Ihrem System finden, hängt von Betriebs­
system- und Office-Version sowie von gegebenenfalls weiterer installierter Software ab.
GDIPlus und OGL, eine Office-spezifische Version von GDIPlus liefern eine Reihe von
Funktionen für den Zugriff auf und die Bearbeitung von Bildern. Sascha Trowitzsch hat
ein Modul programmiert, das diese Funktionen einfach zugänglich macht. Darüber hinaus prüft dieses Modul sogar noch die verfügbaren DLLs für Grafikoperationen und ruft
in Abhängigkeit davon die richtigen API-Funktionen auf.
667
Kapitel 11 Bilder und binäre Dateien
Abbildung 11.17: Bilder im Image-Steuerelement der MSForms-Bibliothek
BEISPIELDATENBANK
Die Module mdlOGL0710 sowie mdlOLE finden Sie in der Beispieldatenbank Bilder­
Und­BinaereDateien.accdb unter www.acciu.de/aeb2010.
Achtung: Dieses Modul funktioniert nur in der 32-bit-Variante von Access 2010.
Nachfolgend finden Sie einige Beispiele für die Anwendung dieser genialen Funk­tions­
samm­lung.
Vorneweg der Hinweis, dass der Datentyp StdPicture der Bibliothek OLE Automation in
den meisten Fällen als Container für ein Bild dient. So lesen Sie etwa zunächst eine
Bilddatei in ein Objekt des Typs StdPicture der Bibliothek OLE Automation ein, bevor Sie
dieses im OLE-Feld einer Tabelle speichern – Sie benötigen also in Ihrer Datenbank
einen entsprechenden Verweis.
11.11.1 Icons in ListView-/TreeView-Steuerelementen
Wenn Sie ein ListView- oder TreeView-Steuerelement einsetzen und darin Icons anzeigen möchten, müssen diese in einem ImageList-Steuerelement zur Verfügung stehen.
Normalerweise ist das kein Problem, denn Sie können die Bilder manuell hinzufügen.
668
Icons und Co.
Besser ist es jedoch, die in einer Anwendung verwendeten Bilddateien zentral in einer
Tabelle der Datenbank zu speichern. Damit die Bilder überall in der Anwendung immer
aktuell sind (immerhin kann es ja mal vorkommen, dass sich ein Icon ändert), sollten
Sie diese dynamisch aus einer Bildertabelle in das ImageList-Steuerelement einlesen.
Dabei helfen die Methoden des Moduls mdlOGL0710, in diesem Fall PicFromField. Im
folgenden Beispiel haben wir im Formular frmBildbeispiele ein ImageList-Steuerelement
namens ctlImageList sowie ein TreeView-Steuerelement namens ctlTreeView angelegt
(siehe Abbildung 11.18).
Abbildung 11.18: Icons im TreeView-Steuerelement
Zur Vereinfachung der Programmierung haben wir auch hier wieder Objektvariablen für
das ImageList- und das TreeView-Steuerelement vorgesehen:
Dim objTreeView As MSComctlLib.TreeView
Dim objImageList As MSComctlLib.ImageList
Beim Laden des Formulars werden diese beiden Variablen mit den Verweisen auf die
entsprechenden Steuerelemente gefüllt. Außerdem ruft diese Prozedur zwei weitere
Prozeduren auf, die erst das ImageList- und dann das TreeView-Steuerelement mit den
benötigten Daten füllen:
Private Sub Form_Load()
Set objTreeView = Me!ctlTreeView.Object
Set objImageList = Me!ctlImageList.Object
ImageListFuellen
TreeViewFuellen
End Sub
Die erste dieser beiden Prozeduren füllt das ImageList-Steuerelement mit den im OLEFeld ImageObjekt der Tabelle USysImages enthaltenen Bilddateien. Dabei stellt die
Prozedur zunächst die Höhe und Breite für die im ImageList-Steuerelement zu speichernden Bilder ein und leert eventuell noch enthaltene Bilder. Schließlich durchläuft
die Prozedur eine Datensatzgruppe und fügt für jeden Datensatz ein Bild zum ImageList-
669
Kapitel 11 Bilder und binäre Dateien
Steuerelement hinzu. Dies geschieht mit der Add-Methode dieses Steuerelements. Diese
erwartet unter anderem einen Verweis auf ein StdPicture-Objekt mit dem Bildobjekt als
Inhalt. Diesen liefert die Funktion PicFromField aus dem Modul mdlOGL0710, die nur einen Verweis auf das Herkunftsfeld benötigt:
Public Sub ImageListFuellen()
Dim db As DAO.Database
Dim rstImages As DAO.Recordset
Dim i As Integer
Set db = CurrentDb
With ctlImageList
.ListImages.Clear
.ImageHeight = 16
.ImageWidth = 16
Set rstImages = db.OpenRecordset("SELECT * FROM USysImages", dbOpenSnapshot)
Do While Not rstImages.EOF
i = i + 1
.ListImages.Add i, rstImages!Imagename, PicFromField(rstImages!ImageObject)
rstImages.MoveNext
Loop
End With
End Sub
Schließlich folgt die Prozedur zum Füllen des TreeView-Steuerelements. Der Einfachheit
halber wollen wir einfach nur für jedes im ImageList-Steuerelement enthaltene
Element einen Node im TreeView anlegen. Damit dies möglich ist, weist die Prozedur
der Eigenschaft ImageList des TreeView-Steuerelements zunächst einen Verweis auf das
ImageList-Steuerelement zu.
Danach ermittelt die Prozedur mit der Eigenschaft Count der Auflistung ListImages des
ImageList-Steuerelements die Anzahl der enthaltenen Bilder. Dieser Wert bildet die obere Grenze der nachfolgenden For...Next-Schleife. Die einzige Anweisung innerhalb dieser
Schleife legt mit der Add-Methode jeweils einen neuen Node im TreeView-Steuerelement
an. Zum Hinzufügen eines Icons brauchen Sie lediglich den Schlüsselwert des entsprechenden Eintrags mit dem vorletzten Parameter zu übergeben:
Public Sub TreeViewFuellen()
Dim i As Integer
With objTreeView
Set .ImageList = Me.ctlImageList.Object
For i = 1 To objImageList.ListImages.count
.Nodes.Add , , "a" & i, objImageList.ListImages.Item(i).Key, objImageList.
ListImages.Item(i).Key
670
Icons und Co.
Next i
End With
End Sub
11.11.2 Icons in Kontextmenüs
Wer Wert auf eine benutzerfreundliche Anwendung legt, wird Funktionen, die sich auf
bestimmte Elemente der Benutzeroberfläche beziehen, zusätzlich in Kontextmenüs unterbringen. Auch in Kontextmenüs können Sie Icons darstellen (siehe Abbildung 11.19).
Allerdings sind dazu einige Tricks nötig, die unser Modul mdlOGL0710 jedoch auch abbildet.
Abbildung 11.19: Icons im Kontextmenü
Dazu brauchen wir eine kleine Prozedur, welche das Kontextmenü anlegt und durch die
Beim Laden-Ereignisprozedur ausgelöst wird:
Private Sub Form_Load()
PopupAnlegen
End Sub
Die Prozedur PopupAnlegen deaktiviert zunächst die Anzeige der eingebauten Kon­text­
menüs. Danach löscht sie ein eventuell noch vorhandenes Exemplar der nun neu zu erstellenden Symbolleiste. Die Add-Methode der CommandBars-Auflistung erzeugt diese
gleich neu. Genau wie im vorherigen Beispiel soll das Kontextmenü schlicht mit den in
der Tabelle USysImages gespeicherten Bilddateien gefüllt werden. Dazu brauchen wir
ein Database-Objekt und ein Recordset, das den Zugriff auf diese Tabelle ermöglicht.
In einer Schleife durchläuft die Prozedur dann alle Datensätze dieses Recordsets. Die
erste Anweisung innerhalb der Schleife erzeugt schlicht ein neues Element des Typs
msoButtonIcon, also eine Schaltfläche mit Icon. Die Caption-Eigenschaft nimmt den Text
für den Kontextmenüeintrag entgegen, die Picture-Eigenschaft einen Verweis auf ein
StdPicture-Objekt.
671
Kapitel 11 Bilder und binäre Dateien
Dieses StdPicture-Objekt müssen Sie zunächst noch erstellen. Wie im vorherigen
Beispiel hilft dabei die Funktion PicFromField. Kontextmenüs zeigen standardmäßig
nicht die transparenten Teile von Icons an, was aber kein Problem ist: Der Eigenschaft
Mask können Sie einen Verweis auf ein weiteres StdPicture-Objekt übergeben, das definiert, welche Bereiche des für Picture angegebenen StdPicture-Objekts transparent
angezeigt werden sollen.
Glücklicherweise gibt es im Modul mdlOGL0710 eine Funktion, die ein solches
Maskenbildobjekt auf Basis der transparenten Teile des anzuzeigenden Images erzeugen kann und die lediglich einen Verweis auf das zu maskierende StdPicture-Objekt erwartet. Auf diese Weise ist das Kontextmenü schnell erzeugt und mit den gewünschten
Bildern gefüllt:
Private Sub PopupAnlegen()
Dim cbr As CommandBar
Dim cbb As CommandBarButton
Dim objPicture As StdPicture
Dim db As DAO.Database
Dim rstImages As DAO.Recordset
Me.ShortcutMenu = False
On Error Resume Next
CommandBars("Popup_Icons").Delete
On Error GoTo 0
Set cbr = CommandBars.Add("Popup_Icons", msoBarPopup, False, True)
Set db = CurrentDb
Set rstImages = db.OpenRecordset("SELECT * FROM USysImages", dbOpenDynaset)
Do While Not rstImages.EOF
Set cbb = cbr.Controls.Add(1)
With cbb
.Caption = rstImages!ImageName
Set objPicture = PicFromField(rstImages!ImageObject)
If Not objPicture Is Nothing Then
cbb.Picture = objPicture
cbb.Mask = MaskFromPicture(objPicture)
End If
End With
rstImages.MoveNext
Loop
End Sub
Fehlt nur noch ein Mechanismus, der das Kontextmenü bei Bedarf anzeigt. Im Bei­spiel­
for­mular soll es immer angezeigt werden, wenn der Benutzer mit der rechten Maustaste
auf den Detailbereich klickt. Dies erledigt eine entsprechende Er­eig­nis­pro­ze­dur:
672
Icons und Co.
Private Sub Detailbereich_MouseDown(Button As Integer, Shift As Integer, X As Single, _
Y As Single)
Select Case Button
Case 2
CommandBars("Popup_Icons").ShowPopup
End Select
End Sub
11.11.3 Icons im Ribbon
Auch für das Anzeigen von Icons im Ribbon können Sie die PicFromField-Funktion verwenden (siehe Abbildung 11.20). Wir greifen auf das kommende Kapitel vor, wo Sie
erfahren, dass Sie einem Ribbon-Steuerelement über eine Prozedur mit einer speziellen Syntax einen Verweis auf ein StdPicture-Objekt übergeben können, das dann im
Steuerelement angezeigt wird.
Abbildung 11.20: Ein Icon im Ribbon
Eine solche Prozedur sieht im einfachsten Fall wie folgt aus. Die einzige Zeile dieser
Prozedur ist recht unübersichtlich:
Public Sub loadImage(control, ByRef image)
Set image = PicFromField(CurrentDb.OpenRecordset("SELECT ImageObject FROM µ
USysImages WHERE ImageName = '" & control & "'").Fields(0), &HFFFFFF)
End Sub
Also liefern wir nachfolgend eine etwas übersichtlichere Variante. Diese verdeutlicht
die notwendigen Schritte. Die Prozedur liefert mit dem Parameter control den Wert der
Eigenschaft image des Ribbon-Steuerelements, für das diese Prozedur aufgerufen wird.
Das anschließend geöffnete Recordset enthält genau den Datensatz für dieses Bild. Ein
Verweis auf das Feld ImageObjekt dieses Datensatzes landet in der Objektvariablen fld,
welches wiederum als Parameter eines Aufrufs der PicFromField-Prozedur dient. In
diesem Falle müssen Sie dem Aufruf noch einen weiteren Parameter übergeben, der
Informationen über die Transparenz enthält:
Public Sub loadImage(control, ByRef image)
Dim db As DAO.Database
673
Kapitel 11 Bilder und binäre Dateien
Dim rst As DAO.Recordset
Dim fld As DAO.Field
Set db = CurrentDb
Set rst = db.OpenRecordset("SELECT ImageObject FROM USysImages µ
WHERE ImageName = '" & control & "'")
Set fld = rst!ImageObject
Set image = PicFromField(fld, &HFFFFFF)
End Sub
11.11.4 Bilder aus dem OLE-Feld in einem Formular
­anzeigen
Genau wie die Bilddateien aus Anlagefeldern können Sie auch solche aus OLE-Feldern
in Formularen anzeigen. Mit dem StdPicture-Objekt und dem Image-Steuerelement der
MSForms 2.0-Bibliothek ist es möglich, in OLE-Feldern gespeicherte Bilder direkt – und
zwar ohne Umweg über das Dateisystem – in einem Formular anzuzeigen. Der Entwurf
des Formulars sieht wie in Abbildung 11.21 aus, die Anzeige der Bilder erfolgt mit besagtem Image-Steuerelement. Als Datensatzquelle dient die Tabelle tblOLEBilder.
Um den Inhalt des OLE-Feldes der Tabelle anzuzeigen, lesen Sie zunächst den Binär­
strom aus dem passenden Tabellenfeld – hier das Feld OLEBild der Tabelle tblOLEBilder –
aus und wandeln es in ein StdPicture-Objekt um.
Dazu verwenden Sie ebenfalls die Funktion PicFromField aus dem Modul mdlOGL0710.
Abbildung 11.21: Das Formular zum Anzeigen von Bildern direkt aus der Tabelle in der Entwurfs­
ansicht
674
Icons und Co.
Die Routine BildAnzeigen macht sich die Funktion PicFromField zu Nutze, indem sie das
Field-Objekt mit dem Bild ermittelt und dieses an die Funktion PicFromField übergibt,
um ein passendes StdPicture-Objekt zurückzuerhalten. Dieses wiederum lässt sich einfach im Image-Steuerelement des Formulars anzeigen.
Private Sub BildAnzeigen()
Dim objPicture As stdole.StdPicture
Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim fld As DAO.Field
Set db = CurrentDb
Set rst = db.OpenRecordset("SELECT OLEBild FROM tblOLEBilder WHERE OLEBildID = " _
& Me.OLEBildID, dbOpenDynaset)
Set fld = rst.Fields(0)
InitGDIP
Set objPicture = PicFromField(fld)
Set Me.imgBild.Picture = objPicture
ShutDownGDIP
End Sub
Listing 11.7: Diese Routine ermittelt das Field-Objekt mit dem Bild zum aktuell im Formular
angezeigten Datensatz und wandelt dessen Inhalt in ein Format um, das vom Image-Steuerelement
angezeigt werden kann
Wann nun wird das in der Tabelle enthaltene Bild in das Image-Steuerelement geladen?
Natürlich in der Ereignisprozedur, die beim Anzeigen eines jeden Datensatzes ausgelöst
wird. Diese prüft, ob das Feld OLEBild überhaupt gefüllt ist, und ruft dann die Routine
BildAnzeigen auf, um das Image-Steuerelement damit zu füllen:
Private Sub Form_Current()
If Not IsNull(Me.OLEBild) Then
BildAnzeigen
Else
Set Me.imgBild.Picture = Nothing
End If
End Sub
Listing 11.8: Bild im Formular anzeigen
Wenn bereits ein Bild im ersten Datensatz der Datensatzquelle des Formulars enthalten
ist, sieht dieses nun beim Öffnen wie in Abbildung 11.22 aus. In der Abbildung sehen Sie
noch eine Schaltfläche zum Hinzufügen eines Bildes zu einem Datensatz. Diese füllen
Sie natürlich auch noch mit Leben – Sie wollen ja schließlich auch komfortabel Daten
zur Tabelle hinzufügen. Dazu legen Sie die folgende Ereignisprozedur an, die zunächst
675
Kapitel 11 Bilder und binäre Dateien
die Funktion WZHOpenFileName zum Auswählen der gewünschten Bilddatei aufruft (Sie
finden diese Funktion im Modul mdlOpenSaveFile der Beispieldatenbank). Anschließend
speichert die Routine den aktuellen Datensatz, weil gegebenenfalls noch keiner in der
zugrunde liegenden Tabelle enthalten ist. Das ist notwendig, weil das Bild direkt in der
Tabelle gespeichert wird. Schließlich speichert die Routine das Bild mit der Funktion
SaveFileToOLEField in der passenden Tabelle und aktualisiert die Anzeige durch einen
Aufruf der Funktion BildAnzeigen.
Abbildung 11.22: Ein direkt aus der Tabelle geladenes Bild im Binärformat
Private Sub cmdBildHinzufuegen_Click()
Dim strFilename As String
strFilename = WZHOpenFileName(CurrentProject.Path, "Bildddatei auswählen", , ,
False, ofnThumbs)
Me!Dateiname = Mid(strFilename, InStrRev(strFilename, "\") + 1)
DoCmd.RunCommand acCmdSaveRecord
SaveFileToOLEField strFilename, "tblOLEBilder", "OLEBild", True, "OLEBildID",
Me.OLEBildID
BildAnzeigen
End Sub
Listing 11.9: Einfügen eines Bildes aus einer Datei in ein OLE-Feld
11.11.5 Bild aus einem OLE-Feld wiederherstellen
Auf diese Art gespeicherte Bilder können Sie natürlich auch wieder in eine Datei umwandeln. Auch dazu können Sie eine passende Schaltfläche im Formular anlegen. Für
diese hinterlegen Sie dann den folgenden Code. Die Routine ermittelt zunächst aus dem
676
Icons und Co.
im Feld Dateiname gespeicherten Wert die Dateiendung und daraus weiter unten das
Dateiformat, unter dem die Bilddatei gespeichert werden soll. Zwischendurch erzeugt
sie ein Recordset, das genau den soeben im Formular angezeigten Datensatz enthält,
und schreibt aus dem darin enthaltenen OLE-Feld die passende Datei auf die Fest­platte
(in das Verzeichnis der aktuellen Anwendung).
Private Sub cmdBildSpeichern_Click()
Dim objPicture As stdole.StdPicture
Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim fld As DAO.Field
Dim strFileType As String
Dim intPicType As PicFileType
strFileType = Mid(Me.Dateiname, InStrRev(Me.Dateiname, ".") + 1)
Set db = CurrentDb
Set rst = db.OpenRecordset("SELECT OLEBild FROM tblOLEBilder " _
& "WHERE OLEBildID = " & Me.OLEBildID, dbOpenDynaset)
Set fld = rst.Fields(0)
Set objPicture = PicFromField(fld)
InitGDIP
Select Case strFileType
Case "bmp"
intPicType = pictypeBMP
Case "gif"
intPicType = pictypeGIF
Case "png"
intPicType = pictypePNG
Case "jpg"
intPicType = pictypeJPG
End Select
SaveImage objPicture, CurrentProject.Path & "\" & Me!Dateiname, _
intPicType
ShutDownGDIP
Set fld = Nothing
rst.Close
Set rst = Nothing
Set db = Nothing
End Sub
Listing 11.10: Speichern eines Bildes aus einem OLE-Feld in eine Datei
11.11.6 Speichern in verschiedenen Formaten
Sie sind beim Speichern eines Bildes, das in einem OLE-Feld als Binärstrom vorliegt,
keinesfalls daran gebunden, es im ursprünglichen Format zu speichern. Ändern Sie ein-
677
Kapitel 11 Bilder und binäre Dateien
mal die Dateiendung im passenden Feld im Formular und klicken Sie dann auf die Bild
speichern-Schaltfläche – Sie werden sehen, dass die Routine SaveImage aus dem Modul
mdlOGL0710 Bilder auch in andere Formate umwandeln kann.
11.11.7 Ersatz für Anlagen?
Das Anlage-Feld ist zweifellos eine Erleichterung für Access-Anwender. Allerdings behält das Speichern der Dateien in einer verborgenen Datei einen faden Beigeschmack.
Warum also nicht Bilder und binäre Dateien als Binärstrom in einem OLE-Feld speichern?
Mit den genannten Funktionen des Moduls mdlOGL0710 erhalten Sie Möglichkeiten, die
das Anlage-Feld nicht liefern kann. Oder doch? Aber natürlich. Sascha Trowitzsch liefert auch noch eine Routine, mit der Sie den Inhalt eines Anlage-Feldes so in ein ByteArray einlesen, dass Sie es leicht mit der Funktion AttachmentToPicture in ein StdPictureObjekt umwandeln können. Und somit können Sie auch alle anderen in mdlOGL0710
enthaltenen Funktionen einsetzen. Und schließlich liefert die Beispieldatenbank auch
noch eine Funktion, die ein Byte-Array wieder in einem Anlage-Feld speicher (siehe
Array2Attachment).
Performance pro und kontra
Bei der Entscheidung, ob Sie Anlage- oder OLE-Felder zum Speichern Ihrer Bilder oder
Dateien verwenden, sollten Sie auch die Performance berücksichtigen. Access komprimiert den Inhalt von Anlage-Feldern, wenn es sinnvoll ist – etwa beim .bmp-Format.
Damit benötigen Sie weniger Speicherplatz und vor allem lassen sich Daten schneller
über das Netzwerk transportieren. Andererseits kostet das Packen und Entpacken ebenfalls Ressourcen. Das binäre Speichern im OLE-Feld erfolgt unkomprimiert, kostet also
beim Anlegen und Laden weniger Zeit. Dafür haben die Dateien Originalgröße – schlecht
also etwa beim .bmp-Format – und führen gegebenenfalls zu mehr Netzwerktraffic. Für
Bilder im .jpg-, .gif- oder .png-Format, die per Definition bereits komprimiert sind, spielt
das hingegen keine Rolle.
Ebenfalls wichtig ist die Frage, ob die Datenbank einmal nach SQL Server et cetera migriert werden soll. Das OLE-Feld macht in diesem Fall weniger Schwierigkeiten, da es
sich direkt in der entsprechenden Tabelle befindet, während das Anlagefeld ja intern in
einer separaten Tabelle gespeichert wird.
678

Similar documents