{"id":55001386,"date":"2022-10-01T00:00:00","date_gmt":"2022-10-03T14:37:08","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1386"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Objektpositionen_speichern_und_wiederherstellen","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Objektpositionen_speichern_und_wiederherstellen\/","title":{"rendered":"Objektpositionen speichern und wiederherstellen"},"content":{"rendered":"<p><b>Neulich fragte ein Leser, ob und wie man die Position von Objekten im Access-Fenster speichern und wiederherstellen k&ouml;nne. Der Hintergrund ist, dass er immer wieder m&uuml;hsam Tabellen, Abfragen und andere Objekte zu einem Arbeitsbereich zusammengestellt hat und wenn er die Anwendung schlie&szlig;t, ist die ganze Arbeit dahin &#8211; und am n&auml;chsten Tag muss er die Objekte erneut anordnen. Ich f&uuml;hlte mich ein wenig an Zeiten erinnert, wo man zwar einen Homecomputer zum Programmieren, aber kein Ger&auml;t zum Speichern der eingetippten Spiele aus den Computermagazinen hatte &#8230; Da sich die Zeiten zum Gl&uuml;ck ge&auml;ndert haben, zeige ich in diesem Beitrag, wie Sie die Position und Gr&ouml;&szlig;e der beim Schlie&szlig;en einer Datenbank ge&ouml;ffneten Objekte abspeichern und beim n&auml;chsten &Ouml;ffnen wieder herstellen k&ouml;nnen.<\/b><\/p>\n<h2>Aufgabenstellung<\/h2>\n<p>Aus den Anforderungen des Lesers ergeben sich die folgenden Aufgabenstellungen:<\/p>\n<ul>\n<li>Herausfinden, wie wir die Position und Gr&ouml;&szlig;e aller zu einem bestimmten Zeitpunkt ge&ouml;ffneten Objekte ermitteln k&ouml;nnen<\/li>\n<li>Definieren einer Tabelle zum Speichern der ge&ouml;ffneten Objekte mit Name und Objekttyp und ihrer Position und Gr&ouml;&szlig;e sowie der aktuellen Ansicht<\/li>\n<li>Prozedur zum Speichern dieser Informationen in einer geeigneten Tabelle in der jeweilige Datenbankanwendung<\/li>\n<li>Herausfinden, wie wir die abgespeicherten Objekte wieder &ouml;ffnen und die Position und die Gr&ouml;&szlig;e zu einem bestimmten Zeitpunkt wiederherstellen k&ouml;nnen<\/li>\n<li>Festlegen eines Automatismus, die Position und Gr&ouml;&szlig;e der Objekte beim Schlie&szlig;en der Datenbank zu speichern.<\/li>\n<li>Festlegen eines weiteren Automatismus, um die Position und Gr&ouml;&szlig;e bei &Ouml;ffnen der Datenbankanwendung wiederherzustellen<\/li>\n<\/ul>\n<h2>Gr&ouml;&szlig;e und Position der ge&ouml;ffneten Objekte ermitteln<\/h2>\n<p>Die erste Aufgabe ist bereits die anspruchsvollste: Wie k&ouml;nnen wir alle ge&ouml;ffneten Objekte ermitteln und wie finden wir die aktuelle Position und Gr&ouml;&szlig;e dieser Objekte heraus?<\/p>\n<p>F&uuml;r diese Aufgabe gibt es keine L&ouml;sung, mit der wir alle Objekte gleicherma&szlig;en behandeln k&ouml;nnen. So gibt es zwar Auflistungen namens <b>Forms <\/b>und <b>Reports<\/b>, mit denen direkt auf die aktuell ge&ouml;ffneten Formulare und Berichte zugegriffen werden kann.<\/p>\n<p>Entsprechende Auflistungen f&uuml;r Tabellen und Abfragen beispielsweise namens <b>Tables <\/b>oder <b>Queries <\/b>suchen wir jedoch vergeblich.<\/p>\n<p>Wenn wir jedoch nach diesen Schl&uuml;sselw&ouml;rtern im Objektkatalog des VBA-Editors suchen, finden wir schnell passende Eintr&auml;ge, n&auml;mlich <b>AllTables <\/b>und <b>AllQueries <\/b>(siehe Bild 1).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1386_001.png\" alt=\"Finden von geeigneten Auflistungen f&uuml;r den Zugriff auf Tabellen und Abfragen\" width=\"549,559\" height=\"448,4247\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Finden von geeigneten Auflistungen f&uuml;r den Zugriff auf Tabellen und Abfragen<\/span><\/b><\/p>\n<p>Damit haben wir zumindest schon einmal Auflistungen f&uuml;r alle Objekttypen gefunden &#8211; nun schauen wir uns an, wie wir an die jeweils gew&uuml;nschten Informationen wie Name, aktuelle Ansicht, Position vom linken und oberen Rand, H&ouml;he und Breite gelangen.<\/p>\n<h2>Formulare und Berichte analysieren<\/h2>\n<p>Bei Formularen und Berichten macht Access es uns ein wenig leichter als bei Tabellen und Abfragen, die wir uns im Anschluss anschauen. Mit der <b>Forms<\/b>&#8211; und der <b>Reports<\/b>-Auflistung k&ouml;nnen wir direkt die aktuell ge&ouml;ffneten Objekte referenzieren. Mit der folgenden Prozedur durchlaufen wir beispielsweise alle Formulare, die aktuell ge&ouml;ffnet sind:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>Formulare()\r\n     <span style=\"color:blue;\">Dim <\/span>frm<span style=\"color:blue;\"> As <\/span>Form\r\n     For Each frm In Forms\r\n         <span style=\"color:blue;\">Debug.Print<\/span> frm.Name,  frm.WindowLeft, frm.WindowTop,  frm.WindowWidth, frm.WindowHeight\r\n     <span style=\"color:blue;\">Next<\/span> frm\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die Werte der Eigenschaften <b>WindowLeft<\/b>, <b>WindowTop<\/b>, <b>WindowWidth <\/b>und <b>WindowHeight <\/b>liefert Access in der Einheit <b>Twips<\/b>. Vorneweg: Diese Eigenschaften sind schreibgesch&uuml;tzt und wir k&ouml;nnen diese sp&auml;ter nicht nutzen, um die Gr&ouml;&szlig;e und die Position der Formulare und Berichte wiederherzustellen. Allerdings arbeitet auch die Methode, die wir dazu sp&auml;ter nutzen werden, mit Angaben in dieser Einheit. Daher verzichten wir an dieser Stelle auf eine Beschreibung, was Twips genau sind.<\/p>\n<p>Den Namen des jeweiligen Formulars oder Berichts lesen wir einfach aus der Eigenschaft <b>Name <\/b>aus. Spannend ist nun noch, die aktuelle Ansicht zu ermitteln.<\/p>\n<p>Formulare k&ouml;nnen in den Ansichten <b>Einzelnes Formular<\/b>, <b>Endlosformular<\/b>, <b>Datenblatt <\/b>oder <b>Geteiltes Formular <\/b>angezeigt werden (siehe Bild 2). Bei Berichten kommen noch die Ansichten <b>Berichtssicht <\/b>und <b>Seitenansicht <\/b>hinzu.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1386_002.png\" alt=\"M&ouml;gliche Ansichten f&uuml;r ein Formular\" width=\"599,559\" height=\"282,0906\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: M&ouml;gliche Ansichten f&uuml;r ein Formular<\/span><\/b><\/p>\n<p>Diese Eigenschaft k&ouml;nnen wir per VBA einerseits &uuml;ber <b>CurrentView <\/b>ermitteln. <b>CurrentView <\/b>liefert die folgenden Werte:<\/p>\n<ul>\n<li><b>0<\/b> (<b>acCurViewDesign<\/b>): Entwurfsansicht<\/li>\n<li><b>1<\/b> (<b>acCurViewFormBrowse<\/b>): Formularansicht<\/li>\n<li><b>2<\/b> (<b>acCurViewDatasheet<\/b>): Datenblattansicht<\/li>\n<li><b>5<\/b> (<b>acCurViewPreview<\/b>): Seitenansicht (bei Berichten)<\/li>\n<li><b>6 <\/b>(<b>acCurViewReportBrowse<\/b>): Berichtssicht (bei Berichten)<\/li>\n<li><b>7<\/b> (<b>acCurViewLayout<\/b>): Layoutansicht<\/li>\n<\/ul>\n<p>Aber Moment &#8211; das sind ja gar nicht die Werte, die wir f&uuml;r die Eigenschaft <b>Standardansicht <\/b>aus dem Eigenschaftenblatt ausw&auml;hlen k&ouml;nnen. Diese k&ouml;nnen wir der VBA-Eigenschaft <b>DefaultView <\/b>eines <b>Form<\/b>-Objekts entnehmen und die Werte stimmen nicht mit den Zahlenwerten f&uuml;r die Eigenschaft <b>CurrentView <\/b>&uuml;berein.<\/p>\n<p>Im Gegenteil &#8211; es gibt sogar f&uuml;r Formulare und Berichte teilweise gleiche Werte mit unterschiedlicher Bedeutung:<\/p>\n<ul>\n<li><b>0<\/b>: Einzelnes Formular<\/li>\n<li><b>1<\/b>: Endlosformular<\/li>\n<li><b>2<\/b>: Datenblatt<\/li>\n<li><b>3<\/b>: PivotTable<\/li>\n<li><b>4<\/b>: PivotChart<\/li>\n<li><b>5<\/b>: Geteiltes Formular<\/li>\n<\/ul>\n<p>F&uuml;r Berichte gibt es die folgenden beiden Werte:<\/p>\n<ul>\n<li><b>0<\/b>: Seitenansicht<\/li>\n<li><b>1<\/b>: Berichtsansicht<\/li>\n<\/ul>\n<p>Wie aber kommen wir an die aktuelle Ansicht? Immerhin kann der Benutzer diese ja, wenn die m&ouml;glichen Ansichten nicht auf eine Ansicht eingeschr&auml;nkt ist, wechseln. Daher verwenden wir die Eigenschaft <b>CurrentView<\/b>, um die aktuelle Ansicht zu ermitteln.<\/p>\n<h2>Tabellen und Abfragen analysieren<\/h2>\n<p>Etwas komplizierter wird die Analyse bei Tabellen und Abfragen. Wie bereits erw&auml;hnt, gibt es keine Auflistung, die alle derzeit ge&ouml;ffneten Tabellen oder Abfragen auflistet.<\/p>\n<p>Also schauen wir, was wir mit den beiden Auflistungen <b>AllTables <\/b>und <b>AllQueries<\/b>, die wir weiter oben im Objektkatalog gefunden haben, f&uuml;r unsere Zwecke nutzen k&ouml;nnen.<\/p>\n<p>Um diese Auflistungen zu durchlaufen, wollen wir zun&auml;chst herausfinden, welchen Datentyp die damit referenzierten Elemente &uuml;berhaupt aufweisen. Dazu greifen wir einfach auf das erste Element einer solchen Auflistung zu und lassen uns den Objekttyp mit der Funktion <b>Typename <\/b>im Direktbereich ausgeben:<\/p>\n<pre>  Typename(CurrentData.AllTables(0))\r\nAccessObject<\/pre>\n<p>Jetzt, da wir den Objekttypen kennen, k&ouml;nnen wir die Elemente direkt in einer <b>For Each<\/b>-Schleife durchlaufen und auch per IntelliSense auf die Eigenschaften der Elemente zugreifen (siehe Bild 3).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1386_003.png\" alt=\"Erkunden der Eigenschaften von AccessObject-Elementen\" width=\"424,5589\" height=\"272,4396\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Erkunden der Eigenschaften von AccessObject-Elementen<\/span><\/b><\/p>\n<p>Um herauszufinden, welche Objekte ge&ouml;ffnet sind und in welcher Ansicht sie dann angezeigt werden, verwenden wir die folgende Prozedur:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>GeoeffneteTabellenDurchlaufen()\r\n     <span style=\"color:blue;\">Dim <\/span>objTable<span style=\"color:blue;\"> As <\/span>AccessObject\r\n     For Each objTable In CurrentData.AllTables\r\n         <span style=\"color:blue;\">Debug.Print<\/span> objTable.Name;\r\n         <span style=\"color:blue;\">If <\/span>objTable.IsLoaded<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">Debug.Print<\/span> objTable.CurrentView\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             <span style=\"color:blue;\">Debug.Print<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> objTable\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Damit erhalten wir beispielsweise folgendes Ergebnis, wenn die beiden Tabellen <b>tblObjecttypes <\/b>und <b>tblTest <\/b>in der Datenblattansicht und die Tabelle <b>tblObjects <\/b>in der Entwurfsansicht ge&ouml;ffnet sind:<\/p>\n<pre>MSysAccessStorage\r\nMSysACEs\r\n... weitere nicht ge&ouml;ffnete Systemtabellen\r\nMSysRelationships\r\nMSysResources\r\ntblObjects 0 \r\ntblObjecttypes 2 \r\ntblTest 2 <\/pre>\n<p>Interessant sind f&uuml;r Tabellen die folgenden Ansichten:<\/p>\n<ul>\n<li><b>0<\/b>: Entwurfsansicht <\/li>\n<li><b>2<\/b>: Datenblattansicht<\/li>\n<\/ul>\n<p>Abfragen durchlaufen wir auf &auml;hnliche Weise &#8211; wir verwenden hier lediglich die Auflistung <b>AllQueries<\/b>:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>GeoeffneteAbfragenDurchlaufen()\r\n     <span style=\"color:blue;\">Dim <\/span>objQuery<span style=\"color:blue;\"> As <\/span>AccessObject\r\n     For Each objQuery In CurrentData.AllQueries\r\n         <span style=\"color:blue;\">Debug.Print<\/span> objQuery.Name;\r\n         <span style=\"color:blue;\">If <\/span>objQuery.IsLoaded<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">Debug.Print<\/span> objQuery.CurrentView\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             <span style=\"color:blue;\">Debug.Print<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> objQuery\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Interessant ist hier, dass es eigentlich noch eine weitere Ansicht gibt, n&auml;mlich die SQL-Ansicht (siehe Bild 4). Wenn wir eine Abfrage in dieser Ansicht &ouml;ffnen und die Prozedur <b>GeoeffneteAbfrageDurchlaufen <\/b>starten, gibt diese ebenfalls den Wert <b>0 <\/b>f&uuml;r die Eigenschaft <b>CurrentView <\/b>zur&uuml;ck.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1386_004.png\" alt=\"Die SQL-Ansicht einer Abfrage\" width=\"424,5589\" height=\"299,6886\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Die SQL-Ansicht einer Abfrage<\/span><\/b><\/p>\n<p>Davon ausgehend, dass der Benutzer nicht den Zustand von in der SQL-Ansicht ge&ouml;ffneten Abfragen speichern m&ouml;chte, stellt das aber auch im Rahmen dieses Beitrags kein Problem dar.<\/p>\n<h2>Position und Gr&ouml;&szlig;e von Tabellen und Abfragen ermitteln<\/h2>\n<p>Nachdem wir die Gr&ouml;&szlig;e und Position von Formularen und Berichten direkt &uuml;ber die Eigenschaften der <b>Form<\/b>&#8211; beziehungsweise <b>Report<\/b>-Objekte ermitteln k&ouml;nnen, schauen wir uns nun die Tabellen und Abfragen an. Da das <b>AccessObject<\/b>-Element keine diesbez&uuml;glichen Eigenschaften offeriert, m&uuml;ssen wir einen kleinen Umweg gehen, um die Informationen zu beschaffen.<\/p>\n<p>Ausgehend davon, dass wir ohnehin nur ge&ouml;ffnete Elemente verwenden wollen, k&ouml;nnen wir dann das <b>Screen<\/b>-Objekt nutzen, welches uns Informationen &uuml;ber die jeweils aktiven Objekte liefert, also die Objekte, die aktuell den Fokus besitzen. Mit dem <b>Screen<\/b>-Objekt k&ouml;nnen wir &uuml;ber die folgenden Eigenschaften auf die jeweiligen Objekte zugreifen:<\/p>\n<ul>\n<li><b>Screen.ActiveDatasheet<\/b>: Aktive Tabellen und Abfragen in der Datenblattansicht<\/li>\n<li><b>Screen.ActiveForm<\/b>: Aktives Formular<\/li>\n<li><b>Screen.ActiveReport<\/b>: Aktiver Bericht<\/li>\n<\/ul>\n<p>Hier sehen wir also eine weitere Einschr&auml;nkung bez&uuml;glich der Ansichten, die wir beim Speichern von Position und Gr&ouml;&szlig;e ber&uuml;cksichtigen k&ouml;nnen: Die Entwurfsansicht von Tabellen oder Abfragen f&auml;llt weg, da wir diese nicht mit den <b>Active&#8230;<\/b>-Eigenschaften referenzieren k&ouml;nnen.<\/p>\n<p>Die Eigenschaft <b>ActiveDatasheet<\/b> liefert tats&auml;chlich nur einen Objektverweis zur&uuml;ck, wenn aktuell eine Tabelle oder Abfrage in der Datenblattansicht ge&ouml;ffnet ist. Aber auch das ist kein Problem, zumindest nicht gemessen an dem Wunsch des Lesers, die Position und Gr&ouml;&szlig;e von in der Datenblattansicht ge&ouml;ffneten Elementen zu ermitteln und zu speichern.<\/p>\n<p>Allerdings hilft uns <b>Screen.ActiveDatasheet <\/b>noch nicht weiter, wenn das Objekt, das wir untersuchen wollen, nicht den Fokus hat. Deshalb m&uuml;ssen wir, bevor wir auf eine ge&ouml;ffnete Tabelle in der Datenblattansicht zugreifen wollen, zun&auml;chst den Fokus auf diese Tabelle verschieben. Dass sie &uuml;berhaupt ge&ouml;ffnet ist, k&ouml;nnen wir voraussetzen, denn wir wollen ja nur die Position und Gr&ouml;&szlig;e von Tabellen ermitteln, die derzeit im Arbeitsbereich sichtbar sind.<\/p>\n<p><!--30percent--><\/p>\n<p>Den Namen der zu untersuchenden Tabelle kennen wir &uuml;ber die <b>Name<\/b>-Eigenschaft auch. Also k&ouml;nnen wir die <b>DoCmd.SelectObject<\/b>-Methode nutzen, um die zu untersuchende Tabelle oder Abfrage in den Fokus zu setzen &#8211; beispielsweise so:<\/p>\n<pre>DoCmd.SelectObject acTable, objTable.Name<\/pre>\n<h2>Tabelle zum Speichern der Objekteigenschaften<\/h2>\n<p>Als N&auml;chstes erstellen wir die Tabelle, in der wir die Gr&ouml;&szlig;e, Position und Ansicht der aktuell ge&ouml;ffneten Objekte speichern wollen.<\/p>\n<p>Welche Informationen wir speichern wollen, haben wir bereits ausf&uuml;hrlich besprochen, daher hier nur der Verweis auf den Entwurf der Tabelle <b>tblObjects <\/b>in Bild 5.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1386_005.png\" alt=\"Tabelle zum Speichern der Objekteigenschaften\" width=\"574,559\" height=\"438,3328\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Tabelle zum Speichern der Objekteigenschaften<\/span><\/b><\/p>\n<p>Au&szlig;erdem noch die Information, dass wir den Typ des jeweiligen Objekts im Feld <b>Objecttype <\/b>als Zahlenwert speichern und dabei auf die folgenden Werte zur&uuml;ckgreifen:<\/p>\n<ul>\n<li><b>0<\/b>: <b>acTable <\/b>(Tabelle)<\/li>\n<li><b>1<\/b>: <b>acQuery <\/b>(Abfrage)<\/li>\n<li><b>2<\/b>: <b>acForm <\/b>(Formular)<\/li>\n<li><b>3<\/b>: <b>acReport <\/b>(Bericht)<\/li>\n<\/ul>\n<p>Den Wert f&uuml;r das Feld <b>ObjectView <\/b>w&auml;hlen wir wie von der Eigenschaft <b>CurrentView <\/b>geliefert.<\/p>\n<p>In der Prozedur <b>SaveObjectInfo <\/b>aus Listing 1 leeren wir zun&auml;chst die Tabelle <b>tblObjects<\/b>. Dann durchlaufen wir alle Elemente der Auflistung <b>AllTables <\/b>und pr&uuml;fen in der enthaltenen <b>If&#8230;Then<\/b>-Bedingung mit der Eigenschaft <b>IsLoaded<\/b>, ob das jeweilige Element ge&ouml;ffnet ist. Falls ja, ermitteln wir den Namen und selektieren das Objekt mit <b>DoCmd.SelectObject<\/b>.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>SaveObjectInfo()\r\n     <span style=\"color:blue;\">Dim <\/span>obj<span style=\"color:blue;\"> As <\/span>AccessObject\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>frm<span style=\"color:blue;\"> As <\/span>Form\r\n     <span style=\"color:blue;\">Dim <\/span>rpt<span style=\"color:blue;\"> As <\/span>Report\r\n     <span style=\"color:blue;\">Dim <\/span>strName<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>intTop<span style=\"color:blue;\"> As Integer<\/span>, intWidth<span style=\"color:blue;\"> As Integer<\/span>, intHeight<span style=\"color:blue;\"> As Integer<\/span>, intLeft<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>intType<span style=\"color:blue;\"> As <\/span>AcObjectType\r\n     <span style=\"color:blue;\">Dim <\/span>intView<span style=\"color:blue;\"> As <\/span>AcView\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     db.Execute \"DELETE FROM tblObjects\", dbFailOnError\r\n     For Each obj In CurrentData.AllTables\r\n         <span style=\"color:blue;\">If <\/span>obj.IsLoaded<span style=\"color:blue;\"> Then<\/span>\r\n             strName = obj.Name\r\n             DoCmd.SelectObject acTable, strName\r\n             intType = acTable\r\n             intView = Screen.ActiveDatasheet.CurrentView\r\n             intTop = Screen.ActiveDatasheet.WindowTop\r\n             int<span style=\"color:blue;\">Left<\/span> = Screen.ActiveDatasheet.WindowLeft\r\n             intWidth = Screen.ActiveDatasheet.WindowWidth\r\n             intHeight = Screen.ActiveDatasheet.WindowHeight\r\n             db.Execute \"INSERT INTO tblObjects(Objectname, Objecttype, ObjectTop, ObjectLeft, ObjectWidth, \" _\r\n                 & \"ObjectHeight, ObjectView) VALUES(''\" & strName & \"'', \" & intType & \", \" & intTop & \", \" & int<span style=\"color:blue;\">Left<\/span> _\r\n                 & \", \" & intWidth & \", \" & intHeight & \", \" & intView & \")\", dbFailOnError\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> obj\r\n     ''... Abfragen analog zu Tabellen\r\n     For Each frm In Forms\r\n         strName = frm.Name\r\n         intType = acForm\r\n         intView = frm.CurrentView\r\n         intTop = frm.WindowTop\r\n         int<span style=\"color:blue;\">Left<\/span> = frm.WindowLeft\r\n         intWidth = frm.WindowWidth\r\n         intHeight = frm.WindowHeight\r\n         db.Execute \"INSERT INTO tblObjects(Objectname, Objecttype, ObjectTop, ObjectLeft, ObjectWidth, \" _\r\n             & \"ObjectHeight, ObjectView) VALUES(''\" & strName & \"'', \" & intType & \", \" & intTop & \", \" & int<span style=\"color:blue;\">Left<\/span> _\r\n             & \", \" & intWidth & \", \" & intHeight & \", \" & intView & \")\", dbFailOnError\r\n     <span style=\"color:blue;\">Next<\/span> frm\r\n     ''...Berichte analog zu Formularen\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Prozedur zum Speichern der Informationen zu den ge&ouml;ffneten Objekten<\/span><\/b><\/p>\n<p>Damit hat es anschlie&szlig;end den Fokus, auch wenn dies zuvor nicht der Fall war. Danach ermitteln wir die weiteren gesuchten Informationen und tragen diese in die Variablen ein. Diese nutzen wir in der anschlie&szlig;end ausgef&uuml;hrten <b>INSERT INTO<\/b>-Aktionsabfrage, um einen neuen Datensatz mit allen ben&ouml;tigten Informationen in der Tabelle <b>tblObjects <\/b>zu speichern.<\/p>\n<p>Auf &auml;hnliche Weise gehen wir anschlie&szlig;end bei den Abfragen vor &#8211; hier verwenden wir allerdings die Auflistung <b>AllQueries <\/b>und setzen einen anderen Wert f&uuml;r <b>intType<\/b>.<\/p>\n<p>Schlie&szlig;lich folgen die beiden <b>For Each<\/b>-Schleifen &uuml;ber die Auflistungen <b>Forms <\/b>und <b>Reports<\/b>, in denen wir die Daten zu den Formularen und Berichten ermitteln und diese in die Tabelle <b>tblObjects <\/b>eintragen.<\/p>\n<p>Das Ergebnis sieht f&uuml;r ein paar Beispielelemente wie in Bild 6 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1386_006.png\" alt=\"Eigenschaften einiger Beispielelemente in der Tabelle tblObjects\" width=\"700\" height=\"192,0577\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Eigenschaften einiger Beispielelemente in der Tabelle tblObjects<\/span><\/b><\/p>\n<h2>Wiederherstellen der Objekte<\/h2>\n<p>Bevor wir uns um die Prozedur k&uuml;mmern, mit der wir die Objekte aus der Tabelle <b>tblObjects <\/b>&ouml;ffnen und ihre Positionen wiederherstellen, wollen wir uns die Arbeit beim Testen der Prozedur etwas vereinfachen &#8211; statt die aktuell ge&ouml;ffneten Objekte immer wieder von Hand schlie&szlig;en zu m&uuml;ssen, durchlaufen wir diese einfach innerhalb der Auflistungen, die wir bereits kennengelernt haben, und schlie&szlig;en diese dort automatisch:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>CloseAllObjects()\r\n     <span style=\"color:blue;\">Dim <\/span>obj<span style=\"color:blue;\"> As <\/span>AccessObject\r\n     <span style=\"color:blue;\">Dim <\/span>frm<span style=\"color:blue;\"> As <\/span>Form\r\n     <span style=\"color:blue;\">Dim <\/span>rpt<span style=\"color:blue;\"> As <\/span>Report\r\n     For Each obj In CurrentData.AllTables\r\n         <span style=\"color:blue;\">If <\/span>obj.IsLoaded<span style=\"color:blue;\"> Then<\/span>\r\n             DoCmd.Close acTable, obj.Name\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> obj\r\n     For Each obj In CurrentData.AllQueries\r\n         <span style=\"color:blue;\">If <\/span>obj.IsLoaded<span style=\"color:blue;\"> Then<\/span>\r\n             DoCmd.Close acQuery, obj.Name\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> obj\r\n     For Each frm In Forms\r\n         DoCmd.Close acForm, frm.Name\r\n     <span style=\"color:blue;\">Next<\/span> frm\r\n     For Each rpt In Reports\r\n         DoCmd.Close acReport, rpt.Name\r\n     <span style=\"color:blue;\">Next<\/span> rpt\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Danach programmieren wir die Prozedur, welche die Elemente aus der Tabelle <b>tblObjects <\/b>&ouml;ffnet und ihre Gr&ouml;&szlig;e und Position wiederherstellt. Bei Gr&ouml;&szlig;e und Position k&ouml;nnen wir einfach die gespeicherten Werte &uuml;bernehmen und in die entsprechenden Eigenschaften schreiben. Bei der Ansicht wird es etwas komplizierter. Der Grund ist: Wir haben zwar den Wert der Eigenschaft von <b>CurrentView <\/b>gespeichert (siehe weiter oben), aber wir k&ouml;nnen nur die Werte f&uuml;r die Eigenschaft <b>DefaultView <\/b>beim erneuten &Ouml;ffnen der Elemente nutzen.<\/p>\n<p>Die <b>Form<\/b>&#8211; und <b>Report<\/b>-Klassen bieten zwar die <b>CurrentView<\/b>-Eigenschaft in VBA an, aber dabei handelt es sich um schreibgesch&uuml;tzte Eigenschaften. Wir k&ouml;nnen die zu verwendende Ansicht nur beim &Ouml;ffnen des jeweiligen Objekts einstellen, also in der <b>DoCmd.Open&#8230;<\/b>-Methode, die je nach zu &ouml;ffnendem Objekt <b>OpenTable<\/b>, <b>OpenQuery <\/b>und so weiter hei&szlig;t. Wir m&uuml;ssen daher die im Feld <b>ObjectView <\/b>gespeicherten Werte noch umwandeln.<\/p>\n<p>Dabei k&ouml;nnen wir hier und da Vereinfachungen treffen. Wir gehen zum Beispiel davon aus, dass der Benutzer Tabellen und Abfragen nur in der Datenblattansicht &ouml;ffnen m&ouml;chte und nicht mehrere Tabellen in der Entwurfsansicht nebeneinander platziert. <\/p>\n<p>Bei Formularen unterscheiden wir die Ansichten <b>Formularansicht<\/b>, <b>Endlosansicht <\/b>und <b>Datenblattansicht<\/b>. In der Liste der Werte f&uuml;r den zweiten Parameter der Methode <b>DoCmd.OpenForm <\/b>finden wir allerdings nur die folgenden Werte:<\/p>\n<ul>\n<li><b>0 <\/b>(<b>acNormal<\/b>): Zeigt das Formular in der als Standardansicht gew&auml;hlten Ansicht an.<\/li>\n<li><b>1 <\/b>(<b>acDesign<\/b>): Entwurfsansicht<\/li>\n<li><b>2 <\/b>(<b>acPreview<\/b>): Druckvorschau<\/li>\n<li><b>3 <\/b>(<b>acFormDS<\/b>): Datenblattansicht<\/li>\n<li><b>6 <\/b>(<b>acLayout<\/b>): Layoutansicht<\/li>\n<\/ul>\n<p>Interessant ist die Anzeige in der Formularansicht, in der Endlosansicht und in der Datenblattansicht. Ob das Formular in der Formularansicht oder in der Endlosansicht ge&ouml;ffnet wird, k&ouml;nnen wir nicht steuern &#8211; wir geben den Parameter <b>acNormal <\/b>an und Access &ouml;ffnet das Formular in der Ansicht, die als Standardansicht eingestellt ist. Wenn wir f&uuml;r das Feld <b>ObjectView <\/b>also den Wert <b>1 <\/b>gespeichert haben, m&uuml;ssen wir als zweiten Parameter in <b>DoCmd.OpenForm <\/b>den Wert <b>0<\/b> nutzen. <\/p>\n<p>Wenn das Formular beim Speichern in der Datenblattansicht angezeigt wurde, enth&auml;lt das Feld <b>ObjectView <\/b>den Wert <b>2<\/b>. In diesem Fall verwenden wir den Wert <b>3 <\/b>(<b>acFormDS<\/b>) f&uuml;r den zweiten Parameter der <b>OpenForm<\/b>-Methode.<\/p>\n<p>Bei den Berichten sieht es etwas anders aus. Hier speichern wir im Feld <b>ObjectView<\/b> entweder den Wert <b>5 <\/b>f&uuml;r <b>acCurViewPreview <\/b>beziehungsweise Seitenansicht oder <b>6 <\/b>f&uuml;r <b>acCurViewReportBrowse<\/b> beziehungsweise Berichtsansicht. Beim &Ouml;ffnen mit <b>DoCmd.OpenReport <\/b>m&uuml;ssen wir allerdings die Werte <b>acViewPreview <\/b>nutzen beziehungsweise <b>acViewReport<\/b>.<\/p>\n<p>Die Prozedur sieht insgesamt wie in Listing 2 aus. Wir deklarieren f&uuml;r die &Uuml;bersetzung der Ansicht f&uuml;r Formulare und Berichte die beiden Variablen <b>intFormView <\/b>mit dem Typ <b>AcFormView <\/b>und <b>intReportView <\/b>mit dem Typ <b>AcView<\/b>. Die hinter <b>AcFormView <\/b>und <b>acView <\/b>liegenden Enumerationen entsprechen den Parametern der Methoden <b>DoCmd.OpenForm <\/b>beziehungsweise <b>DoCmd.OpenReport<\/b>.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>OpenObjects()\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>intFormView<span style=\"color:blue;\"> As <\/span>AcFormView\r\n     <span style=\"color:blue;\">Dim <\/span>intReportView<span style=\"color:blue;\"> As <\/span>AcView\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT * FROM tblObjects\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n         Select Case rst!Objecttype\r\n             <span style=\"color:blue;\">Case <\/span>acTable\r\n                 DoCmd.OpenTable rst!Objectname, acViewNormal\r\n             <span style=\"color:blue;\">Case <\/span>acQuery\r\n                 DoCmd.OpenQuery rst!Objectname, acViewNormal\r\n             <span style=\"color:blue;\">Case <\/span>acForm\r\n                 Select Case rst!ObjectView\r\n                     <span style=\"color:blue;\">Case <\/span>1\r\n                         intFormView = acNormal\r\n                     <span style=\"color:blue;\">Case <\/span>2\r\n                         intFormView = acFormDS\r\n                 <span style=\"color:blue;\">End Select<\/span>\r\n                 DoCmd.OpenForm rst!Objectname, intFormView\r\n             <span style=\"color:blue;\">Case <\/span>acReport\r\n                 Select Case rst!ObjectView\r\n                     <span style=\"color:blue;\">Case <\/span>5\r\n                         intReportView = acViewPreview\r\n                     <span style=\"color:blue;\">Case <\/span>6\r\n                         intReportView = acViewReport\r\n                 <span style=\"color:blue;\">End Select<\/span>\r\n                 DoCmd.OpenReport rst!Objectname, intReportView\r\n         <span style=\"color:blue;\">End Select<\/span>\r\n         DoCmd.MoveSize rst!ObjectLeft, rst!ObjectTop, rst!ObjectWidth, rst!ObjectHeight\r\n         rst.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Prozedur zum Wiederherstellen der Objekte<\/span><\/b><\/p>\n<p>Dann erstellen wir ein Recordset auf Basis der Tabelle <b>tblObjects<\/b>, welche die Gr&ouml;&szlig;e, Position und die Ansicht aller zuletzt ge&ouml;ffneten Objekte enth&auml;lt. Diese durchlaufen wir in einer <b>Do While<\/b>-Schleife und pr&uuml;fen zun&auml;chst, um welchen Objekttyp es sich handelt. Diesen ermitteln wir aus dem Feld <b>Objecttype<\/b>. Je nach Wert, also <b>acTable<\/b>, <b>acQuery<\/b>, <b>acForm <\/b>oder <b>acReport<\/b>, steuert die Prozedur einen der <b>Case<\/b>-Zweige in einer <b>Select Case<\/b>-Bedingung an. F&uuml;r Tabellen (<b>acTable<\/b>) ruft die Prozedur die Methode <b>DoCmd.OpenTable <\/b>auf und &uuml;bergibt den Namen des Objekts aus dem Feld <b>ObjectName <\/b>als ersten Parameter und f&uuml;r die Ansicht den Wert <b>acViewNormal<\/b>.<\/p>\n<p>Bei Abfragen (<b>acQuery<\/b>) sieht der Ablauf identisch aus, nur dass hier die Methode <b>DoCmd.OpenQuery <\/b>verwendet wird. Dann kommen wir zu den Formularen (<b>acForm<\/b>). Hier pr&uuml;fen wir den Wert des Feldes <b>ObjectView<\/b>. Lautet dieser <b>1<\/b>, stellen wir die Variable <b>intFormView <\/b>auf <b>acNormal <\/b>ein, f&uuml;r den Wert <b>2 <\/b>nutzen wir <b>acFormDS<\/b>. <b>intFormView <\/b>verwenden wir beim &Ouml;ffnen des Formulars mit <b>DoCmd.OpenForm <\/b>als zweiten Parameter.<\/p>\n<p>Bei Berichten (<b>acReport<\/b>) erhalten wir entweder den Wert <b>5 <\/b>(hier stellen wir <b>intReportView <\/b>auf <b>acViewPreview <\/b>ein) oder <b>6 <\/b>(dann erh&auml;lt <b>intReportView <\/b>den Wert <b>acViewReport<\/b>). Den Bericht &ouml;ffnen wir dann schlie&szlig;lich mit der <b>DoCmd.OpenReport<\/b>-Methode.<\/p>\n<p>Anschlie&szlig;end folgen noch die Gr&ouml;&szlig;e und die Position. Hier nutzen wir die Methode <b>DoCmd.MoveSize<\/b>. Mit den ersten beiden Parametern der Methode stellen wir die Position ein, die wir aus den beiden Feldern <b>ObjectLeft <\/b>und <b>ObjectTop <\/b>erhalten. Au&szlig;erdem legen wir mit dem dritten und vierten Parameter die Breite und die H&ouml;he des Formulars fest, die wir aus den Feldern <b>ObjectWidth <\/b>und <b>ObjectHeight <\/b>beziehen.<\/p>\n<p>Auf diese Weise durchlaufen wir alle Objekte und &ouml;ffnen diese in der gew&uuml;nschten Gr&ouml;&szlig;e, Position und Ansicht.<\/p>\n<h2>Speichern der Position beim Schlie&szlig;en der Datenbank<\/h2>\n<p>Nun ben&ouml;tigen wir einen kleinen Trick, damit die aktuelle Konfiguration der Objekte beim Schlie&szlig;en der Datenbank automatisch gespeichert wird &#8211; und zwar am besten nach vorheriger R&uuml;ckfrage.<\/p>\n<p>Dazu &ouml;ffnen wir direkt beim Starten der Anwendung ein Formular, das wir direkt beim &Ouml;ffnen ausblenden. Um das zu erledigen, nutzen wir das <b>AutoExec<\/b>-Makro.<\/p>\n<p>Legen Sie also ein neues Makro an, f&uuml;gen Sie die Makroaktion <b>&Ouml;ffnenFormular <\/b>hinzu, geben Sie dort als Formularnamen <b>frmSaveObjects <\/b>an und legen Sie f&uuml;r die Eigenschaft <b>Fenstermodus <\/b>den Wert <b>Ausgeblendet <\/b>fest (siehe Bild 7).  Speichern Sie es dann unter dem Namen <b>AutoExec<\/b>, damit es beim Starten der Datenbank automatisch ausgef&uuml;hrt wird.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1386_007.png\" alt=\"Das AutoExec-Makro\" width=\"624,559\" height=\"303,2133\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Das AutoExec-Makro<\/span><\/b><\/p>\n<p>Danach f&uuml;gen wir ein neues Formular namens <b>frmSaveObjects <\/b>hinzu, das beim Start unsichtbar ge&ouml;ffnet werden soll. F&uuml;r dieses Formular legen wir zwei Ereignisprozeduren fest. Die erste soll beim Laden ausgef&uuml;hrt werden und daf&uuml;r sorgen, dass je nach Wunsch des Benutzers die Objekte aus der gespeicherten Konfiguration des Arbeitsbereichs ge&ouml;ffnet werden. Die zweite feuert beim Entladen und soll den Benutzer fragen, ob er die Konfiguration der zu diesem Zeitpunkt ge&ouml;ffneten Objekte des Arbeitsbereichs speichern soll.<\/p>\n<p>Die Prozedur <b>Form_Load <\/b>sieht wie in Listing 3 aus und fragt den Benutzer per Meldungsfenster mit den beiden Schaltfl&auml;chen <b>Ja <\/b>und <b>Nein<\/b>, ob dieser die zuletzt gespeicherte Konfiguration wiederherstellen m&ouml;chte. Falls ja, soll die oben beschriebene Prozedur <b>OpenObjects <\/b>aufgerufen werden.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     If <span style=\"color:blue;\">MsgBox<\/span>(\"Gespeicherten Arbeitsbereich wiederherstellen?\", vbYesNo + vbInformation, _\r\n             \"Arbeitsbereich wiederherstellen\") = vbYes Then\r\n         OpenObjects Me.Name\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 3: Prozedur, die beim Laden des Formulars ausgef&uuml;hrt wird<\/span><\/b><\/p>\n<p>Diese haben wir allerdings noch um einen Parameter erweitert. Welchen Grund hat das? Wir wollen die Gr&ouml;&szlig;e und Position des unsichtbar ge&ouml;ffneten Formulars <b>frmSaveObjects <\/b>nicht mit speichern und auch nicht wiederherstellen. Deshalb &uuml;bergeben wir den Namen dieses Formulars an die Prozedur und sorgen in dieser Prozedur daf&uuml;r, dass dieses Formular beim Wiederherstellen nicht ber&uuml;cksichtigt wird.<\/p>\n<p>Die notwendigen &Auml;nderungen in der Prozedur <b>OpenObjects <\/b>finden Sie in Listing 4. Hier haben wir den Parameter <b>strExclude <\/b>deklariert und an zwei Stellen <b>If&#8230;Then<\/b>-Bedingungen eingef&uuml;gt, die in dem Fall, dass <b>strExclude <\/b>leer ist, die enthaltenen Anweisungen nicht ausf&uuml;hren, sondern zum n&auml;chsten Element springen.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>OpenObjects(<span style=\"color:blue;\">Optional<\/span> strExclude<span style=\"color:blue;\"> As String<\/span>)\r\n     ...\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n         Select Case rst!Objecttype\r\n             ...\r\n             <span style=\"color:blue;\">Case <\/span>acForm\r\n                 <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> rst!Objectname = strExclude<span style=\"color:blue;\"> Then<\/span>\r\n                     Select Case rst!ObjectView\r\n                         <span style=\"color:blue;\">Case <\/span>1\r\n                             intFormView = acNormal\r\n                         <span style=\"color:blue;\">Case <\/span>2\r\n                             intFormView = acFormDS\r\n                     <span style=\"color:blue;\">End Select<\/span>\r\n                     DoCmd.OpenForm rst!Objectname, intFormView\r\n                 <span style=\"color:blue;\">End If<\/span>\r\n             ...\r\n         <span style=\"color:blue;\">End Select<\/span>\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> rst!Objectname = strExclude<span style=\"color:blue;\"> Then<\/span>\r\n             DoCmd.MoveSize rst!ObjectLeft, rst!ObjectTop, rst!ObjectWidth, rst!ObjectHeight\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         rst.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Anpassungen in der Prozedur OpenObjects<\/span><\/b><\/p>\n<h2>Speichern der Konfiguration beim Schlie&szlig;en<\/h2>\n<p>Die Prozedur <b>OpenObjects <\/b>h&auml;tten wir eigentlich auch direkt vom <b>AutoExec<\/b>-Makro aus aufrufen k&ouml;nnen statt &uuml;ber den Umweg des Formulars mit der <b>Form_Load<\/b>-Prozedur. Allerdings ben&ouml;tigen wir das unsichtbare Formular f&uuml;r den oben genannten Trick. Genau genommen m&uuml;sste das Formular gar nicht unsichtbar sein &#8211; das machen wir nur, damit der Benutzer es nicht schlie&szlig;t und uns damit den Trick vermiest.<\/p>\n<p>Das Formular soll n&auml;mlich am Ende, wenn der Benutzer die Anwendung schlie&szlig;t, ebenfalls geschlossen werden. Dann l&ouml;st es n&auml;mlich noch das Ereignis <b>Beim Entladen <\/b>aus, mit dem wir den Benutzer fragen, ob er die aktuelle Konfiguration des Arbeitsbereichs noch speichern m&ouml;chte.<\/p>\n<p>Falls ja, rufen wir die Prozedur <b>SaveObjectInfo <\/b>auf, der wir ebenfalls wieder den Namen des Formulars &uuml;bergeben (siehe Listing 5).<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Unload(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     If <span style=\"color:blue;\">MsgBox<\/span>(\"Gr&ouml;&szlig;e und Position der ge&ouml;ffneten Objekte speichern?\", vbYesNo + vbInformation, _\r\n             \"Arbeitsbereich speichern\") = vbYes Then\r\n         SaveObjectInfo Me.Name\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 5: Prozedur, die beim Entladen des Formulars ausgef&uuml;hrt wird<\/span><\/b><\/p>\n<p>Die Prozedur <b>SaveObjectInfo <\/b>passen wir wie in Listing 6 an, damit der &uuml;bergebene Parameter verarbeitet wird. Diesen werten wir nur in der <b>For Each<\/b>-Schleife &uuml;ber alle Formulare aus. Nur wenn der Name des aktuellen Formulars aus <b>frm.Name <\/b>nicht mit dem Inhalt des Parameters <b>strExclude <\/b>&uuml;bereinstimmt, speichert die Prozedur die Konfiguration des Formulars.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>SaveObjectInfo(<span style=\"color:blue;\">Optional<\/span> strExclude<span style=\"color:blue;\"> As String<\/span>)\r\n     ...\r\n     For Each frm In Forms\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> frm.Name = strExclude<span style=\"color:blue;\"> Then<\/span>\r\n             strName = frm.Name\r\n             intType = acForm\r\n             intView = frm.CurrentView\r\n             intTop = frm.WindowTop\r\n             int<span style=\"color:blue;\">Left<\/span> = frm.WindowLeft\r\n             intWidth = frm.WindowWidth\r\n             intHeight = frm.WindowHeight\r\n             db.Execute \"INSERT INTO tblObjects(Objectname, Objecttype, ObjectTop, ObjectLeft, ObjectWidth, \" _\r\n                 & \"ObjectHeight, ObjectView) VALUES(''\" & strName & \"'', \" & intType & \", \" & intTop & \", \" & int<span style=\"color:blue;\">Left<\/span> _\r\n                 & \", \" & intWidth & \", \" & intHeight & \", \" & intView & \")\", dbFailOnError\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> frm\r\n     ...\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Prozedur SaveObjectInfo mit Parameter strExclude<\/span><\/b><\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Dieser Beitrag stellt eine Tabelle und zwei Prozeduren vor, mit denen die Gr&ouml;&szlig;e und die Position der aktuell ge&ouml;ffneten Elemente gespeichert und wiederhergestellt werden k&ouml;nnen.<\/p>\n<p>Diese Funktion haben wir so in eine Anwendung integriert, dass diese beim &Ouml;ffnen fragt, ob die Objekte entsprechend den in der Tabelle gespeicherten Daten wiederhergestellt werden sollen. Beim Schlie&szlig;en der Anwendung fragt die Funktion, ob die aktuelle Konstellation gespeichert werden soll.<\/p>\n<p>Der Benutzer kann jedoch auch manuell zu einem beliebigen Zeitpunkt die Prozedur <b>SaveObjectInfo <\/b>aufrufen und die aktuelle Konstellation speichern oder diese mit <b>LoadObjects <\/b>wiederherstellen.<\/p>\n<p>Gegebenenfalls lie&szlig;e sich diese Funktion auch per Access-Add-In oder COM-Add-In realisieren, damit diese immer in der Benutzeroberfl&auml;che zur Verf&uuml;gung steht.<\/p>\n<h2>Downloads zu diesem Beitrag<\/h2>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>PositionenVonAccessObjektenSpeichernUndWiederherstellen.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/68BD1CDD-0B86-4B9D-948E-2B4B42834655\/aiu_1386.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Neulich fragte ein Leser, ob und wie man die Position von Objekten im Access-Fenster speichern und wiederherstellen k&ouml;nne. Der Hintergrund ist, dass er immer wieder m&uuml;hsam Tabellen, Abfragen und andere Objekte zu einem Arbeitsbereich zusammengestellt hat und wenn er die Anwendung schlie&szlig;t, ist die ganze Arbeit dahin &#8211; und am n&auml;chsten Tag muss er die Objekte erneut anordnen. Ich f&uuml;hlte mich ein wenig an Zeiten erinnert, wo man zwar einen Homecomputer zum Programmieren, aber kein Ger&auml;t zum Speichern der eingetippten Spiele aus den Computermagazinen hatte &#8230; Da sich die Zeiten zum Gl&uuml;ck ge&auml;ndert haben, zeige ich in diesem Beitrag, wie Sie die Position und Gr&ouml;&szlig;e der beim Schlie&szlig;en einer Datenbank ge&ouml;ffneten Objekte abspeichern und beim n&auml;chsten &Ouml;ffnen wieder herstellen k&ouml;nnen.<\/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":[662022,66052022,44000023],"tags":[],"class_list":["post-55001386","post","type-post","status-publish","format-standard","hentry","category-662022","category-66052022","category-Mit_Formularen_arbeiten"],"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>Objektpositionen speichern und wiederherstellen - 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\/Objektpositionen_speichern_und_wiederherstellen\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Objektpositionen speichern und wiederherstellen\" \/>\n<meta property=\"og:description\" content=\"Neulich fragte ein Leser, ob und wie man die Position von Objekten im Access-Fenster speichern und wiederherstellen k&ouml;nne. Der Hintergrund ist, dass er immer wieder m&uuml;hsam Tabellen, Abfragen und andere Objekte zu einem Arbeitsbereich zusammengestellt hat und wenn er die Anwendung schlie&szlig;t, ist die ganze Arbeit dahin - und am n&auml;chsten Tag muss er die Objekte erneut anordnen. Ich f&uuml;hlte mich ein wenig an Zeiten erinnert, wo man zwar einen Homecomputer zum Programmieren, aber kein Ger&auml;t zum Speichern der eingetippten Spiele aus den Computermagazinen hatte ... Da sich die Zeiten zum Gl&uuml;ck ge&auml;ndert haben, zeige ich in diesem Beitrag, wie Sie die Position und Gr&ouml;&szlig;e der beim Schlie&szlig;en einer Datenbank ge&ouml;ffneten Objekte abspeichern und beim n&auml;chsten &Ouml;ffnen wieder herstellen k&ouml;nnen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Objektpositionen_speichern_und_wiederherstellen\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2022-10-03T14:37:08+00:00\" \/>\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=\"21\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Objektpositionen_speichern_und_wiederherstellen\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Objektpositionen_speichern_und_wiederherstellen\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Objektpositionen speichern und wiederherstellen\",\"datePublished\":\"2022-10-03T14:37:08+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Objektpositionen_speichern_und_wiederherstellen\\\/\"},\"wordCount\":3462,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"articleSection\":[\"2022\",\"5\\\/2022\",\"Mit Formularen arbeiten\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Objektpositionen_speichern_und_wiederherstellen\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Objektpositionen_speichern_und_wiederherstellen\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Objektpositionen_speichern_und_wiederherstellen\\\/\",\"name\":\"Objektpositionen speichern und wiederherstellen - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"datePublished\":\"2022-10-03T14:37:08+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Objektpositionen_speichern_und_wiederherstellen\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Objektpositionen_speichern_und_wiederherstellen\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Objektpositionen_speichern_und_wiederherstellen\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Objektpositionen speichern und wiederherstellen\"}]},{\"@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":"Objektpositionen speichern und wiederherstellen - 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\/Objektpositionen_speichern_und_wiederherstellen\/","og_locale":"de_DE","og_type":"article","og_title":"Objektpositionen speichern und wiederherstellen","og_description":"Neulich fragte ein Leser, ob und wie man die Position von Objekten im Access-Fenster speichern und wiederherstellen k&ouml;nne. Der Hintergrund ist, dass er immer wieder m&uuml;hsam Tabellen, Abfragen und andere Objekte zu einem Arbeitsbereich zusammengestellt hat und wenn er die Anwendung schlie&szlig;t, ist die ganze Arbeit dahin - und am n&auml;chsten Tag muss er die Objekte erneut anordnen. Ich f&uuml;hlte mich ein wenig an Zeiten erinnert, wo man zwar einen Homecomputer zum Programmieren, aber kein Ger&auml;t zum Speichern der eingetippten Spiele aus den Computermagazinen hatte ... Da sich die Zeiten zum Gl&uuml;ck ge&auml;ndert haben, zeige ich in diesem Beitrag, wie Sie die Position und Gr&ouml;&szlig;e der beim Schlie&szlig;en einer Datenbank ge&ouml;ffneten Objekte abspeichern und beim n&auml;chsten &Ouml;ffnen wieder herstellen k&ouml;nnen.","og_url":"https:\/\/access-im-unternehmen.de\/Objektpositionen_speichern_und_wiederherstellen\/","og_site_name":"Access im Unternehmen","article_published_time":"2022-10-03T14:37:08+00:00","author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"21\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Objektpositionen_speichern_und_wiederherstellen\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Objektpositionen_speichern_und_wiederherstellen\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Objektpositionen speichern und wiederherstellen","datePublished":"2022-10-03T14:37:08+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Objektpositionen_speichern_und_wiederherstellen\/"},"wordCount":3462,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"articleSection":["2022","5\/2022","Mit Formularen arbeiten"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Objektpositionen_speichern_und_wiederherstellen\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Objektpositionen_speichern_und_wiederherstellen\/","url":"https:\/\/access-im-unternehmen.de\/Objektpositionen_speichern_und_wiederherstellen\/","name":"Objektpositionen speichern und wiederherstellen - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"datePublished":"2022-10-03T14:37:08+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Objektpositionen_speichern_und_wiederherstellen\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Objektpositionen_speichern_und_wiederherstellen\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Objektpositionen_speichern_und_wiederherstellen\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Objektpositionen speichern und wiederherstellen"}]},{"@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\/55001386","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=55001386"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001386\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001386"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001386"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001386"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}