ABOUT Visual Basic Programmieren Programmierung Download Downloads Tips & Tricks Tipps & Tricks Know-How Praxis VB VBA Visual Basic for Applications VBS VBScript Scripting Windows ActiveX COM OLE API ComputerPC Microsoft Office Microsoft Office 97 Office 2000 Access Word Winword Excel Outlook Addins ASP Active Server Pages COMAddIns ActiveX-Controls OCX UserControl UserDocument Komponenten DLL EXE
Diese Seite wurde zuletzt aktualisiert am 05.07.2002

Diese Seite wurde zuletzt aktualisiert am 05.07.2002
Aktuell im ABOUT Visual Basic-MagazinGrundlagenwissen und TechnologienKnow How, Tipps und Tricks rund um Visual BasicAddIns für die Visual Basic-IDE und die VBA-IDEVBA-Programmierung in MS-Office und anderen AnwendungenScripting-Praxis für den Windows Scripting Host und das Scripting-ControlTools, Komponenten und Dienstleistungen des MarktesRessourcen für Programmierer (Bücher, Job-Börse)Dies&Das...

Themen und Stichwörter im ABOUT Visual Basic-Magazin
Code, Beispiele, Komponenten, Tools im Überblick, Shareware, Freeware
Ihre Service-Seite, Termine, Job-Börse
Melden Sie sich an, um in den vollen Genuss des ABOUT Visual Basic-Magazins zu kommen!
Informationen zur AVB-Web-Site, Kontakt und Impressum

Zurück...

Tasten im MDI-Form

Zurück...

(-hg) mailto:hg_mdikeys@aboutvb.de

Im Gegensatz zu einem gewöhnlichen Form bietet Ihnen ein MDI-Form keine Tasten-Ereignisse. Wenn kein MDI-Kind-Form geöffnet ist, kann Ihre Anwendung somit nicht auf Tastatureingaben reagieren. Zwar könnten Sie irgendein Steuerelement auf dem MDI-Form unterbringen, das den Fokus innehaben kann und so ersatzweise Tastenanschläge annehmen könnte. Aber vielleicht soll Ihr MDI-Form eben gerade kein weiteres, sichtbares Steuerelement enthalten.

Die naheliegendste Lösung wäre ein sichtbares, aber durchsichtiges Steuerelement, das den Fokus auf sich zieht, wenn das MDI-Form das aktive Fenster ist und kein Kind-Form angezeigt wird. Immerhin können Sie etwa bei einem UserControl die Eigenschaft BackStyle auf "0 - Transparent" setzen. Doch sobald Sie es auf einem MDI-Form platzieren (und zwangsläufig müssen Sie es am Rand des Arbeitsbereichs andocken), erscheint zur Laufzeit eine graue Fläche - egal, wie schmal Sie das Steuerelement auch machen. Es hilft auch nichts, auf die Durchsichtigkeit zu verzichten und statt dem Steuerelement dessen die Farbe des Arbeitsbereichs zu geben - die trennende Kante des 3D-Rahmens bleibt weiterhin unschön verschoben. Wegen des Andockzwangs für ein sichtbares Steuerelement können Sie dieses jedoch auch nicht irgendwo innerhalb des Arbeitsbereichs unterbringen.

Der Weg führt über ein unsichtbares und durchsichtiges UserControl (Eigenschaft InvisibleAtRuntime auf True gesetzt). Auch wenn das Steuerelement dann über keine Visible-Eigenschaft verfügt und auch die SetFocus-Methode nicht mehr zulässig ist, können Sie zur Laufzeit die VB-eigene Verwaltung über API-Funktionen austricksen. Ein Aufruf der API-Funktion ShowWindow lässt es "sichtbar" werden. Es bleibt trotzdem durchsichtig, ist aber nun dazu bereit, den Fokus erhalten zu können. Dann verschieben Sie es mittels der SetParent-Funktion aus dem Arbeitsbereich des MDI-Forms (der ein eigenes Fenster ist) in das Fenster des MDI-Forms und entziehen es so der VB- und MDI-Verwaltung. Nun geben Sie ihm noch mit der API-Funktion SetFocus (als Alias "SetFocusAPI" deklariert, um dem Konflikt mit der VB-Methode SetFocus zu entgehen) den Fokus. Und schon kommen die Tastatureingaben in den Key-Ereignissen des UserControls an, die sie nun selbst als Events nach außen an das MDI-Form weiterreichen können. Und wenn nun ein Kind-Form geöffnet wird, das die Tastatureingaben selbst annehmen soll, verliert das UserControl automatisch den Fokus - Sie brauchen sich gar nicht weiter darum zu kümmern.

Public Event KeyDown(KeyCode As Integer, Shift As Integer)
Public Event KeyPress(KeyAscii As Integer)
Public Event KeyUp(KeyCode As Integer, Shift As Integer)

Private Declare Function GetFocus Lib "user32" () As Long
Private Declare Function GetForegroundWindow Lib "user32" () _
 As Long
Private Declare Function SetFocusAPI Lib "user32" _
 Alias "SetFocus" (ByVal hwnd As Long) As Long
Private Declare Function SetParent Lib "user32" _
 (ByVal hWndChild As Long, ByVal hWndNewParent As Long) _
 As Long
Private Declare Function ShowWindow Lib "user32" _
 (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long

Public Sub Show()
  Const SW_NORMAL = 1
  
  ShowWindow .hwnd, SW_NORMAL
  SetParent .hwnd, .Parent.hwnd
  SetFocusAPI .hwnd
End Sub

Private Sub UserControl_KeyDown(KeyCode As Integer, _
 Shift As Integer)

  RaiseEvent KeyDown(KeyCode, Shift)
End Sub

Private Sub UserControl_KeyPress(KeyAscii As Integer)
  RaiseEvent KeyPress(KeyAscii)
End Sub

Private Sub UserControl_KeyUp(KeyCode As Integer, _
 Shift As Integer)

  RaiseEvent KeyUp(KeyCode, Shift)
End Sub

Soweit funktioniert das schon ganz gut. Nun ist noch eine nächste Aufgabe zu lösen. Wenn nämlich ein anderes Anwendungsfenster aktiviert wird, verliert nicht nur das MDI-Form seinen Aktivitätsstatus, sondern auch das UserControl verliert den Fokus. Wird das MDI-Form wieder aktiv, bekommt das UserControl jedoch nicht automatisch wieder den Fokus. Und da es in VB (außer per relativ aufwändigem Subclassing) keine Möglichkeit gibt, den Wechsel von einer anderen Anwendung zur eigenen Anwendung zu erkennen, müssen Sie auf andere Weise dafür sorgen, dass das UserControl wieder den Fokus erhält, so lange kein Kind-Form geöffnet ist.

Am einfachsten geht dies über einen auf dem UserControl platzierten Timer, der in mittels der API-Funktion GetForegroundWindow kurzen Abständen (Interval = 50) prüft, ob das MDI-Form aktiv ist. Ist es der Fall, wird über die API-Funktion GetFocus geprüft, ob das UserControl bereits den Fokus hat. Ist dies nicht der Fall wird das UserControl über den oben schon dargestellten Mechanismus (re)aktiviert, der in das Timer-Ereignis verschoben wird (die Show-Methode entfällt statt dessen).

Private Sub tmr_Timer()
  Const SW_NORMAL = 1
  
  With UserControl
    If GetForegroundWindow() = UserControl.Parent.hwnd Then
      If GetFocus <> .hwnd Then
        ShowWindow .hwnd, SW_NORMAL
        SetParent .hwnd, .Parent.hwnd
        SetFocusAPI .hwnd
      End If
    End If
  End With
End Sub

Aber woher weiß der Timer nun, ob Kind-Forms geöffnet sind oder nicht? Eine kleine Modifikation des Codes im Timer-Ereignis löst auch diese letzte Aufgabe: So wie über die Parent-Eigenschaft des UserControls das Handle des MDI-Forms ermittelt werden kann, können Sie auch die Eigenschaft ActiveForm des MDI-Forms prüfen. Ist diese Nothing, ist kein Kind-Form geöffnet.

Private Sub tmr_Timer()
  Const SW_NORMAL = 1
  
  With UserControl
    If GetForegroundWindow() =.Parent.hwnd Then
      If GetFocus <> .hwnd Then
        If .Parent.ActiveForm Is Nothing Then
          ShowWindow .hwnd, SW_NORMAL
          SetParent .hwnd, .Parent.hwnd
          SetFocusAPI .hwnd
        End If
      End If
    End If
  End With
End Sub

Der Rest ist nur noch ein wenig Kosmetik. Damit Sie das UserControl zur Designzeit bequem handhaben können, ist es dort noch nicht durchsichtig und zeigt in einem Label die Beschriftung "MDIKeys". Und auch der Timer darf zur Designzeit nicht aktiv sein.

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
  If Ambient.UserMode Then
    UserControl.BackStyle = 0
    lbl.Visible = False
    tmr.Enabled = True
  End If
End Sub

Private Sub UserControl_Resize()
  If Not Ambient.UserMode Then
    With lbl
      UserControl.Size .Width + 2 * .Left, .Height + 2 * .Top
    End With
  End If
End Sub

Beispiel-Projekt und UserControl ucMDIKeys (mdikeys.zip - ca. 4,9 KB)



Komponenten-Übersicht

Schnellsuche




Zum Seitenanfang

Copyright © 1999 - 2023 Harald M. Genauck, ip-pro gmbh  /  Impressum

Zum Seitenanfang

Zurück...

Zurück...