Tipps und Tricks

Berichte und Reporting

Wie seinen Rechner, sein Auto oder das Design seiner Internetseite wird man gelegentlich auch mal das Aussehen seines Briefkopfes leid und tauscht diesen kurzerhand aus. Kurzerhand Nicht wirklich: Wenn Sie etwa mehrere Access-Anwendungen anpassen müssen, die wiederum mehrere Berichte mit Ihrem Briefkopf enthalten, wartet eine Menge Handarbeit auf Sie.

Dabei geht es doch viel leichter: Erstellen Sie doch einfach einen Unterbericht mit dem Briefkopf und fügen Sie diesen in alle anderen Berichte, die einen Briefkopf benötigen, ein. Damit brauchen Sie änderungen nur noch an einer Stelle vorzunehmen. Selbst wenn Sie mehrere Anwendungen haben, die Berichte mit einem Briefkopf enthalten, ist die Aufgabe schnell erledigt, denn Sie müssen ja nur den angepassten Bericht mit dem Briefkopf in alle relevanten Access-Datenbanken kopieren.

Und so funktioniert es: Legen Sie einen Bericht an und platzieren Sie darin die Elemente Ihres Briefkopfes. Entfernen Sie die Berichtskopfelemente aus einem vorhandenen Bericht. Fügen Sie dann den Bericht mit dem Briefkopf in den Zielbericht ein – das geht am einfachsten, wenn Sie den Zielbericht in der Entwurfsansicht öffnen und den einzufügenden Bericht aus dem Datenbankfenster an die gewünschte Stelle des Zielberichts ziehen.

VBA und Programmiertechnik

Wer keine Arbeit hat, der macht sich welche. Zum Beispiel, indem er funktionierende Codepassagen aus einer Routine in eine andere Routine kopiert. Funktioniert per Copy and Paste und liefert auch funktionell das gewünschte Ergebnis.

Manchmal programmiert man auch unbewusst an zwei Stellen innerhalb des gleichen Moduls oder zumindest innerhalb der gleichen Anwendung Codezeilen, die entweder völlig identisch sind oder zumindest genau die gleiche Funktion haben. Stehen dann einmal änderungen innerhalb dieser Code-Dubletten an, hat man direkt die doppelte (oder x-fache) Arbeit: Jede änderung müssen Sie an mehreren Stellen durchführen, damit alles wieder wie gewünscht funktioniert. Dabei lassen sich solche Probleme ganz einfach lösen: “Klammern” Sie den doppelten Code einfach aus, indem Sie ihn in einer eigenen Routine anlegen und von den ursprünglichen Routinen darauf verweisen. Im einfachsten Fall funktioniert das nach dem folgenden Schema: Nehmen wir an, dass Sie bei bestimmten Aktionen eine Reihe von Steuerelementen in einem Formular aktivieren oder deaktivieren möchten und dass a im ganzen Modul bekannt ist:

Private Form_Load()
     If a Then
         Me!txt1.Enabled = True
         Me!txt2.Enabled = True
         Me!txt3.Enabled = True
     Else
         Me!txt1.Enabled = False
         Me!txt2.Enabled = False
         Me!txt3.Enabled = False
     End If
     ...
End Sub
Private cmdBeispiel_Click()
     If a Then
         Me!txt1.Enabled = True
         ...
End Sub

Wenn Sie dies nun bei verschiedenen Gelegenheiten tun – etwa beim öffnen des Formulars, beim Anzeigen eines neuen Datensatzes oder beim Klick auf eine bestimmte Schaltfläche – haben Sie den gleichen Code an mehreren Stellen stehen. Kommt nun noch ein weiteres Steuerelement hinzu, müssen Sie den Code an mehreren Stellen anpassen. Stattdessen erstellen Sie eine neue Funktion mit einem sinnvollen Namen, etwa SteuerelementeAnpassen.

Private Sub SteuerelementeAnpassen
     If a Then
         Me!txt1.Enabled = True
         Me!txt2.Enabled = True
         Me!txt3.Enabled = True
     Else
         Me!txt1.Enabled = False
         Me!txt2.Enabled = False
         Me!txt3.Enabled = False
     End If
End Sub

Ersetzen Sie dann diese “extrahierten” Zeilen an allen betroffenen Stellen durch einen einfachen Aufruf der neuen Routine SteuerelementeAnpassen, etwa so:

Private Form_Load()
     SteuerelementeAnpassen
     ...
End Sub
Private cmdBeispiel_Click()
     SteuerelementeAnpassen
     ...
End Sub

Nun können Steuerelemente hinzukommen oder wegfallen, wie sie wollen, die Anpassung müssen Sie immer nur an einer Stelle vornehmen.

Sie haben das Ende des frei verfügbaren Textes erreicht. Möchten Sie ...

Workplace

Jahresabonnement TestzugangOder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

Christoph Spielmann, Düsseldorf

In der vorliegenden Ausgabe von Access im Unternehmen präsentieren wir Ihnen wieder einige Tipps & Tricks, die es in sich haben. Sie erfahren, wie Sie beliebige Dateien von Access aus öffnen, ohne die Anwendung auswählen zu müssen und wie Sie unerwünschte Zeichen aus Dateinamen entfernen können. Außerdem stellen wir Ihnen eine Möglichkeit vor, um ein Laufband in den Formularen Ihrer Access-Anwendung unterzubringen.

Unter Windows ist bekanntlich jede Dateierweiterung mit einer passenden Anwendung verknüpft. Dieser Tipp zeigt Ihnen, wie Sie eine Datei von Access aus direkt zusammen mit der zugeordneten Anwendung öffnen.

Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd _    As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters _    As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long

Quellcode 1

Public Function OpenDocument(DocumentFile As String) As Long
    Dim ret As Long
        If Len(DocumentFile) > 0 Then
            ret = ShellExecute(Application.hWndAccessApp, "open", DocumentFile, _                vbNullChar, "", 1)
            If Err Then
                OpenDocument = 0
            ElseIf ret > 32 Then
                OpenDocument = -1
            Else
                OpenDocument = ret
            End If
        Else
        OpenDocument = 0
    End If
End Function

Quellcode 2

Die Information darüber, welche Anwendungen für welche Dateien zuständig sind, ist in der Registry von Windows untergebracht. Nun wäre es sehr mühselig, die Informationen hier auszulesen. Zum Glück kann Windows da mit einer passenden API-Funktion aufwarten, die Ihnen diese Arbeit abnimmt. Diese API-Funktion trägt den Namen ShellExecute und wird wie in Quellcode 1 deklariert:

Da die einzelnen Parameter etwas unübersichtlich sind, kann der Aufruf mit Hilfe der VBA-Prozedur aus Quellcode 2 vereinfacht werden.

Public Function CreateValidFilename(ByVal Filename _    As String) As String
    Dim i As Long
    Dim Text As String
    Dim Länge As Long
    Dim Zeichen As String
    For i = 1 To Len(Filename)
        Select Case Asc(Mid$(Filename, i, 1))
            Case Is < 32, 92, 47, 58, 42, 63, 34, 60, _                62, 124
                Mid$(Filename, i, 1) = "_"
        End Select
    Next
    CreateValidFilename = Filename
End Function

Quellcode 3

Diese Funktion erwartet als Parameter lediglich den Dateinamen der zu öffnenden Datei. Als Ergebnis erhalten Sie im Fehlerfall einen Wert kleiner oder gleich 0 zurück. Wenn Sie beispielsweise die Excel-Datei C:\\Mappe1.xls in Excel öffnen möchten, dann geben Sie lediglich den folgenden Ausdruck an:

OpenDocument "C:\\Mappe1.xls"

Die komplette Funktion finden Sie im Modul modOpenDocument der BeispieldatenbankTippsTricks0206.mdb.

Bei der Eingabe eines Dateinamens sind fast alle Zeichen erlaubt. Eine Ausnahme bilden jedoch die folgenden Zeichen:

\\ / : * " < > |

Die Prozedur aus Quellcode 3 prüft einen Dateinamen auf eines dieser Zeichen und ersetzt dieses automatisch durch einen Unterstrich. Wenn Sie dieser Funktion beispielsweise den Text Umsatz 2002/2003.xls übergeben, wird dieser in Umsatz 2002_2003.xls umgewandelt und kann als Dateiname verwendet werden.

Sie haben das Ende des frei verfügbaren Textes erreicht. Möchten Sie ...

Workplace

Jahresabonnement TestzugangOder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

Autor: Christoph Spielmann, Düsseldorf

Auf den folgenden Seiten versorgt Sie unser Autor Christoph Spielmann mit einigen Tipps und Tricks rund um VBA, die Sie sofort in Betrieb nehmen können. Hier finden Sie beispielsweise eine Möglichkeit, die Bildschirmauflösung zu ermitteln. Das kann u. a. für die Auslegung der Größe von For-mularen sehr interessant sein. Sie lernen, wie Sie Dateien entgültig löschen (ohne doppelten Boden, direkt in den Reißwolf) und wie Sie dem Anwender von Ihrer Applikation aus eine Möglichkeit zur Verfügung stellen, mal eben eine Diskette zu formatieren. Falls Sie einmal ein bestimmtes Systemverzeichnis auf Ihrer Festplatte vermissen – keine Sorge, hier finden Sie die richtige Funktion, um es wiederzufinden. Die nachfolgend beschriebenen Funktionen packen Sie am besten gut an eine sichere Stelle – Sie werden sie immer wieder benötigen.

Einige Office-Anwendungen stellen Ihnen die aktuelle Bildschirmgröße direkt zur Verfügung. So finden Sie beispielsweise in den Eigenschaften HorizontalResolution und VerticalResolution des System-Objekts der Word-Bibliothek die Breite und die Höhe des Bildschirms in Pixel:

Breite = System.HorizontalResolution
Höhe = System.VerticalResolution
Private Declare Function GetDC Lib "user32" _
    (ByVal hwnd As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32" _
    (ByVal hdc As Long, ByVal nIndex As Long) As Long
Private Declare Function ReleaseDC Lib "user32" _
    (ByVal hwnd As Long, ByVal hdc As Long) As Long
Private Const HORZRES = 8
Private Const VERTRES = 10
Public Property Get ScreenHeightPixels() As Long
    Dim nDC As Long
    nDC = GetDC(0)
    ScreenHeightPixels = GetDeviceCaps(nDC, VERTRES)
    ReleaseDC 0, nDC
End Property
Public Property Get ScreenWidthPixels() As Long
    Dim nDC As Long
    nDC = GetDC(0)
    ScreenWidthPixels = GetDeviceCaps(nDC, HORZRES)
    ReleaseDC 0, nDC
End Property

Doch in der Access-Bibliothek fehlt diese Möglichkeit. Und in keiner der Bibliotheken der Office-Anwendungen finden Sie eine direkte oder indirekte Möglichkeit, die aktuelle Bildschirmauflösung in Erfahrung zu bringen (die Bildschirmauflösung hängt davon ab, ob der Anwender in den Bildschirmeinstellungen große oder kleine Bildschirmschriften oder eine beliebige Schriftgröße eingestellt hat).

Die gesuchten Werte liefert dagegen immer aktuell die API-Funktion GetDeviceCaps. Sie wird für den Gerätekontext (DC) eines bestimmten Geräts aufgerufen, etwa eines Druckers oder eben des Bildschirms.

Private Const LOGPIXELSX = 88
Private Const LOGPIXELSY = 90
Public Property Get dpiX() As Long
    Dim nDC As Long
    nDC = GetDC(0)
    dpiX = GetDeviceCaps(nDC, LOGPIXELSX)
    ReleaseDC 0, nDC
End Property
Public Property Get dpiY() As Long
    Dim nDC As Long
    nDC = GetDC(0)
    dpiY = GetDeviceCaps(nDC, LOGPIXELSY)
    ReleaseDC 0, nDC
End Property
Public Property Get TwipsPerPixelX() As Single
    Dim nDC As Long
    nDC = GetDC(0)
    TwipsPerPixelX = 1440 / _        GetDeviceCaps(nDC, LOGPIXELSX)
    ReleaseDC 0, nDC
End Property
Public Property Get TwipsPerPixelY() As Single
    Dim nDC As Long
    nDC = GetDC(0)
    TwipsPerPixelY = 1440 / _        GetDeviceCaps(nDC, LOGPIXELSY)
    ReleaseDC 0, nDC
End Property
Public Property Get ScreenHeightTWIPS() As Single
    Dim nDC As Long
    nDC = GetDC(0)
    ScreenHeightTWIPS = GetDeviceCaps(nDC, VERTRES) * _
     (1440 / GetDeviceCaps(nDC, LOGPIXELSY))
    ReleaseDC 0, nDC
End Property
Public Property Get ScreenWidthTWIPS() As Single
    Dim nDC As Long
    nDC = GetDC(0)
    ScreenWidthTWIPS = GetDeviceCaps(nDC, HORZRES) * _
        (1440 / GetDeviceCaps(nDC, LOGPIXELSX))
    ReleaseDC 0, nDC
End Property

Den Gerätekontext des Bildschirms erhalten Sie über die API-Funktion GetDC, der Sie als Fenster-Handle für den ganzen Bildschirm den Wert 0 übergeben.

Nach der Verwendung des Gerätekontextes müssen Sie daran denken, ihn wieder mit der API-Funktion ReleaseDC freizugeben.

Neben dem Gerätekontext übergeben Sie der Funktion GetDeviceCaps den jeweiligen Index, zu dem Sie den gewünschten Wert erhalten wollen. über die beiden Hilfs-funktionen ScreenHeightPixels und ScreenWidthPixels erhalten Sie auf diese Weise z. B. die Bildschirmhöhe und die Bildschirmbreite.

In Quellcode 1 finden Sie zunächst die erforderlichen Deklarationen der benötigten API-Funktionen sowie der dazugehörenden Konstanten.

Die fehlende Information über die Bildschirmauflösung erhalten Sie über die Funktion GetDeviceCaps (Beispiele s. Quellcode 2). Sie liefert Ihnen direkt die vertikale und die horizontale Bildschirmauflösung in dpi (Dots per Inch).

Scheinbar sind die vertikale und die horizontale Auflösung immer gleich. Doch sollten Sie sich nicht darauf verlassen – es kann durchaus das eine oder andere Bildschirmgerät mit unterschiedlicher horizontaler und vertikaler Auflösung geben.

Aus der Bildschirmauflösung in dpi können Sie zusätzlich noch den vertikalen und den horizontalen Umrechnungsfaktor für die Maßeinheit TWIPS ermitteln.

Private Type SHFILEOPSTRUCT
    hWnd As Long
    wFunc As Long
    pFrom As String
    pTo As String
    fFlags As Integer
    fAnyOperationsAborted As Long
    hNameMappings As Long
    lpszProgressTitle As String
End Type
Quellcode 5
Private Declare Function SHFileOperation Lib _
    "Shell32.dll" Alias "SHFileOperationA" (lpFileOp _
    As SHFILEOPSTRUCT) As Long
Quellcode 6
Public Function Kill(Files As Variant, Optional ByVal _    AllowUndo As Boolean, Optional ByVal ShowProgress _    As Boolean, Optional ByVal Confirmation As _    Boolean,  Optional ByVal Simple As Boolean, _
    Optional ByVal SysErrors As Boolean, Optional _    ByVal hWnd As Long, Optional UserAborts As Variant _
    ) As Boolean
    Dim l As Long
    Dim nFileOperations As SHFILEOPSTRUCT
    Const FO_DELETE = &H3
    Const FOF_ALLOWUNDO = &H40
    Const FOF_SILENT = &H4
    Const FOF_NOCONFIRMATION = &H10
    Const FOF_SIMPLEPROGRESS = &H100
    Const FOF_NOERRORUI = &H400

Diese ist ein bei vielen externen Steuerelementen (wie etwa den Microsoft Common Controls) verwendeter Standard für bildschirmbezogene Abmessungen. Diese Maßeinheit errechnet sich als 1440stel der horizontalen bzw. vertikalen Bildschirmauflösung, wie sie von GetDeviceCaps geliefert wird (s. Quellcode 3).

Die Bildschirmgröße in TWIPS erhalten Sie dementsprechend über die Funktionen ScreenWidthTWIPS und ScreenHeightTWIPS (s. Quellcode 4)

Eine Datei zu löschen ist in VBA ein Kinderspiel – zum Beispiel mit folgender Anweisung:

Kill "c:\\autoexec.bat"

– und schon ist die Datei weg. Und zwar unrettbar verloren.

Vor allem bei vom Anwender ausgelösten Dateilöschungen sollten Sie ihm die Windows-übliche Möglichkeit einräumen, gelöschte Dateien und Ordner aus dem Papierkorb wieder herstellen zu können.

Verwenden Sie in solchen Fällen die API-Funktion SHFileOperation (s. Quellcode 6). Bei dieser können Sie wählen, ob die Datei(en) im Papierkorb landen, oder ob sie wie bei der VBA-Kill-Anweisung gleich vollständig gelöscht werden.

Außerdem können Sie die ge-wohnte Fortschrittsanzeige bieten und einige zusätzliche Einstellungen festlegen (SHFILEOPSTRUCT, Aussehen der Definition s. Quellcode 5).

Ebenso können Sie mit ihr komplette Ordner auf einen Schlag löschen – ein komplizierter, rekursiver Mechanismus mit den VBA-Anweisungen Kill und RmDir entfällt, da mit diesem Mechanismus alle untergeordneten Ordner geleert und einzeln gelöscht werden müssten.

    With nFileOperations
    If IsArray(Files) Then
        For l = LBound(Files) To UBound(Files)
            .pFrom = .pFrom & Files(l) & vbNullChar
        Next ''l
        .pFrom = .pFrom & vbNullChar
    ElseIf VarType(Files) = vbObject Then
        If TypeOf Files Is Collection Then
            For l = 1 To Files.Count
                .pFrom = .pFrom & Files(l) & vbNullChar
            Next ''l
            .pFrom = .pFrom & vbNullChar
        End If
    ElseIf VarType(Files) = vbString Then
        .pFrom = Files
        If Right$(.pFrom, 1) <> vbNullChar Then
            .pFrom = .pFrom & vbNullChar
        End If
        If Mid$(.pFrom, Len(.pFrom) - 1, 1) <> _            vbNullChar Then
            .pFrom = .pFrom & vbNullChar
        End If
    End If
    If AllowUndo Then 
      .fFlags = FOF_ALLOWUNDO
    End If
    If Not ShowProgress Then
      .fFlags = .fFlags Or FOF_SILENT
    End If
    If Not Confirmation Then
      .fFlags = .fFlags Or FOF_NOCONFIRMATION
    End If
    If Simple Then
      .fFlags = .fFlags Or FOF_SIMPLEPROGRESS
    End If
    If Not SysErrors Then
      .fFlags = .fFlags Or FOF_NOERRORUI
    End If
    .wFunc = FO_DELETE
    .hWnd = hWnd
    Kill = Not CBool(SHFileOperation(nFileOperations))
    If Not IsMissing(UserAborts) Then
      UserAborts = CBool(.fAnyOperationsAborted)
    End If
    End With
End Function

Die hier vorgestellte Ersatzfunktion Kill (s. Quellcode 7) verhält sich wie das VBA-Original, wenn Sie ihr wie gewohnt lediglich den gewünschten Dateinamen übergeben.

Sie können dieser Ersatzfunktion aber auch ein dimensioniertes oder aktuell mit der Array-Funktion zusammengestelltes Array oder eine Collection aus einzelnen Datei- und Ordnerpfaden übergeben. Und Sie können Wildcards (etwa “*.*” oder “*.bas”) verwenden.

Die gewünschte Funktionalität legen Sie in den einzelnen optionalen Parametern fest. Sollen die Dateien in den Papierkorb verschoben werden, setzen Sie AllowUndo gleich True. Soll der Windows-übliche Fortschrittsdialog mit der Möglichkeit zum Abbrechen des Vorgangs angezeigt werden, setzen Sie ShowProgress gleich True.

Die Rückfrage, ob wirklich gelöscht werden soll, legen Sie mit Confirmation gleich True fest. Eine etwas vereinfachte Fortschrittsanzeige, bei der die Anzeige der gerade bearbeiteten Dateinamen unterbleibt, wählen Sie mit Simple gleich True. Wenn Sie im Fall eines Fehlers die Windows-Anzeige dieses Fehlers beibehalten wollen, setzen Sie SysErrors gleich True.

Unabhängig davon, wie Sie den letztgenannten Parameter setzen, gibt die Funktion Kill den Wert True zurück, wenn ein Fehler aufgetreten ist. Allerdings lässt sich der Fehler nicht näher spezifizieren – Sie müssen auf andere Weise prüfen, was schief gegangen sein könnte, z. B. Datei nicht vorhanden, gesperrt u. ä.

Hat der Anwender bei den gelegentlichen Rückfragen des Systems (wie etwa Löschen einer Systemdatei o. ä.) beispielsweise einzelne Dateien übersprungen, können Sie diese Information über den Parameter UserAborts erhalten, in der Sie dazu eine Variable übergeben müssen. Allerdings bleibt Ihnen auch hierbei nur übrig, selbst herausfinden, welche Dateien übersprungen worden sind.

Private Declare Function GetDesktopWindow _    Lib "user32" () As Long
Private Declare Function SHFormatDrive Lib "shell32" _    (ByVal hWnd As Long, ByVal Drive As Long, ByVal _    fmtID As Long, ByVal Options As Long) As Long
Public Enum fdReturnConstants
  fdRetSuccess = 0
  fdRetError = -1
  fdRetCancelled = -2
  fdRetNotFormattable = -3
  fdRetInvalidDrive = -4
End Enum

Das VBA-Original der Kill-Anweisung können Sie anstelle dieser erweiterten Kill-Funktion weiterhin jederzeit aufrufen. Dazu setzen Sie einfach den Herkunftsbezeichner (Qualifizierer) davor: “VBA.Kill …”.

Sie möchten es dem Anwender ermöglichen, in Ihrem Programm eine Diskette frisch zu formatieren Dann sollten Sie sich nicht lange mit der Entwicklung eigener Formatier-Routinen und Formatier-Dialoge aufhalten, sondern dem Anwender den entsprechenden Standard-Dialog anzeigen.

Sie haben das Ende des frei verfügbaren Textes erreicht. Möchten Sie ...

Workplace

Jahresabonnement TestzugangOder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

Autor: Christoph Spielmann, Düsseldorf

Auf den folgenden Seiten versorgt Sie unser Autor Christoph Spielmann mit einigen Tipps und Tricks rund um VBA, die Sie sofort in Betrieb nehmen können. Hier finden Sie beispielsweise eine Möglichkeit, die Bildschirmauflösung zu ermitteln, was z. B. für die Auslegung der Größe von Formularen sehr interessant sein kann. Sie lernen, wie Sie Dateien richtig löschen (ohne doppelten Boden, direkt in den Reißwolf) und wie Sie dem Anwender von Ihrer Applikation aus eine Möglichkeit zur Verfügung stellen, mal eben eine Diskette zu formatieren. Falls Sie einmal ein bestimmtes Systemverzeichnis auf Ihrer Festplatte vermissen – keine Sorge, hier finden Sie die richtige Funktion, um es wiederzufinden. Die nachfolgend beschrieben packen Sie am besten gut an eine sichere Stelle – Sie werden sie immer wieder benötigen.

Einige Office-Anwendungen stellen Ihnen die aktuelle Bildschirmgröße direkt zur Verfügung. So finden Sie beispielsweise in den Eigenschaften HorizontalResolution und VerticalResolution des System-Objekts der Word-Bibliothek die Breite und die Höhe des Bildschirms in Pixel:

Breite = System.HorizontalResolution
Höhe = System.VerticalResolution
Private Declare Function GetDC Lib "user32" _
    (ByVal hwnd As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32" _
    (ByVal hdc As Long, ByVal nIndex As Long) As Long
Private Declare Function ReleaseDC Lib "user32" _
    (ByVal hwnd As Long, ByVal hdc As Long) As Long
Private Const HORZRES = 8
Private Const VERTRES = 10
Public Property Get ScreenHeightPixels() As Long
    Dim nDC As Long
    nDC = GetDC(0)
    ScreenHeightPixels = GetDeviceCaps(nDC, VERTRES)
    ReleaseDC 0, nDC
End Property
Public Property Get ScreenWidthPixels() As Long
    Dim nDC As Long
    nDC = GetDC(0)
    ScreenWidthPixels = GetDeviceCaps(nDC, HORZRES)
    ReleaseDC 0, nDC
End Property

Doch in der Access-Bibliothek fehlt diese Möglichkeit. Und in keiner der Bibliotheken der Office-Anwendungen finden Sie eine direkte oder indirekte Möglichkeit, die aktuelle Bildschirmauflösung in Erfahrung zu bringen (die Bildschirmauflösung hängt davon ab, ob der Anwender in den Bildschirmeinstellungen große oder kleine Bildschirmschriften oder eine beliebige Schriftgröße eingestellt hat).

Die gesuchten Werte liefert dagegen immer aktuell die API-Funktion GetDeviceCaps. Sie wird für den Gerätekontext (DC) eines bestimmten Geräts aufgerufen, etwa eines Druckers oder eben des Bildschirms.

Private Const LOGPIXELSX = 88
Private Const LOGPIXELSY = 90
Public Property Get dpiX() As Long
    Dim nDC As Long
    nDC = GetDC(0)
    dpiX = GetDeviceCaps(nDC, LOGPIXELSX)
    ReleaseDC 0, nDC
End Property
Public Property Get dpiY() As Long
    Dim nDC As Long
    nDC = GetDC(0)
    dpiY = GetDeviceCaps(nDC, LOGPIXELSY)
    ReleaseDC 0, nDC
End Property
Public Property Get TwipsPerPixelX() As Single
    Dim nDC As Long
    nDC = GetDC(0)
    TwipsPerPixelX = 1440 / _        GetDeviceCaps(nDC, LOGPIXELSX)
    ReleaseDC 0, nDC
End Property
Public Property Get TwipsPerPixelY() As Single
    Dim nDC As Long
    nDC = GetDC(0)
    TwipsPerPixelY = 1440 / _        GetDeviceCaps(nDC, LOGPIXELSY)
    ReleaseDC 0, nDC
End Property
Public Property Get ScreenHeightTWIPS() As Single
    Dim nDC As Long
    nDC = GetDC(0)
    ScreenHeightTWIPS = GetDeviceCaps(nDC, VERTRES) * _
     (1440 / GetDeviceCaps(nDC, LOGPIXELSY))
    ReleaseDC 0, nDC
End Property
Public Property Get ScreenWidthTWIPS() As Single
    Dim nDC As Long
    nDC = GetDC(0)
    ScreenWidthTWIPS = GetDeviceCaps(nDC, HORZRES) * _
        (1440 / GetDeviceCaps(nDC, LOGPIXELSX))
    ReleaseDC 0, nDC
End Property

Den Gerätekontext des Bildschirms erhalten Sie über die API-Funktion GetDC, der Sie als Fenster-Handle für den ganzen Bildschirm den Wert 0 übergeben.

Nach der Verwendung des Gerätekontextes müssen Sie daran denken, ihn wieder mit der API-Funktion ReleaseDC freizugeben.

Neben dem Gerätekontext übergeben Sie der Funktion GetDeviceCaps einen Index, zu dem Sie den gewünschten Wert erhalten wollen. Zum Beispiel die Bildschirmhöhe und die Bildschirmbreite liefern auf diese Weise die beiden folgenden Hilfsfunktionen ScreenHeightPixels und ScreenWidthPixels.

In Quellcode 1 finden Sie zunächst die erforderlichen Deklarationen der benötigten API-Funktionen sowie der dazugehörenden Konstanten.

Die fehlende Information über die Bildschirmauflösung erhalten Sie über die Funktion GetDeviceCaps (Beispiele s. Quellcode 2) Sie liefert Ihnen direkt die vertikale und die horizontale Bildschirmauflösung in dpi (Dots per Inch).

Scheinbar sind die vertikale und die horizontale Auflösung immer gleich. Doch sollten Sie sich nicht darauf verlassen – es mag durchaus das eine oder andere Bildschirmgerät mit unterschiedlicher horizontaler und vertikaler Auflösung geben.

Aus der Bildschirmauflösung in dpi können Sie zusätzlich noch den vertikalen und den horizontalen Umrechnungsfaktor für die Maßeinheit TWIPS ermitteln.

Private Type SHFILEOPSTRUCT
    hWnd As Long
    wFunc As Long
    pFrom As String
    pTo As String
    fFlags As Integer
    fAnyOperationsAborted As Long
    hNameMappings As Long
    lpszProgressTitle As String
End Type
Quellcode 5
Private Declare Function SHFileOperation Lib _
    "Shell32.dll" Alias "SHFileOperationA" (lpFileOp _
    As SHFILEOPSTRUCT) As Long
Quellcode 6
Public Function Kill(Files As Variant, Optional ByVal _    AllowUndo As Boolean, Optional ByVal ShowProgress _    As Boolean, Optional ByVal Confirmation As _    Boolean,  Optional ByVal Simple As Boolean, _
    Optional ByVal SysErrors As Boolean, Optional _    ByVal hWnd As Long, Optional UserAborts As Variant _
    ) As Boolean
    Dim l As Long
    Dim nFileOperations As SHFILEOPSTRUCT
    Const FO_DELETE = &H3
    Const FOF_ALLOWUNDO = &H40
    Const FOF_SILENT = &H4
    Const FOF_NOCONFIRMATION = &H10
    Const FOF_SIMPLEPROGRESS = &H100
    Const FOF_NOERRORUI = &H400

Diese ist ein bei vielen externen Steuerelementen (wie etwa den Microsoft Common Controls) verwendeter Standard für bildschirmbezogene Abmessungen. Diese Maßeinheit errechnet sich als 1440tel der horizontalen bzw. vertikalen Bildschirmauflösung, wie sie von GetDeviceCaps geliefert wird (s. Quellcode 3).

Die Bildschirmgröße in TWIPS erhalten Sie dementsprechend über die Funktionen ScreenWidthTWIPS und ScreenHeightTWIPS (s. Quellcode 4)

Eine Datei zu löschen ist in VBA ein Kinderspiel – zum Beispiel mit folgender Anweisung:

Kill "c:\\autoexec.bat"

– und schon ist die Datei weg. Und unrettbar verloren.

Vor allem bei vom Anwender ausgelösten Dateilöschungen sollten Sie ihm daher die Windows-übliche Möglichkeit einräumen, gelöschte Dateien (und Ordner) aus dem Papierkorb wieder herzustellen zu können.

Verwenden Sie in solchen Fällen die API-Funktion SHFileOperation (s. Quellcode 6). Bei dieser können Sie wählen, ob die Datei(en) im Papierkorb landen, oder ob sie wie bei der VBA-Kill-Anweisung gleich vollständig gelöscht werden.

Außerdem können Sie die gewohnte Fortschrittsanzeige bieten und einige Einstellungen mehr festlegen (SHFILEOPSTRUCT, Aussehen der Definition s. Quellcode 5).

Ebenso können Sie mit ihr komplette Ordner auf einen Schlag löschen – ein komplizierter, rekursiver Mechanismus mit den VBA-Anwiesungen Kill und RmDir entfällt, mit dem alle untergeordneten Ordner geleert und einzeln gelöscht werden müssten.

    With nFileOperations
    If IsArray(Files) Then
        For l = LBound(Files) To UBound(Files)
            .pFrom = .pFrom & Files(l) & vbNullChar
        Next ''l
        .pFrom = .pFrom & vbNullChar
    ElseIf VarType(Files) = vbObject Then
        If TypeOf Files Is Collection Then
            For l = 1 To Files.Count
                .pFrom = .pFrom & Files(l) & vbNullChar
            Next ''l
            .pFrom = .pFrom & vbNullChar
        End If
    ElseIf VarType(Files) = vbString Then
        .pFrom = Files
        If Right$(.pFrom, 1) <> vbNullChar Then
            .pFrom = .pFrom & vbNullChar
        End If
        If Mid$(.pFrom, Len(.pFrom) - 1, 1) <> _            vbNullChar Then
            .pFrom = .pFrom & vbNullChar
        End If
    End If
    If AllowUndo Then 
      .fFlags = FOF_ALLOWUNDO
    End If
    If Not ShowProgress Then
      .fFlags = .fFlags Or FOF_SILENT
    End If
    If Not Confirmation Then
      .fFlags = .fFlags Or FOF_NOCONFIRMATION
    End If
    If Simple Then
      .fFlags = .fFlags Or FOF_SIMPLEPROGRESS
    End If
    If Not SysErrors Then
      .fFlags = .fFlags Or FOF_NOERRORUI
    End If
    .wFunc = FO_DELETE
    .hWnd = hWnd
    Kill = Not CBool(SHFileOperation(nFileOperations))
    If Not IsMissing(UserAborts) Then
      UserAborts = CBool(.fAnyOperationsAborted)
    End If
    End With
End Function

Die hier vorgestellte Ersatzfunktion Kill (s. Quellcode 7) verhält sich wie das VBA-Original, wenn Sie ihr (wie gewohnt) lediglich den gewünschten Dateinamen übergeben.

Sie können ihr aber auch ein (dimensioniertes oder aktuell mit der Array-Funktion zusammengestelltes) Array oder eine Collection aus einzelnen Datei- und Ordnerpfaden übergeben. Und sie können Wildcards (etwa “*.*” oder “*.bas”) verwenden.

Die gewünschte Funktionalität legen Sie in den einzelnen optionalen Parametern fest. Sollen die Dateien in den Papierkorb verschoben werden, setzen Sie AllowUndo gleich True. Soll der Windows-übliche Fortschrittsdialog mit Möglichkeit zum Abbrechen des Vorgangs angezeigt werden, setzen Sie ShowProgress gleich True.

Die Rückfrage, ob wirklich gelöscht werden soll, legen Sie mit Confirmation gleich True fest. Eine etwas vereinfachte Fortschrittsanzeige, bei der die Anzeige der gerade bearbeiteten Dateinamen unterbleibt, wählen Sie mit Simple gleich True. Wenn Sie im Falle eines Fehlers die Windows-Anzeige dieses Fehlers beibehalten wollen, setzen Sie SysErrors gleich True.

Unabhängig davon, wie Sie den letztgenannten Parameter setzen, gibt die Funktion Kill den Wert True zurück, wenn ein Fehler aufgetreten ist. Allerdings lässt sich der Fehler nicht näher spezifizieren – Sie müssen auf andere Weise prüfen, was schief gegangen sein könnte (Datei nicht vorhanden, gesperrt u. a.).

Hat der Anwender bei den gelegentlichen Rückfragen des Systems (Löschen einer Systemdatei o. ä.) beispielsweise einzelne Dateien übersprungen, können Sie diese Information über den Parameter UserAborts erhalten, in der Sie dazu eine Variable übergeben müssen. Allerdings müssen Sie auch hierbei wieder selbst herausfinden, welche Dateien übersprungen worden sind.

Private Declare Function GetDesktopWindow _    Lib "user32" () As Long
Private Declare Function SHFormatDrive Lib "shell32" _    (ByVal hWnd As Long, ByVal Drive As Long, ByVal _    fmtID As Long, ByVal Options As Long) As Long
Public Enum fdReturnConstants
  fdRetSuccess = 0
  fdRetError = -1
  fdRetCancelled = -2
  fdRetNotFormattable = -3
  fdRetInvalidDrive = -4
End Enum

Das VBA-Original der Kill-Anweisung können Sie anstelle dieser erweiterten Kill-Funktion weiterhin jederzeit aufrufen. Dazu setzen Sie einfach den Herkunftsbezeichner (Qualifizierer) davor: “VBA.Kill …”.

Sie möchten es dem Anwender ermöglichen, in Ihrem Programm eine Diskette frisch zu formatieren Dann sollten Sie sich nicht lange mit der Entwicklung eigener Formatier-Routinen und -Dialogen aufhalten, sondern dem Anwender den entsprechenden Standard-Dialog anzeigen.

Sie haben das Ende des frei verfügbaren Textes erreicht. Möchten Sie ...

Workplace

Jahresabonnement TestzugangOder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

André Minhorst, Duisburg

Die Anzeige von Berichten bringt in der Regel zwei Probleme mit sich:

Erstens ist der Bericht selten so an das Berichtsfenster angepasst, dass der Betrachter den gewünschten Ausschnitt in einer geeigneten Auflösung vorfindet (s. Abb. 1).

Und zweitens entsprechen die Proportionen des Berichtsfensters beim öffnen selten denen des Berichtes.

Wenn der Benutzer einer Datenbankanwendung nur hin und wieder einen Bericht in der Vorschau öffnet, mögen die Probleme sicher nicht gravierend sein. Bei einer häufigen Anwendung der Berichtsvorschau wird das Anpassen der Größe des Fensters und der Auflösung jedoch schnell zu einer nervraubenden Tätigkeit.

Abb. 1: Ein willkürlich geöffneter Access-Bericht…

Mit einer kleinen Schaltfläche und zwei einfachen Befehlen können Sie dem Benutzer Ihrer Datenbankanwendung das Leben sehr erleichtern. Das öffnen des Berichtes in der gewünschten Größe mit den richtigen Proportionen ist dann kein Problem mehr (s. Abb. 2).

Abb. 2: … und einer, der auf die Fenstergröße zugeschnitten ist.

Anpassen der Größe des Berichtsfensters

Die Größe eines Berichtsfensters lässt sich nach dem öffnen des Berichtes mit der Methode MoveSize des DoCmd-Befehls einstellen. Die Methode hat vier Parameter: Die horizontale und vertikale Position des oberen, linken Eckpunktes und die Höhe und die Breite des aktiven Fensters.

Der Befehl hat beispielsweise folgendes Aussehen:

DoCmd.MoveSize 10,10,1000,1000

Der Befehl wirkt sich immer auf das aktive Fenster aus.

Private Sub btnBerichtPassendAnzeigen_Click()
    DoCmd.OpenReport "Alphabetische Artikelliste", _        acPreview
    DoCmd.RunCommand acCmdFitToWindow
    DoCmd.MoveSize 20, 20, 8000, 12000

Anpassen der Auflösung des Berichtes

Die Auflösung eines Berichts können Sie ebenfalls mit einer Methode des DoCmd-Befehls verändern: Diesmal handelt es sich um die Methode RunCommand, mit der Sie alle Anweisungen ausführen können, die Sie auch in den Menüleisten von Access vorfinden.

Dabei gibt es für jeden Menübefehl eine bestimmte Konstante. Im vorliegenden Fall sind alle Konstanten interessant, mit denen man die Auflösung eines Berichtes beeinflussen kann.

Auflösung

Konstante

10%

acCmdZoom10

25%

acCmdZoom25

50%, 75%, 100%, 150%, 200%

wie oben, nur mit entsprechenden Zahlen

Passend zum Fenster

acFitToWindow

Tab. 1: Berichtsauflösungen und die entsprechenden Konstanten

In Tab. 1 finden Sie die Auflösungen in Prozent sowie die entsprechende zu verwendende Konstante.

Anwenden derBerichtseinstellungen

Eine professionelle Access-Datenbankanwendung verfügt normalerweise über geeignete Schaltflächen zur Anzeige von Daten in Berichten.

Im Folgenden verwenden Sie ein kleines Formular mit einer solchen Schaltfläche, um den Bericht in der richtigen Größe und Auflösung anzuzeigen.

Nachdem Sie eine Schaltfläche namens btnBerichtsvorschau in ein beliebiges Formular eingefügt haben, hinterlegen Sie die Prozedur aus Quellcode 1 für die Ereigniseigenschaft Beim Klicken der Schaltfläche.

Der Bericht wird nun in einem Berichtsfenster angezeigt, das ungefähr proportional zu dem im DIN-A4-Format vorliegenden Bericht ist.

Eine interessante Neuerung von Office 2000 ist die Anzeige von eigenen Einträgen in der Taskleiste für jedes geöffnete Objekt einer Anwendung. Bezogen auf Access bedeutet dies, dass Sie beispielsweise einzelne Formulare oder Berichte über einen Mausklick auf den entsprechenden Eintrag in die Taskleiste aktivieren können (s. Abb. 3).

Manch einer mag diese Eigenschaft aber auch lästig finden. Daher ist es ganz günstig, dass Microsoft eine Option zum Deaktivieren der Taskleisteneinträge vorgesehen hat:

öffnen Sie einfach den Dialog Optionen über den Menübefehl Extras/Optionen. Im Register Ansicht finden Sie unter Anzeigen die Option Fenster in Taskleiste. Entfernen Sie einfach den Haken aus dem Kontrollkästchen und Sie haben wieder mehr Platz in der Taskleiste (s. Abb. 4).

Sie haben das Ende des frei verfügbaren Textes erreicht. Möchten Sie ...

Workplace

Jahresabonnement TestzugangOder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar