zyl910

优化技巧、硬件体系、图像处理、图形学、游戏编程、国际化与文本信息处理。

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

关键在于对WM_ENTERIDLE消息的处理
在菜单状态下移动鼠标会产生WM_ENTERIDLE消息
这时用TempPoint、WindowFromPoint可以取得当前鼠标所指窗体的句柄
再用GetClassName取得类名,与"#32768"(菜单窗体的类名)进行比较
再等待1秒钟,用keybd_event发送VK_ESCAPE取消菜单状态

但是还是有一个的缺点:无法在鼠标不移动的时候自动隐藏
这时需要Timer控件的帮忙

 


 

将下列文件粘贴到记事本,并保存为相应文件


AutoHidePopupMenu.vbp
====================================================================
Type=Exe
Form=Form1.frm
Reference=*/G{00020430-0000-0000-C000-000000000046}#2.0#0#../../../../../../WINDOWS/SYSTEM/stdole2.tlb#OLE Automation
Module=Module1; Module1.bas
Startup="Form1"
ExeName32="AutoHidePopupMenu.exe"
Command32=""
Name="AutoHidePopupMenu"
HelpContextID="0"
CompatibleMode="0"
MajorVer=1
MinorVer=0
RevisionVer=0
AutoIncrementVer=0
ServerSupportFiles=0
VersionCompanyName="zyl910"
CompilationType=0
OptimizationType=0
FavorPentiumPro(tm)=0
CodeViewDebugInfo=0
NoAliasing=0
BoundsCheck=0
OverflowCheck=0
FlPointCheck=0
FDIVCheck=0
UnroundedFP=0
StartMode=0
Unattended=0
Retained=0
ThreadPerObject=0
MaxNumberOfThreads=1

 


Form1.frm
====================================================================
VERSION 5.00
Begin VB.Form Form1
   BorderStyle     =   1  'Fixed Single
   Caption         =   "AutoHidePopupMenu"
   ClientHeight    =   3225
   ClientLeft      =   45
   ClientTop       =   330
   ClientWidth     =   4710
   LinkTopic       =   "Form1"
   MaxButton       =   0   'False
   ScaleHeight     =   3225
   ScaleWidth      =   4710
   StartUpPosition =   3  '窗口缺省
   Begin VB.Timer Timer1
      Interval        =   1000
      Left            =   2580
      Top             =   360
   End
   Begin VB.Label LblNow
      AutoSize        =   -1  'True
      Caption         =   "LblNow"
      Height          =   180
      Left            =   1410
      TabIndex        =   1
      Top             =   210
      Width           =   540
   End
   Begin VB.Label LblClick
      AutoSize        =   -1  'True
      Caption         =   "点击鼠标右键"
      BeginProperty Font
         Name            =   "宋体"
         Size            =   26.25
         Charset         =   134
         Weight          =   400
         Underline       =   0   'False
         Italic          =   0   'False
         Strikethrough   =   0   'False
      EndProperty
      Height          =   525
      Left            =   720
      TabIndex        =   0
      Top             =   1200
      Width           =   3150
   End
   Begin VB.Menu mnuPopup
      Caption         =   "Popup"
      Visible         =   0   'False
      Begin VB.Menu mnuItem1
         Caption         =   "Item&1"
      End
      Begin VB.Menu mnuItem2
         Caption         =   "Item&2"
      End
      Begin VB.Menu mnuItem3
         Caption         =   "Item&3"
      End
   End
End
Attribute VB_Name = "Form1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit

Private Sub Form_Load()
    'MsgBox ClassName(Me.hWnd)
   
    LblNow.Caption = Now
   
    Hook Me.hWnd
   
End Sub

Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    LblClick_MouseUp Button, Shift, X, Y
   
End Sub

Private Sub Form_Unload(Cancel As Integer)
    UnHook Me.hWnd
   
End Sub

Private Sub LblClick_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If Button And vbKeyRButton Then
        'ShowMsg = True
        PopupMenu mnuPopup
        'ShowMsg = False
       
    End If
   
End Sub

Private Sub Timer1_Timer()
    LblNow.Caption = Now
   
    '这样即使不移动鼠标,菜单也会自动隐藏
    If ChkTime Then
        ChkExit
    End If
   
End Sub

 


Module1.bas
====================================================================
Attribute VB_Name = "Module1"
Option Explicit

'## API ########################################
'== 硬件与系统函数 =============================
Public Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Public Declare Function GetTickCount Lib "kernel32" () As Long

Public Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
Public Const VK_ESCAPE = &H1B
Public Const KEYEVENTF_KEYUP = &H2

Type POINTAPI
    X As Long
    Y As Long
End Type

'== 控件与消息函数 =============================
'CallWindowProc  把消息信息传递给指定的窗体过程
'GetClassName    为指定的窗口取得类名
'SetWindowLong   在窗体结构中为指定的窗体设置信息。返回值:Long,指定数据的前一个值。
'WindowFromPoint 返回包含了指定点的窗口的句柄。
Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Declare Function GetClassNameA Lib "user32" (ByVal hWnd As Long, lpClassName As Any, ByVal nMaxCount As Long) As Long
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public Declare Function WindowFromPoint Lib "user32" (ByVal xPoint As Long, ByVal yPoint As Long) As Long

'-- SetWindowLong ------------------------------
Public Const GWL_WNDPROC = -4

'===============================================
Public Const WM_ENTERIDLE = &H121

'===============================================
Public MeOldWndProc As Long '旧的窗体消息处理程序地址

Public ShowMsg As Boolean

Public OldIn As Boolean
Public OldTime As Long
Public ChkTime As Boolean

Public Function ClassName(ByVal hWnd As Long) As String
    Dim StrData(0 To &H100) As Byte
    Dim Rc As Long
   
    Rc = GetClassNameA(hWnd, StrData(0), &H100)
    If Rc > 0 Then
        ClassName = StrConv(LeftB(StrData, Rc), vbUnicode)
    Else
        ClassName = vbNullString
    End If
   
End Function

Public Sub Hook(ByVal hWnd As Long)
    MeOldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf WindowProc)
   
End Sub

Public Sub UnHook(ByVal hWnd As Long)
    Call SetWindowLong(hWnd, GWL_WNDPROC, MeOldWndProc)
   
End Sub

'消息处理
Public Function WindowProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Select Case uMsg
    Case WM_ENTERIDLE
        'Debug.Print "WM_ENTERIDLE"
       
        ChkExit
       
    Case Else
        'If ShowMsg Then Debug.Print uMsg
       
        '下级传递消息
        WindowProc = CallWindowProc(MeOldWndProc, hWnd, uMsg, wParam, lParam)
       
    End Select
   
End Function

Public Sub ChkExit()
    Dim TempPoint As POINTAPI
    Dim TemphWnd As Long
    Dim TempBool As Boolean
   
    GetCursorPos TempPoint
    TemphWnd = WindowFromPoint(TempPoint.X, TempPoint.Y)
    If TemphWnd Then
        TempBool = (ClassName(TemphWnd) = "#32768")
    Else
        TempBool = False
    End If
    'Debug.Print TempBool
   
    If TempBool <> OldIn Then
        If TempBool Then
            OldTime = 0
            ChkTime = False
        Else
            OldTime = GetTickCount
            ChkTime = True
        End If
        OldIn = TempBool
       
    End If
   
    If ChkTime Then
        If GetTickCount - OldTime > 1000 Then '大于1秒就退出
            'Debug.Print "Exit"
            keybd_event VK_ESCAPE, 0, 0, 0
            keybd_event VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0
           
            ChkTime = False
           
        End If
       
    End If
   
End Sub

posted on 2002-12-06 09:39  zyl910  阅读(424)  评论(0编辑  收藏  举报