{"id":55001557,"date":"2025-08-01T00:00:00","date_gmt":"2025-08-20T15:32:41","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1557"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/","title":{"rendered":"Icons in Ribbon, Kontextmen&uuml;, Formular und TreeView"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg01.met.vgwort.de\/na\/83d6b0ad670841858768ee632ccf2c10\" width=\"1\" height=\"1\" alt=\"\"><b>Seit Jahren gibt es im Web einige Module, die das Handling von Bilddateien als Icons in Ribbons, Kontextmen&uuml;s, TreeViews oder als Formular-Icon erlauben. Diese sind meist umfangreich und f&uuml;r Laien kaum verst&auml;ndlich. Wir haben die verwendeten Techniken einmal ein wenig einfacher gestaltet, sodass man nicht mehr so viel Code ben&ouml;tigt &#8211; und vor allem weniger API-Funktionen. In diesem Artikel lernen Sie, wie Sie Ribbon-Eintr&auml;ge und Kontextmen&uuml;-Befehle mit Icons versehen. Als Bonus gibt es eine hilfreiche Funktion, mit der wir schnell viele Icons in die Access-Datenbank &uuml;bertragen k&ouml;nnen, statt diese Schritt-f&uuml;r-Schritt einzulesen.<\/b><\/p>\n<h2>Theorie zu Bilddateien f&uuml;r Icons und Ribbons<\/h2>\n<p>Seit der Version 2010 speichert Microsoft Access Bilder, die aus dem Dateisystem ausgew&auml;hlt und Steuerelementen wie dem Bildsteuerelement oder der Schaltfl&auml;che zugeordnet werden, in einer Systemtabelle der Datenbank namens <b>MSysResources<\/b>.<\/p>\n<p>Nachdem wir einem Formular im Entwurf &uuml;ber den Ribbonbefehl <b>Bild einf&uuml;gen <\/b>ein Bild hinzugef&uuml;gt haben, ist dieses anschlie&szlig;end st&auml;ndig verf&uuml;gbar (siehe Bild 1).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_1557_001.png\" alt=\"Bilder sind nach dem Hinzuf&uuml;gen st&auml;ndig in der aktuellen Datenbank verf&uuml;gbar.\" width=\"700\" height=\"340,5191\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Bilder sind nach dem Hinzuf&uuml;gen st&auml;ndig in der aktuellen Datenbank verf&uuml;gbar.<\/span><\/b><\/p>\n<p>Die Bilddateien werden intern versteckt gespeichert, n&auml;mlich in der bereits erw&auml;hnten Tabelle <b>MSysResources<\/b>.<\/p>\n<p>Diese sieht nach dem Hinzuf&uuml;gen einiger Bilder wie in Bild 2 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_1557_002.png\" alt=\"Tabelle zum Speichern der Bilder in der aktuellen Datenbank\" width=\"499,5589\" height=\"302,5497\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Tabelle zum Speichern der Bilder in der aktuellen Datenbank<\/span><\/b><\/p>\n<p>All diese Bilder k&ouml;nnen wir allerdings auch anderweitig nutzen, wenn sie sich einmal in der Datenbank befinden &#8211; zum Beispiel, indem wir sie per VBA auslesen und in Ribbons oder Kontextmen&uuml;s anzeigen.<\/p>\n<h2>Vorbereitung: Icons in der Datenbank speichern<\/h2>\n<p>Der Dialog zum Hinzuf&uuml;gen von Bildern zur Datenbank &uuml;ber den Befehl <b>Bild einf&uuml;gen <\/b>hat einen Nachteil, der bereits aus der Beschriftung dieses Befehls ersichtlich wird &#8211; man kann immer nur ein Bild pro Vorgang hinzuf&uuml;gen. Wenn man einen Satz von Bildern hat, die man immer wieder ben&ouml;tigt, wird das schnell aufwendig.<\/p>\n<p>Wir stellen also in diesem Beitrag eine Funktion vor, mit der wir gleich mehrere Bilder im Dateidialog ausw&auml;hlen und zur Datenbank hinzuf&uuml;gen k&ouml;nnen.<\/p>\n<h2>Bilder in Ribbon und Kontextmen&uuml;<\/h2>\n<p>W&auml;hrend wir die Bilder aus der Tabelle <b>MSysResources <\/b>zu Bildsteuerelementen oder Schaltfl&auml;chen hinzuf&uuml;gen k&ouml;nnen, indem wir diese einfach f&uuml;r die Eigenschaft <b>Bild<\/b> ausw&auml;hlen (siehe Bild 3), ist das bei den Schaltfl&auml;chen und anderen Elementen in Schaltfl&auml;chen im Kontextmen&uuml;s nicht so einfach m&ouml;glich. Diese erwarten ein per VBA zugewiesenes Element des Typs <b>StdPicture<\/b>.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_1557_003.png\" alt=\"Die Bilder stehen in der Bild-Eigenschaft zur Verf&uuml;gung\" width=\"599,559\" height=\"439,538\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Die Bilder stehen in der Bild-Eigenschaft zur Verf&uuml;gung<\/span><\/b><\/p>\n<p>Ein Bild aus der Tabelle <b>MSysResources <\/b>auszuw&auml;hlen und in ein <b>StdPicture<\/b>-Element umzuwandeln, ist kein Hexenwerk, aber dazu sind einige Codezeilen n&ouml;tig und eine Reihe API-Funktionen. Im zweiten Abschnitt dieses Beitrags werden wir eine Vorgehensweise vorstellen, die wesentlich kompakter als die &uuml;blicherweise verwendeten und auch in diesem Magazin eingef&uuml;hrten Techniken sind.<\/p>\n<p>Au&szlig;erdem zeigen wir, wie diese Elemente dann den entsprechenden Steuerelementen zugewiesen werden.<\/p>\n<h2>Schnelles Einlesen von vielen Icons<\/h2>\n<p>Zuerst schauen wir uns die Funktion zum schnellen Einlesen von mehreren Bilddateien an.<\/p>\n<p>Diese erfordert zun&auml;chst eine Funktion, mit der wir die einzulesenden Dateien per Dateidialog ausw&auml;hlen k&ouml;nnen. Au&szlig;erdem ben&ouml;tigen wir eine Routine, welche die ausgew&auml;hlten Dateien in das Anlagefeld der Tabelle <b>MSysResources <\/b>schreibt. Diese beiden Routinen f&uuml;hren wir in einer aufrufenden Prozedur namens <b>amvFileToResources <\/b>zusammen.<\/p>\n<p>Die Funktion zum Anzeigen des Dateidialogs basiert auf der <b>FileDialog<\/b>-Klasse der Office-Bibliothek, auf die wir noch einen Verweis setzen m&uuml;ssen (siehe Bild 4).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_1557_006.png\" alt=\"Hinzuf&uuml;gen des Verweises auf die Office-Bibliothek\" width=\"499,5589\" height=\"393,8207\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Hinzuf&uuml;gen des Verweises auf die Office-Bibliothek<\/span><\/b><\/p>\n<p>Diese ben&ouml;tigen wir auch sp&auml;ter noch, wenn wir ein Kontextmen&uuml; mit Icons erstellen wollen.<\/p>\n<h2>Steuerung des Einlesevorgangs der Bilddateien<\/h2>\n<p>Die Prozedur <b>amvFileToResources <\/b>steuert unseren Vorgang:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>amvFilesToResources()\r\n     <span style=\"color:blue;\">Dim <\/span>strPaths()<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strPathlist<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>i<span style=\"color:blue;\"> As Integer<\/span>\r\n         \r\n     strPathlist = ChooseFiles\r\n     strPaths() = <span style=\"color:blue;\">Split<\/span>(strPathlist, \"|\")\r\n     For i = <span style=\"color:blue;\">LBound<\/span>(strPaths) To <span style=\"color:blue;\">UBound<\/span>(strPaths)\r\n         <span style=\"color:blue;\">Debug.Print<\/span> strPaths(i)\r\n         amvAddImageToMSysResources strPaths(i)\r\n     <span style=\"color:blue;\">Next<\/span> i\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Sie ruft zun&auml;chst die Funktion <b>amvChooseFiles <\/b>auf, die eine Zeichenkette mit den durch das Pipe-Zeichen (|) getrennten einzelnen Pfaden der einzulesenden Dateien zur&uuml;ckgibt.<\/p>\n<p>Diese Liste speichern wir in der Variablen <b>strPathlist<\/b>. Den Inhalt dieser Variablen teilen wir mit der <b>Split<\/b>-Funktion in ein Array auf, das wir in der Variablen <b>strPaths() <\/b>speichern.<\/p>\n<p>Die Elemente dieses Arrays durchlaufen wir nachfolgend in einer <b>For&#8230;Next<\/b>-Schleife. In dieser Schleife rufen wir f&uuml;r jedes Element einmal die Funktion <b>amvAddImageToMSysResources <\/b>auf, um die jeweilige Datei in einen neuen Datensatz der Tabelle <b>MSysResources <\/b>zu schreiben.<\/p>\n<h2>Die Funktion amvChooseFiles<\/h2>\n<p>Die Funktion zum Ausw&auml;hlen der Dateien nutzt den Dateiauswahldialog der Office-Bibliothek, um dem Benutzer eine flexible Mehrfachauswahl von Dateien zu erm&ouml;glichen, und gibt die Pfade der ausgew&auml;hlten Dateien als durch das Pipe-Zeichen getrennte Zeichenkette zur&uuml;ck (siehe Listing 1). Gleichzeitig merkt sich die Funktion den beim letzten Vorgang verwendeten Ordnerpfad und schl&auml;gt diesen beim n&auml;chsten Aufruf erneut vor, was eine erhebliche Erleichterung bei wiederholter Arbeit mit denselben Ordnern darstellt.Zu Beginn der Funktion werden die n&ouml;tigen Variablen deklariert. Eine dieser Variablen speichert das Initialverzeichnis f&uuml;r den Dateiauswahldialog. Dieser Pfad wird mithilfe der Funktion amv<b>GetAppSetting <\/b>(siehe Modul <b>MDL_AMV_Registry<\/b>) aus dem Bereich der Registry f&uuml;r Anwendungseinstellungen ausgelesen. Ist dort kein Pfad hinterlegt, etwa weil die Funktion zum ersten Mal verwendet wird oder die Einstellung gel&ouml;scht wurde, verwendet die Funktion standardm&auml;&szlig;ig das Verzeichnis der aktuellen Datenbankdatei. Das bedeutet, dass der Benutzer beim ersten Aufruf im Ordner der Datenbank zu arbeiten beginnt, bei weiteren Aufrufen jedoch direkt im zuletzt verwendeten Verzeichnis landet.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>amvChooseFiles()\r\n     <span style=\"color:blue;\">Dim <\/span>objFileDialog<span style=\"color:blue;\"> As <\/span>Office.FileDialog\r\n     <span style=\"color:blue;\">Dim <\/span>strTemp<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>varFilename<span style=\"color:blue;\"> As Variant<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strInitialFilename<span style=\"color:blue;\"> As String<\/span>\r\n     strInitialFilename = amvGetAppSetting(\"InitialFilename\")\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(strInitialFilename) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         strInitialFilename = CurrentProject.Path & \"\\\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> objFileDialog = Application.FileDialog(msoFileDialogOpen)\r\n     <span style=\"color:blue;\">With<\/span> objFileDialog\r\n         .Title = \"Bilddateien ausw&auml;hlen\"\r\n         .ButtonName = \"Ausw&auml;hlen\"\r\n         .AllowMultiSelect = <span style=\"color:blue;\">True<\/span>\r\n         .InitialFileName = strInitialFilename\r\n         .Filters.Clear\r\n         .Filters.Add \"PNG-Dateien\", \"*.png\"\r\n         .Filters.Add \"ICO-Dateien (.ico)\", \"*.ico\"\r\n         <span style=\"color:blue;\">If <\/span>.Show = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> .SelectedItems.Count = 0<span style=\"color:blue;\"> Then<\/span>\r\n                 strInitialFilename = .SelectedItems(1)\r\n                 strInitialFilename = <span style=\"color:blue;\">Left<\/span>(strInitialFilename, <span style=\"color:blue;\">InStrRev<\/span>(strInitialFilename, \"\\\"))\r\n                 For Each varFilename In .SelectedItems\r\n                     strTemp = strTemp & \"|\" & varFilename\r\n                 <span style=\"color:blue;\">Next<\/span> varFilename\r\n                 <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(strTemp) = 0<span style=\"color:blue;\"> Then<\/span>\r\n                     strTemp = <span style=\"color:blue;\">Mid<\/span>(strTemp, 2)\r\n                 <span style=\"color:blue;\">End If<\/span>\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     End <span style=\"color:blue;\">With<\/span>\r\n     amvSaveAppSetting \"InitialFilename\", strInitialFilename\r\n     amvChooseFiles = strTemp\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Ermitteln der einzulesenden Bilddateien per Dateidialog<\/span><\/b><\/p>\n<p>Anschlie&szlig;end wird ein Dialogobjekt vom Typ <b>FileDialog <\/b>mit dem Typ <b>msoFileDialogOpen<\/b> zum Ausw&auml;hlen von Dateien erzeugt. Der Dialog wird so konfiguriert, dass mehrere Dateien auf einmal ausgew&auml;hlt werden k&ouml;nnen. Er erh&auml;lt einen beschreibenden Titel, einen angepassten Beschriftungstext f&uuml;r die Auswahlschaltfl&auml;che sowie zwei Filtereintr&auml;ge: einen f&uuml;r PNG-Dateien und einen f&uuml;r ICO-Dateien.<\/p>\n<p>Zeigt der Benutzer nun den Dialog an und best&auml;tigt die Auswahl, wird &uuml;berpr&uuml;ft, ob &uuml;berhaupt Dateien ausgew&auml;hlt wurden. Ist dies der Fall, wird aus dem Pfad der ersten Datei der zugeh&ouml;rige Ordner extrahiert. Dieser Ordner wird sp&auml;ter als neue Anwendungseinstellung gespeichert, damit er beim n&auml;chsten Aufruf der Funktion wieder als Ausgangspunkt dient. Danach werden alle ausgew&auml;hlten Dateipfade nacheinander in einer Zeichenkette gesammelt. Zwischen den einzelnen Dateipfaden wird das Pipe-Zeichen als Trenner eingef&uuml;gt. Abschlie&szlig;end wird der f&uuml;hrende Trenner entfernt, sodass die R&uuml;ckgabe sauber formatiert ist.<\/p>\n<p>Die Funktion speichert dann den aktualisierten Startordner mithilfe der Prozedur <b>amvSaveAppSetting<\/b>, ebenfalls im Modul <b>MDL_AMV_Registry <\/b>zu finden, und gibt schlie&szlig;lich die Zeichenkette mit den Pfaden der ausgew&auml;hlten Dateien zur&uuml;ck.<\/p>\n<h2>Prozedur zum Speichern der Bilder in der Tabelle MSysResources<\/h2>\n<p>Nach der Auswahl folgt die Prozedur <b>amvAddImageToMSysResources<\/b>. Diese deklariert ein <b>Database<\/b>-Objekt, zwei Recordsets f&uuml;r die Tabelle <b>MSysResources <\/b>und die darin enthaltene interne Tabelle zum Speichern der Attachments und ein <b>Field2<\/b>-Objekt zum Laden der Dateien in das Zielfeld (siehe Listing 2).<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>amvAddImageToMSysResources(ByVal strPath<span style=\"color:blue;\"> As String<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rstResources<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>rstAttachments<span style=\"color:blue;\"> As <\/span>DAO.Recordset2\r\n     <span style=\"color:blue;\">Dim <\/span>fldFileData<span style=\"color:blue;\"> As <\/span>DAO.Field2\r\n     <span style=\"color:blue;\">Dim <\/span>strExtension<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strFilename<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strFilenameWithoutExtension<span style=\"color:blue;\"> As String<\/span>\r\n     strExtension = <span style=\"color:blue;\">Mid<\/span>(strPath, <span style=\"color:blue;\">InStrRev<\/span>(strPath, \".\") + 1)\r\n     strFilename = <span style=\"color:blue;\">Mid<\/span>(strPath, <span style=\"color:blue;\">InStrRev<\/span>(strPath, \"\\\") + 1)\r\n     strFilenameWithoutExtension = <span style=\"color:blue;\">Left<\/span>(strFilename, <span style=\"color:blue;\">InStrRev<\/span>(strFilename, \".\") - 1)\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rstResources = db.OpenRecordset(\"SELECT * FROM MSysResources\", dbOpenDynaset)\r\n     rstResources.Add<span style=\"color:blue;\">New<\/span>\r\n     \r\n     rstResources!Extension = strExtension\r\n     rstResources!Name = strFilenameWithoutExtension\r\n     rstResources!Type = \"img\"\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> rstAttachments = rstResources.Fields(\"Data\").Value\r\n     rstAttachments.Add<span style=\"color:blue;\">New<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> fldFileData = rstAttachments.Fields(\"FileData\")\r\n     fldFileData.LoadFromFile strPath\r\n     rstAttachments.FileName = strFilename\r\n     rstAttachments.Update\r\n     rstAttachments.Close\r\n     <span style=\"color:blue;\">Set<\/span> rstAttachments = Nothing\r\n     \r\n     rstResources.Update\r\n     rstResources.Close\r\n     <span style=\"color:blue;\">Set<\/span> rstResources = Nothing\r\n     <span style=\"color:blue;\">Set<\/span> db = Nothing\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Die Prozedur amvAddImageToMSysResources<\/span><\/b><\/p>\n<p>Die Prozedur erwartet den Pfad der einzulesenden Datei als Parameter. Sie ermittelt zun&auml;chst die Dateiendung und den Dateinamen sowie den Dateinamen ohne Dateiendung und tr&auml;gt diese Daten in die Variablen <b>strExtension<\/b>, <b>strFilename <\/b>und <b>strFilenameWithoutExtensions <\/b>ein.<\/p>\n<p>Dann erstellt sie eine Referenz zum aktuellen <b>Database<\/b>-Objekt und &ouml;ffnet dar&uuml;ber die Tabelle <b>MSysResources<\/b> als Recordset.<\/p>\n<p>Hier f&uuml;gt sie mit <b>AddNew <\/b>einen neuen Datensatz hinzu und tr&auml;gt die Dateiendung in das Feld <b>Extension <\/b>sowie den Dateinamen ohne Dateiendung in das Feld <b>Name <\/b>ein. Als Type wird immer <b>img <\/b>eingetragen.<\/p>\n<p>Nun folgt der spannende Teil. Das zweite Recordset wird mit dem Wert <b>Value <\/b>des Feldes <b>Data <\/b>der Tabelle <b>MSysResources <\/b>gef&uuml;llt, also mit der internen Tabelle zum Speichern der Attachments.<\/p>\n<p>Auch hier f&uuml;gen wir mit <b>AddNew <\/b>einen neuen Datensatz ein und referenzieren dann das Feld <b>FileData <\/b>mit der Variablen <b>fldFileData<\/b>. Die hier verwendete <b>Field2<\/b>-Klasse liefert gegen&uuml;ber der herk&ouml;mmlichen Field-Klasse noch die Methode <b>LoadFromFile<\/b>, die das Einlesen einer Datei in das Feld erm&ouml;glicht. Diese nutzen wir, um die angegebene Datei in das Anlagefeld zu laden. Zus&auml;tzlich stellen wir die Eigenschaft <b>Filename <\/b>auf den Dateinamen ein, diesmal mit Dateierweiterung, und speichern den neu hinzugef&uuml;gten Datensatz der internen Tabelle mit der <b>Update<\/b>-Methode.<\/p>\n<p>Die gleiche Methode rufen wir auch noch f&uuml;r das &uuml;bergeordnete Recordset auf und schlie&szlig;en dann die ge&ouml;ffneten Objekte und geben die Objektvariablen frei.<\/p>\n<h2>Vorbereiten der Tabelle MSysResources mit einigen Bilddateien<\/h2>\n<p>Rufen wir die Prozedur <b>amvFileToResources <\/b>nun auf, erscheint der Dateidialog, mit dem wir die gew&uuml;nschten Bilddateien ausw&auml;hlen k&ouml;nnen. Die ausgew&auml;hlten Dateien werden ohne R&uuml;cksicht auf eventuelle Dubletten in die Tabelle <b>MSysResources <\/b>geschrieben.<\/p>\n<p>Nachdem wir dies erledigt haben, sind einige Dateien in dieser Tabelle gelandet, die wir f&uuml;r die folgenden Techniken als Icons f&uuml;r das Ribbon und f&uuml;r Kontextmen&uuml;s nutzen k&ouml;nnen.<\/p>\n<h2>Bilder im Ribbon anzeigen<\/h2>\n<p>Wenn wir Bilder im Ribbon anzeigen wollen, ben&ouml;tigen wir zweierlei:<\/p>\n<ul>\n<li>Ein Element im Ribbon, dessen <b>image<\/b>-Attribut mit dem Namen des zu verwendenden Bildes aus der Tabelle <b>MSysResources<\/b> gef&uuml;llt ist. Dabei verwenden wir den Namen ohne Dateiendung, so wie er im Feld <b>Name<\/b> der Tabelle eingetragen ist.<\/li>\n<li>Au&szlig;erdem ben&ouml;tigen wir im Element <b>customUI <\/b>das Attribut <b>loadImages<\/b>, das den Namen der Funktion enth&auml;lt, das beim Anzeigen der jeweiligen Elemente zum Einlesen der Bilder genutzt werden soll.<\/li>\n<\/ul>\n<p>Eine der einfachsten m&ouml;glichen Ribbondefinitionen f&uuml;r diesen Zweck haben wir bereits in die f&uuml;r diesen Fall vorbereitete Tabelle <b>USysRibbons <\/b>eingetragen (siehe Bild 5). Das Attribut des <b>button<\/b>-Elements enth&auml;lt den Wert <b>apple<\/b>, was dazu f&uuml;hrt, dass ein Bild namens <b>apple <\/b>angezeigt werden soll. Das Attribut <b>loadImage <\/b>ist mit dem Wert <b>loadImage <\/b>ausgestattet, was bedeutet, dass wir eine gleichnamige Funktion zum Einlesen der Bilder hinterlegen m&uuml;ssen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_1557_004.png\" alt=\"Einfachste m&ouml;gliche Ribbondefinition zum Anzeigen eines benutzerdefinierten Bildes\" width=\"700\" height=\"241,9547\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Einfachste m&ouml;gliche Ribbondefinition zum Anzeigen eines benutzerdefinierten Bildes<\/span><\/b><\/p>\n<p>Funktionen f&uuml;r die Automation von Ribbons hinterlegen wir traditionell in einem Modul namens <b>mdlRibbons<\/b>. In diesem Fall f&uuml;gen wir dort die folgende Funktion ein:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>loadImage(control, ByRef image)\r\n     <span style=\"color:blue;\">Set<\/span> image = amvGetImageFromResourcesByName(control)\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Sie ruft lediglich eine weitere Funktion namens <b>amvGetImageFromResourcesByName <\/b>auf, die den Wert des Parameters <b>control <\/b>&uuml;bergeben bekommt. Diese Funktion liefert das Bild in Form einer Variable des Typs <b>StdPicture <\/b>zur&uuml;ck, die schlie&szlig;lich an die Ribbondefinition zur&uuml;ckgegeben werden kann.<\/p>\n<p>Im Gegensatz zu Prozeduren, die zum Beispiel beim Anklicken eines Ribbonbuttons ausgel&ouml;st werden, liefert <b>control <\/b>hier kein Objekt des Typs <b>IRibbonControl<\/b>, sondern lediglich den Wert des Attributs <b>image <\/b>des jeweils mit einer Bilddatei zu f&uuml;llenden Steuerelements.<\/p>\n<h2>ID der einzuf&uuml;genden Bilddatei ermitteln<\/h2>\n<p>Die Funktion <b>amvGetImageFromResourcesByName <\/b>ist eine Wrapperfunktion, die zu dem &uuml;bergebenen Bildnamen die ID des entsprechenden Datensatzes aus der Tabelle <b>MSysResources <\/b>ermittelt (siehe Listing 3).<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>amvGetImageFromResourcesByName(strName<span style=\"color:blue;\"> As Variant<\/span>)<span style=\"color:blue;\"> As <\/span>StdPicture\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>lngID<span style=\"color:blue;\"> As Long<\/span>\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT ID FROM MSysResources WHERE Name = ''\" & strName & \"''\", dbOpenSnapshot)\r\n     \r\n     Select Case rst.RecordCount\r\n         <span style=\"color:blue;\">Case <\/span>1\r\n             lngID = rst.Fields(0)\r\n             <span style=\"color:blue;\">Set<\/span> amvGetImageFromResourcesByName = amvGetImageFromResources(lngID)\r\n         <span style=\"color:blue;\">Case <\/span>0\r\n             <span style=\"color:blue;\">MsgBox<\/span> \"Bild ''\" & strName & \"'' nicht in der Tabelle MSysResources gefunden.\"\r\n         <span style=\"color:blue;\">Case Else<\/span>\r\n             <span style=\"color:blue;\">MsgBox<\/span> \"Mehr als ein Bild namens ''\" & strName & \"'' in der Tabelle MSysResources vorhanden.\"\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Die Funktion amvGetImageFromResourcesByName<\/span><\/b><\/p>\n<p>Sie ermittelt per Recordset alle Datens&auml;tze, deren Bild den entsprechenden Namen hat.<\/p>\n<p>Die weitere Vorgehensweise h&auml;ngt davon ab, wie viele Datens&auml;tze mit diesem Bildnamen gefunden wurden:<\/p>\n<ul>\n<li>Im Falle eines Bildes wurde zuverl&auml;ssig das richtige Bild gew&auml;hlt &#8211; dann ruft die Funktion eine weitere Funktion namens <b>amvGetImageFromResources <\/b>auf und l&auml;dt so das Bild in das Ribbon (siehe Listing 4).<\/li>\n<pre><span style=\"color:blue;\">Public Function <\/span>amvGetImageFromResources(lngID<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As <\/span>StdPicture\r\n     <span style=\"color:blue;\">Dim <\/span>bytData()<span style=\"color:blue;\"> As Byte<\/span>\r\n     \r\n     <span style=\"color:blue;\">On Error GoTo<\/span> hErr\r\n     \r\n     bytData() = amvAttachmentToByteArray(lngID)\r\n     <span style=\"color:blue;\">Set<\/span> amvGetImageFromResources = amvArrayToStdPicture(bytData)\r\n<span style=\"color:blue;\">Exit Function<\/span>\r\nhErr:\r\n     Err.Clear\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Die Funktion amvGetImageFromResources<\/span><\/b><\/p>\n<li>Wird kein Bild gefunden, erscheint eine entsprechende Meldung.<\/li>\n<li>Wenn mehr als ein Bild gefunden wird, wird ebenfalls eine passende Meldung angezeigt.<\/li>\n<\/ul>\n<h2>Ermitteln des StdPicture-Objekts f&uuml;r die angegebene Ressource<\/h2>\n<p>Die Funktion zum Einlesen einer Ressource in eine Objektvariable des Typs <b>StdPicture <\/b>nimmt die ID des zu verwendenden Datensatzes der Tabelle <b>MSysResources <\/b>entgegen und soll schlie&szlig;lich das <b>StdPicture<\/b>-Objekt zur&uuml;ckliefern.<\/p>\n<p>Dies geschieht in zwei Schritten. Der erste ruft die Funktion <b>amvAttachmentToByteArray <\/b>auf, die das Attachment zun&auml;chst in ein Byte-Array einliest. Das Ergebnis dieser Funktion, das zwischenzeitlich in der Variablen <b>bytData <\/b>landet, wird dann in der Funktion <b>amvArrayToStdPicture <\/b>weiterverarbeitet. Diese liefert schlie&szlig;lich das <b>StdPicture<\/b>-Objekt zur&uuml;ck.<\/p>\n<h2>Funktion zum Erzeugen eines Byte-Arrays aus einem Attachment<\/h2>\n<p>Die Funktion <b>amvAttachmentToByteArray <\/b>aus Listing 5 nimmt den Prim&auml;rschl&uuml;sselwert der Ressource aus der Tabelle <b>MSysResources <\/b>entgegen und liefert ein Byte-Array mit dem Inhalt des Anlagefeldes zur&uuml;ck.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>amvAttachmentToByteArray(lngID<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As Byte<\/span>()\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>bytAttach()<span style=\"color:blue;\"> As Byte<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>bytAttachData()<span style=\"color:blue;\"> As Byte<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngOffset<span style=\"color:blue;\"> As Long<\/span>\r\n<span style=\"color:blue;\">On Error GoTo<\/span> hErr\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT Data.FileData FROM MSysResources WHERE id = \" & lngID, dbOpenSnapshot)\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> rst.EOF<span style=\"color:blue;\"> Then<\/span>\r\n         bytAttachData = rst.Fields(0)\r\n         lngOffset = bytAttachData(0)\r\n         ReDim bytAttach(<span style=\"color:blue;\">UBound<\/span>(bytAttachData) - lngOffset)\r\n         amvCopyMemory bytAttach(0), bytAttachData(lngOffset), <span style=\"color:blue;\">UBound<\/span>(bytAttach)\r\n         amvAttachmentToByteArray = bytAttach\r\n     \r\n         Erase bytAttachData\r\n         Erase bytAttach\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Attachment mit der ID ''\" & lngID & \"'' konnte nicht in MSysResources gefunden werden.\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     \r\n     <span style=\"color:blue;\">Exit Function<\/span>\r\nhErr:\r\n     Err.Clear\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Die Funktion amvAttachmentToByteArray<\/span><\/b><\/p>\n<p>Die Funktion soll aus dem Eintrag der Tabelle <b>MSysResources<\/b> den tats&auml;chlichen Inhalt des gespeicherten Bildes als reines Byte-Array extrahieren. Der besondere Fokus liegt dabei auf der Tatsache, dass Access Anlagen intern mit einem zus&auml;tzlichen Datenkopf versieht.<\/p>\n<p>Dieser Kopf enth&auml;lt Verwaltungsinformationen, die beim sp&auml;teren Verwenden der Daten (zum Beispiel in einem Bildobjekt oder beim Speichern in eine Datei) nicht ben&ouml;tigt und daher entfernt werden m&uuml;ssen. Die Funktion befreit die gespeicherte Datei also von diesem Overhead und liefert nur den reinen, nutzbaren Inhalt zur&uuml;ck.<\/p>\n<p>Ziel der Funktion ist es, f&uuml;r einen &uuml;bergebenen Prim&auml;rschl&uuml;sselwert &#8211; also einen Verweis auf einen Datensatz in <b>MSysResources <\/b>&#8211; den enthaltenen Anlagendatensatz zu lesen, den tats&auml;chlichen Startpunkt der eigentlichen Bin&auml;rdaten zu ermitteln, diese dann isoliert in ein neues Byte-Array zu kopieren und schlie&szlig;lich zur&uuml;ckzugeben. Sie eignet sich somit hervorragend als Bindeglied zwischen der internen Speicherung von Ressourcen in Access und einer externen Weiterverwendung, beispielsweise zur &Uuml;bergabe an Windows-APIs oder wie hier an benutzerdefinierte Ribbon-Schaltfl&auml;chen, die ein <b>StdPicture<\/b>-Objekt erwarten.<\/p>\n<p>Zun&auml;chst werden zwei Byte-Arrays deklariert: <b>bytAttachData<\/b>, welches den vollst&auml;ndigen Inhalt aus dem Anlagenfeld &uuml;bernimmt, und <b>bytAttach<\/b>, das sp&auml;ter den bereinigten, reinen Datenanteil aufnehmen soll.<\/p>\n<p>Eine dritte Variable, <b>lngOffset<\/b>, speichert die Position im Array, ab der der tats&auml;chliche Inhalt beginnt. Dieser Offset wird durch den Wert des ersten Bytes des Arrays bestimmt &#8211; <b>bytAttachData(0) <\/b>-, welches laut interner Speicherstruktur von Access die L&auml;nge des Headers angibt. Dieser Trick ist elementar, da er vermeidet, das genaue Format des Anlagendatentyps analysieren zu m&uuml;ssen. Stattdessen wird das erste Byte als Startmarke interpretiert und als Versatz f&uuml;r das Kopieren der Daten genutzt.<\/p>\n<p>Die Abfrage selbst erfolgt &uuml;ber ein Recordset im Snapshot-Modus, um eine m&ouml;glichst performante und schreibgesch&uuml;tzte Lesung zu gew&auml;hrleisten. Das SQL-Statement greift auf die Spalte <b>FileData <\/b>des eingebetteten Anlagenfelds Data zu. Dies ist m&ouml;glich, da das Anlagenfeld, wie oben bereits erw&auml;hnt, intern als komplexer Datentyp mit Unterfeldern gespeichert wird, wobei <b>FileData <\/b>die eigentlichen Bin&auml;rdaten enth&auml;lt.<\/p>\n<p>Nach dem Lesen des vollst&auml;ndigen Datensatzes und dem Ermitteln des Offsets wird das Zielarray <b>bytAttach <\/b>mit der Gr&ouml;&szlig;e des verbleibenden Datenblocks dimensioniert. Der Copy-Vorgang erfolgt &uuml;ber die API-Funktion <b>amvCopyMemory<\/b>, die wie in Listing 6 neben zwei weiteren, sp&auml;ter noch ben&ouml;tigten API-Funktionen im Kopf des Moduls <b>MDL_AMV_API <\/b>deklariert wird.<\/p>\n<pre><span style=\"color:blue;\">Public <\/span>Declare PtrSafe Sub amvCopyMemory Lib \"Kernel32.dll\" Alias \"RtlMoveMemory\" (Destination<span style=\"color:blue;\"> As <\/span>Any, _\r\n     Source<span style=\"color:blue;\"> As <\/span>Any, ByVal Length<span style=\"color:blue;\"> As Long<\/span>Ptr)\r\n<span style=\"color:blue;\">Public <\/span>Declare PtrSafe Function amvCreateIconFromResourceEx Lib \"user32.dll\" Alias \"CreateIconFromResourceEx\" _\r\n     (presbits<span style=\"color:blue;\"> As <\/span>Any, dwResSize<span style=\"color:blue;\"> As <\/span>Any, ByVal fIcon<span style=\"color:blue;\"> As Long<\/span>, ByVal dwVer<span style=\"color:blue;\"> As Long<\/span>, ByVal cxDesired<span style=\"color:blue;\"> As Long<\/span>, _\r\n     ByVal cyDesired<span style=\"color:blue;\"> As Long<\/span>, ByVal flags<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As Long<\/span>Ptr\r\n<span style=\"color:blue;\">Public <\/span>Declare PtrSafe Function amvSendMessage Lib \"user32\" Alias \"SendMessageA\" (ByVal hwnd<span style=\"color:blue;\"> As Long<\/span>Ptr, _\r\n     ByVal wMsg<span style=\"color:blue;\"> As Long<\/span>, ByVal wParam<span style=\"color:blue;\"> As Long<\/span>Ptr, lParam<span style=\"color:blue;\"> As <\/span>Any)<span style=\"color:blue;\"> As Long<\/span>Ptr<\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Die f&uuml;r die vorliegende L&ouml;sung ben&ouml;tigten API-Funktionen<\/span><\/b><\/p>\n<p>Die API-Deklarationen haben wir bewusst jeweils mit dem Pr&auml;fix <b>amv&#8230; <\/b>versehen. Dazu ist es erforderlich, die urspr&uuml;ngliche API-Funktion mit dem Parameter <b>ALIAS <\/b>zu versehen. Der Sinn dieser Aktion ist, dass diese Funktionen gegebenenfalls in VBA-Projekte eingef&uuml;gt werden, die bereits &uuml;ber die eine oder andere dieser API-Funktionen verf&uuml;gt. Damit diese nicht m&uuml;hsam abgeglichen werden m&uuml;ssen, haben wir einfach unseren eigenen Satz von API-Funktionen bereitgestellt.<\/p>\n<p>Mit <b>amvCopyMemory<\/b> werden die reinen Daten ab der Offset-Position aus dem urspr&uuml;nglichen Array in das neue Array geschrieben &#8211; bytegenau und ohne den Headeranteil.<\/p>\n<p>Nach dem erfolgreichen Kopieren wird das bereinigte Array als Ergebnis der Funktion zur&uuml;ckgegeben. Zus&auml;tzlich werden die beiden internen Arrays am Ende der Funktion mit <b>Erase <\/b>freigegeben, um den Arbeitsspeicher zu entlasten.<\/p>\n<p>Tritt w&auml;hrend des Prozesses ein Fehler auf, springt der Code in die Fehlerbehandlung, die hier nur aus einem <b>Err.Clear <\/b>besteht. Damit wird ein eventueller Fehlerzustand gel&ouml;scht, ohne dass eine Meldung angezeigt wird. Dies ist in Situationen n&uuml;tzlich, in denen bewusst fehlertolerant gearbeitet werden soll &#8211; etwa, wenn der Aufrufer entscheidet, was im Fehlerfall zu tun ist.<\/p>\n<h2>Funktion zum &Uuml;berf&uuml;hren des Byte-Arrays in ein StdPicture-Objekt<\/h2>\n<p>Die Funktion <b>amvArrayToStdPicture <\/b>aus Listing 7 dient der Umwandlung eines <b>Byte<\/b>-Arrays in ein Objekt des Typs <b>StdPicture<\/b>.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>amvArrayToStdPicture(bytArray()<span style=\"color:blue;\"> As Byte<\/span>)<span style=\"color:blue;\"> As <\/span>StdPicture\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> hErr\r\n     <span style=\"color:blue;\">With<\/span> CreateObject(\"WIA.Vector\")\r\n         .BinaryData = bytArray\r\n         <span style=\"color:blue;\">Set<\/span> amvArrayToStdPicture = .Picture\r\n     End <span style=\"color:blue;\">With<\/span>\r\n     <span style=\"color:blue;\">Exit Function<\/span>\r\nhErr:\r\n     Err.Clear\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 7: Funktion zum Umwandeln des Byte-Arrays in ein StdPicture-Objekt<\/span><\/b><\/p>\n<p>Die Funktion nutzt daf&uuml;r auf elegante Weise die <b>Windows Image Acquisition<\/b>-Bibliothek (kurz: <b>WIA<\/b>), die seit Windows XP Bestandteil des Betriebssystems ist und &uuml;ber COM bereitgestellt wird.<\/p>\n<p>Das zentrale Ziel der Funktion ist es, das Bild aus dem <b>Byte<\/b>-Array direkt in ein <b>StdPicture<\/b>-Objekt zu &uuml;berf&uuml;hren.<\/p>\n<p>Die Funktion erstellt ein neues Objekt auf Basis der WIA-Bibliothek, konkret ein sogenanntes Vector-Objekt. Dieses Objekt dient der Aufnahme von bin&auml;ren Daten und verf&uuml;gt &uuml;ber eine Eigenschaft <b>BinaryData<\/b>, der das Byte-Array direkt zugewiesen wird. Intern analysiert die WIA-Bibliothek das Format der Bin&auml;rdaten &#8211; typischerweise PNG, JPG oder BMP &#8211; und wandelt diese automatisch in eine Bilddarstellung um, sofern das Format g&uuml;ltig ist.<\/p>\n<p>Sobald das Byte-Array zugewiesen wurde, steht das resultierende Bild &uuml;ber die Eigenschaft <b>Picture <\/b>als COM-Objekt vom Typ <b>StdPicture <\/b>zur Verf&uuml;gung. Dieses Objekt wird dann &uuml;ber <b>Set <\/b>an die Funktion zur&uuml;ckgegeben.<\/p>\n<p>Die Eleganz dieser L&ouml;sung liegt vor allem in der Kombination von Einfachheit und Effektivit&auml;t: In nur wenigen Codezeilen wird ein h&auml;ufig komplexer Vorgang &#8211; das Interpretieren von Bilddaten und deren Konvertierung in eine COM-kompatible Darstellung &#8211; vollst&auml;ndig gel&ouml;st. Besonders hervorzuheben ist, dass keinerlei tempor&auml;re Dateien oder externe Bibliotheken notwendig sind. Die WIA-Bibliothek ist in der Regel bereits auf jedem Windows-System vorhanden und erfordert lediglich den passenden Verweis, wobei <b>CreateObject<\/b> in diesem Fall sogar ohne expliziten Verweis in den VBA-Verweiseinstellungen funktioniert.<\/p>\n<h2>Testen der Funktionen zum Anzeigen eines Bildes aus MSysResources im Ribbon<\/h2>\n<p>Damit haben wir fast alles zusammen. Wir m&uuml;ssen dies nur noch testen, was wir der Einfachheit halber ohne aufwendiges &Ouml;ffnen und Schlie&szlig;en erledigen wollen.<\/p>\n<p>Dazu erstellen wir ein Testformular, f&uuml;r dessen <b>Beim Laden<\/b>-Ereignis wir die Prozedur aus Listing 8 hinterlegen.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     <span style=\"color:blue;\">Dim <\/span>strRibbonName<span style=\"color:blue;\"> As String<\/span>\r\n     strRibbonName = \"Ribbon_\" & Format(Now, \"yyyymmdd_hhnnss\")\r\n     Application.LoadCustomUI strRibbonName, DLookup(\"RibbonXML\", \"USysRibbons\", \"RibbonName = ''Einfache Buttons''\")\r\n     Me.RibbonName = strRibbonName\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 8: Prozedur zum Anzeigen einer Ribbondefinition beim Laden eines Formulars<\/span><\/b><\/p>\n<p>Diese erstellt einen neuen, tempor&auml;ren Ribbonnamen, der aus der Zeichenkette <b>ribbon <\/b>und dem aktuellen Zeitpunkt im Format <b>yyyymmdd_hhnnss <\/b>besteht. Dieses Ribbon laden wir mit der Methode <b>LoadCustomUI <\/b>in den Ribbonspeicher und weisen das Ribbon mit diesem Namen der Eigenschaft <b>RibbonName <\/b>des Formulars zu. So wird das Ribbon direkt beim &Ouml;ffnen des Formulars angezeigt (siehe Bild 6).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_1557_005.png\" alt=\"Das benutzerdefinierte Ribbon mit Bild aus der Tabelle MSysResources\" width=\"649,559\" height=\"386,6683\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Das benutzerdefinierte Ribbon mit Bild aus der Tabelle MSysResources<\/span><\/b><\/p>\n<p>Wann immer wir die Ribbondefinition &auml;ndern, brauchen wir nur das Formular erneut zu &ouml;ffnen und sehen direkt den aktuellen Stand.<\/p>\n<h2>Benutzerdefinierte Bilder im Kontextmen&uuml; anzeigen<\/h2>\n<p>Auf &auml;hnliche Weise wie im Ribbon k&ouml;nnen wir auch in Kontextmen&uuml;s die Funktionen zum Umwandeln von <b>Attachments <\/b>in <b>StdPicture<\/b>-Objekte erledigen.<\/p>\n<p>Dazu haben wir ein weiteres Formular namens <b>frmContextMenu <\/b>angelegt.<\/p>\n<p>Diesem f&uuml;gen wir zun&auml;chst eine Objektvariable namens <b>cbb <\/b>f&uuml;r die Schaltfl&auml;che im Kontextmen&uuml; hinzu, die wir mit dem Schl&uuml;sselwort <b>WithEvents <\/b>deklarieren:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>WithEvents cbb<span style=\"color:blue;\"> As <\/span>CommandBarButton<\/pre>\n<p>Damit ein benutzerdefiniertes Kontextmen&uuml; angezeigt wird, m&uuml;ssen wir dazu ein entsprechendes Ereignis definieren, in diesem Fall das Ereignis <b>Bei Maustaste <\/b>auf des Detailbereichs des Formulars.<\/p>\n<p>F&uuml;r dieses Ereignis hinterlegen wir die Prozedur aus Listing 9.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Detailbereich_MouseUp(Button<span style=\"color:blue;\"> As Integer<\/span>, Shift<span style=\"color:blue;\"> As Integer<\/span>, X<span style=\"color:blue;\"> As Single<\/span>, Y<span style=\"color:blue;\"> As Single<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>cbr<span style=\"color:blue;\"> As <\/span>CommandBar\r\n     <span style=\"color:blue;\">If <\/span>Button = 2<span style=\"color:blue;\"> Then<\/span>\r\n         On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n         CommandBars(\"Beispiel\").Delete\r\n         <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n         Me.ShortcutMenu = <span style=\"color:blue;\">False<\/span>\r\n         <span style=\"color:blue;\">Set<\/span> cbr = CommandBars.Add(\"Beispiel\", msoBarPopup, , <span style=\"color:blue;\">True<\/span>)\r\n         <span style=\"color:blue;\">Set<\/span> cbb = cbr.Controls.Add(msoControlButton)\r\n         <span style=\"color:blue;\">With<\/span> cbb\r\n             .Picture = amvArrayToPictureFromResource(2)\r\n         End <span style=\"color:blue;\">With<\/span>\r\n         cbr.ShowPopup\r\n         Me.TimerInterval = 100\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 9: Ereignisprozedur zum Anzeigen eines Kontextmen&uuml;s<\/span><\/b><\/p>\n<p>Die Prozedur pr&uuml;ft, ob der Benutzer die rechte Maustaste bet&auml;tigt hat. Dann l&ouml;scht sie eine eventuell bereits vorhandene Instanz des Kontextmen&uuml;s und erstellt dieses neu. Au&szlig;erdem deaktiviert sie f&uuml;r diesen Moment das eingebaute Kontextmen&uuml;, indem sie den Wert der Eigenschaft <b>ShortcutMenu <\/b>auf <b>False <\/b>einstellt.<\/p>\n<p>Danach f&uuml;gt sie die Schaltfl&auml;che zum Kontextmen&uuml; hinzu und stellt die <b>Picture<\/b>-Eigenschaft auf das Ergebnis der Funktion <b>amvArrayToPictureFromResource <\/b>ein. Dieser &uuml;bergeben wir hier direkt die Nummer des Datensatzes der Tabelle <b>MSysResources <\/b>mit der zu verwendenden Bilddatei. Wir k&ouml;nnten auch hier die Funktion <b>GetImageFromResourcesByName <\/b>verwenden und wie im vorherigen Beispiel den Namen der zu verwendenden Ressource &uuml;bergeben. Diese w&uuml;rden wir wie folgt nutzen:<\/p>\n<pre>...\r\n<span style=\"color:blue;\">With<\/span> cbb\r\n     .Caption = \"Beispielbutton\"\r\n     .Picture = amvGetImageFromResourcesByName(\"apple\")\r\n     .Mask = CreateMaskFromStdPicture(.Picture)\r\nEnd <span style=\"color:blue;\">With<\/span>\r\n...<\/pre>\n<p>Die <b>ShowPopup<\/b>-Methode zeigt schlie&szlig;lich das Kontextmen&uuml; wie in Bild 7 an.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_1557_008.png\" alt=\"Kontextmen&uuml; mit Icon aus der Tabelle MSysResources\" width=\"424,5589\" height=\"163,6853\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Kontextmen&uuml; mit Icon aus der Tabelle MSysResources<\/span><\/b><\/p>\n<p>Wenn wir nun direkt wieder die Eigenschaft <b>ShortcutMenu <\/b>auf <b>True <\/b>einstellen w&uuml;rden, w&uuml;rde direkt im Anschluss das eingebaute Men&uuml; erscheinen. Deshalb stellen wir einen Timer durch Setzen der Eigenschaft <b>TimerInterval <\/b>auf den Wert <b>100 <\/b>(Millisekunden), der das Ereignis <b>Bei Zeitgeber <\/b>ausl&ouml;st.<\/p>\n<p>In diesem setzen wir <b>ShortcutMenu <\/b>wieder auf den Wert <b>True <\/b>und deaktivieren den Timer durch Einstellen von <b>TimerInterval <\/b>auf den Wert <b>0<\/b>.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Timer()\r\n     Me.ShortcutMenu = <span style=\"color:blue;\">True<\/span>\r\n     Me.TimerInterval = 0\r\n<span style=\"color:blue;\">End Sub<\/span> <\/pre>\n<p>Schlie&szlig;lich legen wir noch eine Ereignisprozedur f&uuml;r die Kontextmen&uuml;-Schaltfl&auml;che an, die wir mit einer einfachen <b>MsgBox<\/b>-Anweisung f&uuml;llen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cbb_Click(ByVal Ctrl<span style=\"color:blue;\"> As <\/span>_\r\n         Office.CommandBarButton, CancelDefault<span style=\"color:blue;\"> As Boolean<\/span>)\r\n     <span style=\"color:blue;\">MsgBox<\/span> \"Button geklickt\"\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Einen kleinen Haken hat diese Vorgehensweise: Die so &uuml;bergebenen Bilder behalten ihre Transparenz-Informationen nicht bei. Deshalb ist der Hintergrund auch beim &Uuml;berfahren des Kontextmen&uuml;-Befehls mit der Maus wei&szlig; &#8211; im Gegensatz zum Rest des Buttons.<\/p>\n<p>Daf&uuml;r m&uuml;ssen wir dann doch noch ein wenig tiefer in die API-Trickkiste greifen.<\/p>\n<p>Erst einmal f&uuml;gen wir hinter der Zuweisung der <b>Picture<\/b>-Eigenschaft noch die <b>Mask<\/b>-Eigenschaft hinzu:<\/p>\n<pre>...\r\n.Picture = amvArrayToPictureFromResource(2)\r\n.Mask = amvCreateMaskFromStdPicture(.Picture)\r\n...<\/pre>\n<p>Diese Funktion finden Sie in Listing 10. Sie nimmt den Verweis auf das <b>StdPicture<\/b>-Objekt entgegen, f&uuml;r das wir die Maske erstellen wollen.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>amvCreateMaskFromStdPicture(ByVal pic<span style=\"color:blue;\"> As <\/span>StdPicture)<span style=\"color:blue;\"> As <\/span>StdPicture\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> ErrHandler\r\n     Const BI_<span style=\"color:blue;\">RGB<\/span> = 0\r\n     Const DIB_RGB_COLORS = 0\r\n     <span style=\"color:blue;\">Dim <\/span>lngWidth<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngHeight<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>hDC<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>hBitmapMask<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>hBitmapOrig<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>hDCMask<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>hDCOrig<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>x<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>y<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>clr<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>IPic<span style=\"color:blue;\"> As <\/span>IPictureDisp\r\n     lngWidth = pic.width \\ 26.458\r\n     lngHeight = pic.height \\ 26.458\r\n     hBitmapMask = amvCreateCompatibleBitmap(amvGetDC(0), lngWidth, lngHeight)\r\n     hDCMask = amvCreateCompatibleDC(0)\r\n     amvSelectObject hDCMask, hBitmapMask\r\n     hBitmapOrig = pic.Handle\r\n     hDCOrig = amvCreateCompatibleDC(0)\r\n     amvSelectObject hDCOrig, hBitmapOrig\r\n     For x = 0 To lngWidth - 1\r\n         For y = 0 To lngHeight - 1\r\n             clr = amvGetPixel(hDCOrig, x, y)\r\n             <span style=\"color:blue;\">If <\/span>clr &lt;&gt; <span style=\"color:blue;\">RGB<\/span>(255, 255, 255)<span style=\"color:blue;\"> Then<\/span>\r\n                 amvSetPixel hDCMask, x, y, <span style=\"color:blue;\">RGB<\/span>(0, 0, 0)\r\n             <span style=\"color:blue;\">Else<\/span>\r\n                 amvSetPixel hDCMask, x, y, <span style=\"color:blue;\">RGB<\/span>(255, 255, 255)\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">Next<\/span> y\r\n     <span style=\"color:blue;\">Next<\/span> x\r\n     <span style=\"color:blue;\">Set<\/span> IPic = amvCreatePicture(hBitmapMask)\r\n     <span style=\"color:blue;\">Set<\/span> amvCreateMaskFromStdPicture = IPic\r\nExitHere:\r\n     amvDeleteDC hDCOrig\r\n     amvDeleteDC hDCMask\r\n     <span style=\"color:blue;\">Call<\/span> amvReleaseDC(0, hDC)\r\n     <span style=\"color:blue;\">Exit Function<\/span>\r\nErrHandler:\r\n     <span style=\"color:blue;\">MsgBox<\/span> \"Fehler: \" & Err.Description, <span style=\"color:blue;\">vbCr<\/span>itical\r\n     Resume ExitHere\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 10: Funktion zum Erstellen der Maske f&uuml;r die Transparenz des Icons im Kontextmen&uuml;<\/span><\/b><\/p>\n<p>Diese verwendet eine ganze Reihe API-Funktionen, die wir wieder im Modul <b>MDL_AMV_API <\/b>deklariert haben.<\/p>\n<p>Das resultierende <b>StdPicture<\/b>-Element f&uuml;r die Maske enth&auml;lt schwarze Pixel f&uuml;r die sichtbaren Elemente des Icons und wei&szlig;e Pixel f&uuml;r die transparenten Elemente und bildet so die Transparenz ab.<\/p>\n<p>Wenn wir nun mit der Maus &uuml;ber den Kontextmen&uuml;-Eintrag fahren, wird auch der wei&szlig;e Hintergrund des Icons transparent angezeigt und nimmt somit die Farbe der restlichen Schaltfl&auml;che an (siehe Bild 8).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_1557_009.png\" alt=\"Kontextmen&uuml;, diesmal mit transparentem Hintergrund\" width=\"424,5589\" height=\"200,6795\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Kontextmen&uuml;, diesmal mit transparentem Hintergrund<\/span><\/b><\/p>\n<h2>Icons in Formularen<\/h2>\n<p>Als vorletztes Beispiel f&uuml;gen wir noch Code zum Beispiel hinzu, mit dem wir das Standard-Icon in Formularen durch ein benutzerdefiniertes Icon ersetzen k&ouml;nnen. Dazu ben&ouml;tigen wir wiederum eine Funktion, die wir in Listing 11 abgebildet haben. Die einzelnen Schritte wollen wir hier nicht im Detail erl&auml;utern.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>amvSetFormIconFromTable(ByVal hWnd<span style=\"color:blue;\"> As Long<\/span>Ptr, lngID<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As Long<\/span>Ptr\r\n     <span style=\"color:blue;\">Dim <\/span>bytData()<span style=\"color:blue;\"> As Byte<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>dwOffset<span style=\"color:blue;\"> As Long<\/span>Ptr\r\n     <span style=\"color:blue;\">Dim <\/span>dwSize<span style=\"color:blue;\"> As Long<\/span>Ptr\r\n     <span style=\"color:blue;\">Dim <\/span>lngIndex<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngIcon<span style=\"color:blue;\"> As Long<\/span>Ptr\r\n     \r\n     Const ICRESVER<span style=\"color:blue;\"> As Long<\/span> = &H30000\r\n     Const LR_DEFAULTSIZE<span style=\"color:blue;\"> As Long<\/span> = &H40\r\n     Const WM_SETICON<span style=\"color:blue;\"> As Long<\/span> = &H80\r\n     Const ICON_SMALL<span style=\"color:blue;\"> As Long<\/span> = 0\r\n     \r\n     <span style=\"color:blue;\">On Error GoTo<\/span> hErr\r\n     bytData() = amvAttachmentToByteArray(lngID)\r\n     dwSize = VarPtr(bytData(16 * lngIndex + 14))\r\n     dwOffset = VarPtr(bytData(bytData(16 * lngIndex + 18)))\r\n     lngIcon = amvCreateIconFromResourceEx(ByVal dwOffset, ByVal dwSize, 1, ICRESVER, 0&, 0&, LR_DEFAULTSIZE)\r\n     \r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> lngIcon = 0<span style=\"color:blue;\"> Then<\/span>\r\n         amvSetFormIconFromTable = lngIcon\r\n         amvSendMessage hWnd, WM_SETICON, ICON_SMALL, ByVal lngIcon\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">Exit Function<\/span>\r\nhErr:\r\n     Err.Clear\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 11: Diese Funktion schickt ein Icon an das Formular, dessen Handle &uuml;bergeben wurde.<\/span><\/b><\/p>\n<p>Auch hier haben wir wieder eine Wrapper-Funktion erstellt, der wir statt der <b>ID <\/b>des zu verwendenden Icons aus der Tabelle <b>MSysResources <\/b>den Namen des Icons &uuml;bergeben k&ouml;nnen (siehe Listing 12).<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>amvSetFormIconFromTableByName(ByVal hWnd<span style=\"color:blue;\"> As Long<\/span>Ptr, strIcon<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Long<\/span>Ptr\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>lngID<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT ID, Extension FROM MSysResources WHERE Name = ''\" & strIcon & \"''\", _\r\n         dbOpenSnapshot)\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> rst!Extension = \"ico\"<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Icons f&uuml;r Formulare m&uuml;ssen in MSysResources als .ico-Datei gespeichert sein.\"\r\n         <span style=\"color:blue;\">Exit Function<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     Select Case rst.RecordCount\r\n         <span style=\"color:blue;\">Case <\/span>1\r\n             lngID = rst.Fields(0)\r\n             amvSetFormIconFromTableByName = amvSetFormIconFromTable(hWnd, lngID)\r\n         <span style=\"color:blue;\">Case <\/span>0\r\n             <span style=\"color:blue;\">MsgBox<\/span> \"Bild ''\" & strIcon & \"'' nicht in der Tabelle MSysResources gefunden.\"\r\n         <span style=\"color:blue;\">Case Else<\/span>\r\n             <span style=\"color:blue;\">MsgBox<\/span> \"Mehr als ein Bild namens ''\" & strIcon & \"'' in der Tabelle MSysResources vorhanden.\"\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 12: Wrapper-Funktion zum Setzen eines Formular-Icons &uuml;ber den Namen des Icons aus der Tabelle MSysResources<\/span><\/b><\/p>\n<p>Hier pr&uuml;fen wir zuerst, ob das angegebene Element der Tabelle <b>MSysResources <\/b>die Dateiendung <b>.ico <\/b>hat, denn Formulare k&ouml;nnen nur <b>.ico<\/b>-Dateien als Icon anzeigen. Ist das nicht der Fall, wird die Funktion mit einer Meldung beendet. Danach testen wir wieder, ob es genau eine Datei mit diesem Namen in der Tabelle <b>MSysResources <\/b>gibt. Anderenfalls erscheinen entsprechende Fehlermeldungen.<\/p>\n<p>Um einem Formular mit dieser Funktion ein Icon zuzuweisen, f&uuml;gen wir in der Ereignisprozedur f&uuml;r <b>Beim Laden <\/b>beispielsweise die folgende Anweisung hinzu:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     <span style=\"color:blue;\">Call<\/span> amvSetFormIconFromTableByName(Me.hWnd, _\r\n         \"3d_glasses\")\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Ein Formular mit einem auf diese Weise hinzugef&uuml;gten Icon sehen wir in Bild 9.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_1557_010.png\" alt=\"Formular mit Formularicon\" width=\"424,5589\" height=\"205,882\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 9: Formular mit Formularicon<\/span><\/b><\/p>\n<h2>Icons im TreeView- und ListView-Steuerelement<\/h2>\n<p>Damit schauen wir uns auch noch die letzte M&ouml;glichkeit an, Icons in Access-Anwendungen anzuzeigen.<\/p>\n<p>Den beiden Steuerelementen <b>TreeView <\/b>und <b>ListView <\/b>k&ouml;nnen wir allerdings nicht direkt mit einer VBA-Funktion Icons zuweisen. Sie erfordern zwingend das Vorhandensein eines weiteren Steuerelements, und zwar das <b>ImageList<\/b>-Steuerelement.<\/p>\n<p>Wir bauen schnell ein Beispiel auf, indem wir einem Formular ein <b>ImageList<\/b>&#8211; und ein <b>TreeView<\/b>-Steuerelement hinzuf&uuml;gen (siehe Bild 10). Das <b>ImageList<\/b>-Steuerelement ist sp&auml;ter nicht sichtbar.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_1557_011.png\" alt=\"Formular mit ImageList und TreeView\" width=\"499,5589\" height=\"374,1635\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 10: Formular mit ImageList und TreeView<\/span><\/b><\/p>\n<p>Die beiden Steuerelemente benennen wir in <b>imgl <\/b>und <b>tvw <\/b>um. Anschlie&szlig;end f&uuml;gen wir dem Ereignis <b>Beim Laden <\/b>des Formulars die Prozedur aus Listing 13 hinzu.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     <span style=\"color:blue;\">Dim <\/span>objFolder<span style=\"color:blue;\"> As <\/span>MSComctlLib.Node\r\n     amvAddIconToImageListFromResourcesByName Me.imgl.Object, \"folder\"\r\n     amvAddIconToImageListFromResourcesByName Me.imgl.Object, \"document_empty\"\r\n     \r\n     <span style=\"color:blue;\">With<\/span> Me.tvw\r\n         .ImageList = Me.imgl.Object\r\n         \r\n         .Nodes.Clear\r\n         <span style=\"color:blue;\">Set<\/span> objFolder = .Nodes.Add(, , \"root\", \"Root\", \"folder\")\r\n         <span style=\"color:blue;\">With<\/span> objFolder\r\n             .Expanded = <span style=\"color:blue;\">True<\/span>\r\n         End <span style=\"color:blue;\">With<\/span>\r\n         \r\n         .Nodes.Add \"root\", tvwChild, \"child1\", \"Datei 1\", \"document_empty\"\r\n         .Nodes.Add \"root\", tvwChild, \"child2\", \"Datei 2\", \"document_empty\"\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 13: F&uuml;llen des ImageList- und des TreeView-Steuerelements<\/span><\/b><\/p>\n<p>Diese Prozedur deklariert ein <b>Node<\/b>-Objekt f&uuml;r das oberste Element der Hierarchie &#8211; wir wollen ein <b>Folder<\/b>&#8211; und zwei <b>Document<\/b>-Elemente hinzuzuf&uuml;gen, um das Einf&uuml;gen von Icons zu demonstrieren.<\/p>\n<p>Zuerst bef&uuml;llen wir das <b>ImageList<\/b>-Steuerelement mit den ben&ouml;tigten Icons. Dazu rufen wir zwei Mal die Funktion <b>amvAddIconToImageListFromResourcesByName <\/b>auf &#8211; diese erl&auml;utern wir weiter unten. Der Funktion &uuml;bergeben wir jeweils einen Verweis auf das zu f&uuml;llende <b>ImageList<\/b>-Steuerelement sowie den Namen des zu verwendenden Icons aus der Tabelle <b>MSysResources<\/b>.<\/p>\n<p>Beim &Uuml;bergeben des <b>ImageList<\/b>-Steuerelements an den Parameter des Typs <b>MSComctlLib.ImageList <\/b>m&uuml;ssen wir beachten, dass wir nicht direkt einen Verweis auf das Steuerelement &uuml;bergeben k&ouml;nnen, sondern die Eigenschaft <b>Object <\/b>verwenden m&uuml;ssen.<\/p>\n<p>Danach f&uuml;llen wir das <b>TreeView<\/b>-Steuerelement mit ein paar Beispielelementen. Als Erstes f&uuml;gen wir jedoch der Eigenschaft <b>ImageList <\/b>einen Verweis auf das <b>ImageList<\/b>-Steuerelement hinzu, wieder mit seiner Eigenschaft <b>Object<\/b>. So wei&szlig; das <b>TreeView<\/b>-Steuerelement, woher es seine Icons beziehen soll.<\/p>\n<p>Danach leeren wir das <b>TreeView<\/b>-Steuerelement, indem wir f&uuml;r die <b>Nodes<\/b>-Auflistung die <b>Clear<\/b>-Methode aufrufen.<\/p>\n<p>Schlie&szlig;lich f&uuml;gen wir das Root-Element hinzu, indem wir die <b>Add<\/b>-Methode der <b>Nodes<\/b>-Auflistung ausf&uuml;hren. Dieser &uuml;bergeben wir mit dem dritten, vierten und f&uuml;nften Parameter den Key des Elements, den anzuzeigenden Text und den Namen der zu verwendenden Bilddatei aus dem <b>ImageList<\/b>-Steuerelement.<\/p>\n<p>Das neue Element referenzieren wir mit der Variablen <b>objFolder<\/b>, damit wir seine Eigenschaft <b>Expanded <\/b>auf <b>True <\/b>einstellen k&ouml;nnen. So wird das Element direkt aufgeklappt angezeigt.<\/p>\n<p>Danach f&uuml;gen wir noch die beiden Unterelemente hinzu. Dazu verwenden wir wiederum die <b>Add<\/b>-Methode der <b>Nodes<\/b>-Auflistung.<\/p>\n<p>Diesmal &uuml;bergeben wir neben den bereits im vorherigen Aufruf verwendeten Parametern auch noch den ersten und zweiten Parameter.<\/p>\n<p>Der erste Parameter nimmt einen Verweis auf das <b>Node<\/b>-Element entgegen, zu dem wir das neue Element in Relation setzen wollen. Dem zweiten Parameter &uuml;bergeben wir die Art der Beziehung.<\/p>\n<p>In diesem Fall soll das neue Element unterhalb des angegebenen Elements angeordnet werden, also verwenden wir die Konstante <b>tvwChild<\/b>.<\/p>\n<p>Damit ist das F&uuml;llen des TreeViews erledigt und wir k&ouml;nnen uns dem Laden der Bilder aus der Tabelle <b>MSysResources <\/b>in das <b>ImageList<\/b>-Steuerelement zuwenden.<\/p>\n<h2>Icons in das ImageList-Steuerelement laden<\/h2>\n<p>Die Aufgabe, Icons aus der Tabelle <b>MSysResources<\/b> in das <b>ImageList<\/b>-Steuerelement zu schreiben, k&ouml;nnen wir auf einem kleinen Umweg wieder mit der bereits zuvor vorgestellten Funktion <b>amvGetImageFromResources <\/b>erledigen.<\/p>\n<p>Wir beginnen diesmal direkt mit der Wrapper-Funktion, der wir den Namen des zu verwendenden Icons &uuml;bergeben k&ouml;nnen. Sie hei&szlig;t in diesem Fall <b>amvAddIconToImageListFromResources<\/b> (siehe Listing 14).<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>amvAddIconToImageListFromResourcesByName(objImageList<span style=\"color:blue;\"> As <\/span>MSComctlLib.ImageList, strIconName<span style=\"color:blue;\"> As String<\/span>, _\r\n         <span style=\"color:blue;\">Optional<\/span> strAlternativeKey<span style=\"color:blue;\"> As String<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>lngID<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT ID FROM MSysResources WHERE Name = ''\" & strIconName & \"''\", dbOpenSnapshot)\r\n     Select Case rst.RecordCount\r\n         <span style=\"color:blue;\">Case <\/span>1\r\n             lngID = rst.Fields(0)\r\n             <span style=\"color:blue;\">Call<\/span> amvAddIconToImageListFromResources(objImageList, lngID, strAlternativeKey)\r\n         <span style=\"color:blue;\">Case <\/span>0\r\n             <span style=\"color:blue;\">MsgBox<\/span> \"Bild ''\" & strIconName & \"'' nicht in der Tabelle MSysResources gefunden.\"\r\n         <span style=\"color:blue;\">Case Else<\/span>\r\n             <span style=\"color:blue;\">MsgBox<\/span> \"Mehr als ein Bild namens ''\" & strIconName & \"'' in der Tabelle MSysResources vorhanden.\"\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 14: Wrapper-Funktion zum Einlesen von Bildern aus der Tabelle MSysResources in ein ImageList-Steuerelement<\/span><\/b><\/p>\n<p>Die Funktion nimmt die folgenden Parameter entgegen:<\/p>\n<ul>\n<li><b>objImageList<\/b>: Parameter des Typs <b>MSComctlLib.ImageList <\/b>zum Entgegennehmen des Verweises auf das zu f&uuml;llende <b>ImageList<\/b>-Steuerelement<\/li>\n<li><b>strIconName<\/b>: Name des zu verwendenden Icons aus der Tabelle <b>MSysResources<\/b><\/li>\n<li><b>strAlternativeKey<\/b>: Optionaler Parameter, der verwendet werden kann, um das Element in der <b>ImageList <\/b>unter einem anderen <b>Key <\/b>als dem Namen des Elements aus der Tabelle <b>MSysResources <\/b>abzuspeichern.<\/li>\n<\/ul>\n<p>Die Funktion holt die ID zu dem angegebenen Namen aus der Tabelle <b>MSysResources <\/b>und pr&uuml;ft wieder, ob genau ein Element dieses Namens vorhanden ist. Danach ruft sie die Funktion <b>amvAddIconToImageListFromResources <\/b>auf und &uuml;bergibt die relevanten Parameter.<\/p>\n<p>Die Funktion <b>amvAddIconToImageListFromResources<\/b> nimmt &auml;hnliche Parameter entgegen wie die zuvor beschriebene Funktion &#8211; allerdings wird der Parameter <b>strIconName <\/b>durch den Parameter <b>ID <\/b>des zuvor ermittelten Eintrags der Tabelle <b>MSysResources<\/b> ersetzt (siehe Listing 15). <b>strAlternativeKey <\/b>&uuml;bergeben wir wieder, wenn nicht der Name des Bildes aus der Tabelle <b>MSysResources <\/b>als <b>Key <\/b>verwendet werden soll, sondern eine andere Zeichenkette.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>amvAddIconToImageListFromResources(objImageList<span style=\"color:blue;\"> As Object<\/span>, lngID<span style=\"color:blue;\"> As Long<\/span>, _\r\n         <span style=\"color:blue;\">Optional<\/span> strAlternativeKey<span style=\"color:blue;\"> As <\/span>_String)\r\n     <span style=\"color:blue;\">Dim <\/span>pic<span style=\"color:blue;\"> As <\/span>StdPicture\r\n     <span style=\"color:blue;\">Dim <\/span>strIconName<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strKey<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> pic = amvGetImageFromResources(lngID)\r\n     \r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> pic Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(strAlternativeKey) = 0<span style=\"color:blue;\"> Then<\/span>\r\n             strKey = strAlternativeKey\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             strIconName = DLookup(\"Name\", \"MSysResources\", \"ID = \" & lngID)\r\n             strKey = strIconName\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n         objImageList.ListImages.Remove strKey '' falls schon vorhanden\r\n         <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n         objImageList.ListImages.Add Key:=strKey, Picture:=pic\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 15: Funktion zum Einlesen von Bildern &uuml;ber die ID aus der Tabelle MSysResources in ein ImageList-Steuerelement<\/span><\/b><\/p>\n<p>Die Funktion ermittelt mit <b>amvGetImageFromResources <\/b>das <b>StdPicture<\/b>-Objekt zu dem Bild mit der ID aus <b>lngID<\/b>. Ist dieses nicht leer, pr&uuml;ft sie, ob <b>strAlternativeKey <\/b>&uuml;bergeben wurde. Falls ja, wird dieser als <b>strKey <\/b>weiterverwendet. Anderenfalls liest die Funktion den Namen des Icons aus <b>MSysResources <\/b>ein und verwendet diesen als <b>strKey<\/b>.<\/p>\n<p>Danach entfernt die Funktion einen eventuell vorhandenen Eintrag mit dem gleichen Key aus dem <b>ImageList<\/b>-Steuerelement und f&uuml;gt das neue mit den Key aus <b>strKey <\/b>hinzu.<\/p>\n<p>Das gef&uuml;llte <b>TreeView<\/b>-Steuerelement sehen wir nun in Bild 11.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_04\/pic_1557_012.png\" alt=\"TreeView mit dynamisch eingelesenen Icons\" width=\"424,5589\" height=\"186,3648\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 11: TreeView mit dynamisch eingelesenen Icons<\/span><\/b><\/p>\n<h2>Anwenden der L&ouml;sung in eigenen Datenbanken<\/h2>\n<p>Wenn Sie die hier vorgestellten Techniken in einer eigenen Anwendung einsetzen wollen, sind die folgenden Schritte n&ouml;tig:<\/p>\n<p>Importieren Sie die folgenden Module in die Zieldatenbank:<\/p>\n<ul>\n<li><b>MDL_AMV_API<\/b><\/li>\n<li><b>MDL_AMV_Filedialog<\/b><\/li>\n<li><b>MDL_AMV_Pictures<\/b><\/li>\n<li><b>MDL_AMV_Registry<\/b><\/li>\n<\/ul>\n<p>Zus&auml;tzliche Verweise sind zur Kompilierung nicht n&ouml;tig, da wir alle betroffenen Variablen f&uuml;r Late Binding optimiert haben. <\/p>\n<p>Danach k&ouml;nnen Sie schon loslegen und die hier vorgestellten Beispiele durchspielen oder die Funktionen in eigenen Szenarios einsetzen.<\/p>\n<p>Wichtig ist, dass Sie zuvor die Tabelle <b>MSysResources <\/b>mit den notwendigen Bilddateien f&uuml;llen. Das l&auml;sst sich, wie eingangs beschrieben, mit der Funktion <b>amvFilesToResources <\/b>sehr schnell realisieren.<\/p>\n<p>Hier ist nochmal zu beachten:<\/p>\n<ul>\n<li>F&uuml;r die Verwendung als Formularicon sind ausschlie&szlig;lich <b>.ico<\/b>-Dateien zugelassen.<\/li>\n<li>F&uuml;r die &uuml;brigen Einsatzf&auml;lle verwenden wir <b>.png<\/b>-Dateien.<\/li>\n<\/ul>\n<h2>Optimale Icons f&uuml;r die Anzeige als Formular-Icon<\/h2>\n<p>Wenn wir ein Formular-Icon setzen wollen, ben&ouml;tigen wir in optimaler Aufl&ouml;sung ein Icon der Gr&ouml;&szlig;e 16&#215;16 mit 32-Bit und Alphakanal, also mit Transparenz.<\/p>\n<p>Bei den von uns verwenden Icons von <b>www.iconexperience.com <\/b>sind in einer Icon-Datei viele verschiedene Aufl&ouml;sungen, wobei automatisch die falsche Aufl&ouml;sung verwendet wird. Hier k&ouml;nnen Sie die <b>.ico<\/b>-Datei mit einem Tool wie <b>icofx <\/b>&ouml;ffnen und ein neues Icon erstellen, das nur das 16&#215;16-Icon mit 32-Bit und Alphakanal enth&auml;lt.<\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Dieser Beitrag liefert eine umfassende Behandlung aller Bereiche in Access, wo wir benutzerdefinierte Icons per VBA einf&uuml;gen k&ouml;nnen:<\/p>\n<ul>\n<li>im Ribbon,<\/li>\n<li>im Kontextmen&uuml;,<\/li>\n<li>als Formular-Icon und<\/li>\n<li>in <b>TreeView<\/b>&#8211; und <b>ListView<\/b>-Steuerelementen.<\/li>\n<\/ul>\n<p>Au&szlig;erdem finden wir hier eine Funktion, mit der wir schnell viele <b>.ico<\/b>&#8211; oder <b>.png<\/b>-Dateien in die Tabelle <b>MSysResources <\/b>laden k&ouml;nnen.<\/p>\n<h2>Downloads zu diesem Beitrag<\/h2>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>IconsInRibbonKontextmenueFormularUndTreeView.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/00D2F0A6-79BC-4720-BCD5-31629926566D\/aiu_1557.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Seit Jahren gibt es im Web einige Module, die das Handling von Bilddateien als Icons in Ribbon, Kontextmen&uuml;s, TreeViews oder als Formular-Icon erlauben. Diese sind meist umfangreich und f&uuml;r Laien kaum verst&auml;ndlich. Wir haben die verwendeten Techniken einmal ein wenig einfacher gestaltet, sodass man nicht mehr so viel Code ben&ouml;tigt &#8211; und vor allem weniger API-Funktionen. In diesem Artikel lernen Sie, wie Sie Ribbon-Eintr&auml;ge und Kontextmen&uuml;-Befehle mit Icons versehen. Als Bonus gibt eine hilfreiche Funktion, mit der wir schnell viele Icons in die Access-Datenbank &uuml;bertragen k&ouml;nnen, statt diese Schritt-f&uuml;r-Schritt einzulesen.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[662025,66042025,44000028],"tags":[],"class_list":["post-55001557","post","type-post","status-publish","format-standard","hentry","category-662025","category-66042025","category-Ergonomie_und_Benutzeroberflaeche"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.4) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Icons in Ribbon, Kontextmen&uuml;, Formular und TreeView - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Icons in Ribbon, Kontextmen&uuml;, Formular und TreeView\" \/>\n<meta property=\"og:description\" content=\"Seit Jahren gibt es im Web einige Module, die das Handling von Bilddateien als Icons in Ribbon, Kontextmen&uuml;s, TreeViews oder als Formular-Icon erlauben. Diese sind meist umfangreich und f&uuml;r Laien kaum verst&auml;ndlich. Wir haben die verwendeten Techniken einmal ein wenig einfacher gestaltet, sodass man nicht mehr so viel Code ben&ouml;tigt - und vor allem weniger API-Funktionen. In diesem Artikel lernen Sie, wie Sie Ribbon-Eintr&auml;ge und Kontextmen&uuml;-Befehle mit Icons versehen. Als Bonus gibt eine hilfreiche Funktion, mit der wir schnell viele Icons in die Access-Datenbank &uuml;bertragen k&ouml;nnen, statt diese Schritt-f&uuml;r-Schritt einzulesen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2025-08-20T15:32:41+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg01.met.vgwort.de\/na\/83d6b0ad670841858768ee632ccf2c10\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"32\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Icons in Ribbon, Kontextmen&uuml;, Formular und TreeView\",\"datePublished\":\"2025-08-20T15:32:41+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\\\/\"},\"wordCount\":5164,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg01.met.vgwort.de\\\/na\\\/83d6b0ad670841858768ee632ccf2c10\",\"articleSection\":[\"2025\",\"4\\\/2025\",\"Ergonomie und Benutzeroberfl\u00e4che\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\\\/\",\"name\":\"Icons in Ribbon, Kontextmen&uuml;, Formular und TreeView - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg01.met.vgwort.de\\\/na\\\/83d6b0ad670841858768ee632ccf2c10\",\"datePublished\":\"2025-08-20T15:32:41+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg01.met.vgwort.de\\\/na\\\/83d6b0ad670841858768ee632ccf2c10\",\"contentUrl\":\"http:\\\/\\\/vg01.met.vgwort.de\\\/na\\\/83d6b0ad670841858768ee632ccf2c10\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Icons in Ribbon, Kontextmen&uuml;, Formular und TreeView\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Icons in Ribbon, Kontextmen&uuml;, Formular und TreeView - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/","og_locale":"de_DE","og_type":"article","og_title":"Icons in Ribbon, Kontextmen&uuml;, Formular und TreeView","og_description":"Seit Jahren gibt es im Web einige Module, die das Handling von Bilddateien als Icons in Ribbon, Kontextmen&uuml;s, TreeViews oder als Formular-Icon erlauben. Diese sind meist umfangreich und f&uuml;r Laien kaum verst&auml;ndlich. Wir haben die verwendeten Techniken einmal ein wenig einfacher gestaltet, sodass man nicht mehr so viel Code ben&ouml;tigt - und vor allem weniger API-Funktionen. In diesem Artikel lernen Sie, wie Sie Ribbon-Eintr&auml;ge und Kontextmen&uuml;-Befehle mit Icons versehen. Als Bonus gibt eine hilfreiche Funktion, mit der wir schnell viele Icons in die Access-Datenbank &uuml;bertragen k&ouml;nnen, statt diese Schritt-f&uuml;r-Schritt einzulesen.","og_url":"https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/","og_site_name":"Access im Unternehmen","article_published_time":"2025-08-20T15:32:41+00:00","og_image":[{"url":"http:\/\/vg01.met.vgwort.de\/na\/83d6b0ad670841858768ee632ccf2c10","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"32\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Icons in Ribbon, Kontextmen&uuml;, Formular und TreeView","datePublished":"2025-08-20T15:32:41+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/"},"wordCount":5164,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/#primaryimage"},"thumbnailUrl":"http:\/\/vg01.met.vgwort.de\/na\/83d6b0ad670841858768ee632ccf2c10","articleSection":["2025","4\/2025","Ergonomie und Benutzeroberfl\u00e4che"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/","url":"https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/","name":"Icons in Ribbon, Kontextmen&uuml;, Formular und TreeView - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/#primaryimage"},"thumbnailUrl":"http:\/\/vg01.met.vgwort.de\/na\/83d6b0ad670841858768ee632ccf2c10","datePublished":"2025-08-20T15:32:41+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/#primaryimage","url":"http:\/\/vg01.met.vgwort.de\/na\/83d6b0ad670841858768ee632ccf2c10","contentUrl":"http:\/\/vg01.met.vgwort.de\/na\/83d6b0ad670841858768ee632ccf2c10"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Icons_in_Ribbon_Kontextmenue_Formular_und_TreeView\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Icons in Ribbon, Kontextmen&uuml;, Formular und TreeView"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001557","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55001557"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001557\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001557"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001557"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001557"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}