1. 程式人生 > >讓視窗始終在最前面顯示 VB

讓視窗始終在最前面顯示 VB

最近想做一個桌面的類似檯曆的VB程式,其中最主要的就是顯示效果的問題,一般我們可能要求有一個異樣的外觀,另外我們還可能要讓它總是顯示在最前面,所以我就將我做的讓VB視窗總是在最前面顯示的總結寫出來大家參考一下,其實想要讓視窗始終在最前面顯示,只需要一個API函式就可以了,該函式的原型是:

Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long

函式的具體用法如下:

VB宣告
Declare Function SetWindowPos Lib "user32" Alias "SetWindowPos" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
說明
這個函式能為視窗指定一個新位置和狀態。它也可改變視窗在內部視窗列表中的位置。該函式與DeferWindowPos函式相似,只是它的作用是立即表現出來的(在vb裡使用:針對vb窗體,如它們 在win32下遮蔽或最小化,則需重設最頂部狀態。如有必要,請用一個子類處理模組來重設最頂部狀態
返回值
Long,非零表示成功,零表示失敗。會設定GetLastError
引數表
引數 型別及說明
hwnd Long,欲定位的視窗
hWndInsertAfter Long,視窗控制代碼。在視窗列表中,視窗hwnd會置於這個視窗控制代碼的後面。也可能選用下述值之一:
HWND_BOTTOM 將視窗置於視窗列表底部
HWND_TOP 將視窗置於Z序列的頂部;Z序列代表在分級結構中,視窗針對一個給定級別的視窗顯示的順序
HWND_TOPMOST 將視窗置於列表頂部,並位於任何最頂部視窗的前面
HWND_NOTOPMOST 將視窗置於列表頂部,並位於任何最頂部視窗的後面
x Long,視窗新的x座標。如hwnd是一個子視窗,則x用父視窗的客戶區座標表示
y Long,視窗新的y座標。如hwnd是一個子視窗,則y用父視窗的客戶區座標表示
cx Long,指定新的視窗寬度
cy Long,指定新的視窗高度
wFlags Long,包含了旗標的一個整數
SWP_DRAWFRAME 圍繞視窗畫一個框
SWP_HIDEWINDOW 隱藏視窗
SWP_NOACTIVATE 不啟用視窗
SWP_NOMOVE 保持當前位置(x和y設定將被忽略)
SWP_NOREDRAW 視窗不自動重畫
SWP_NOSIZE 保持當前大小(cx和cy會被忽略)
SWP_NOZORDER 保持視窗在列表的當前位置(hWndInsertAfter將被忽略)
SWP_SHOWWINDOW 顯示視窗
SWP_FRAMECHANGED 強迫一條WM_NCCALCSIZE訊息進入視窗,即使視窗的大小沒有改變
註解

視窗成為最頂級視窗後,它下屬的所有視窗也會進入最頂級。一旦將其設為非最頂級,則它的所有下屬和物主視窗也會轉為非最頂級。Z序列用垂直於螢幕的一根假想Z軸量化這種從頂部到底部排列的視窗順序

在VB中宣告此函式之後,我們就可以用以下呼叫將視窗放置在最前面了

SetWindowPos Me.hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE

其中SWP_NOMOVE是常量H1,SWP_NOSIZE是常量H2

一個簡單的例子:

Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal

hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As

Long, ByVal wFlags As Long) As Long
       Private Const HWND_TOPMOST& = -1 ' 將視窗置於列表頂部,並位於任何最頂部視窗的前面
       Private Const SWP_NOSIZE& = &H1 ' 保持視窗大小
       Private Const SWP_NOMOVE& = &H2 ' 保持視窗位置
       Private Sub Form_Load()
        SetWindowPos Me.hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE '將視窗設為總在最前
        End Sub

但是我們在用的時候可能發現這樣不能保證視窗總是在最前面的,這樣我們可以採用一些辦法,在我做的桌面檯曆中我就是使用定時器實現的,即每當我我時間發生改變的時候我都會讓該視窗重新置到最前端。

使用API函式之前必須先在程式中宣告如下:

Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
  
  其中各引數的意義如下:

引數 意義
hwnd Long 欲定位的視窗  
hWndInsertAfter Long 視窗控制代碼。在視窗列表中,視窗hwnd會置於這個視窗控制代碼的後面
x,y Long 視窗新的x,y座標
cx,cy Long 指定新的視窗寬度和高度
wFlags Long 包含了旗標的一個整數,是下列之一  
返回值 Long 非零表示成功,零表示失敗  

  下面是部分wFlags引數和它們的意義:

引數   意義和使用方法
SWP_DRAWFRAME 圍繞視窗畫一個框
SWP_HIDEWINDOW 隱藏視窗
SWP_NOACTIVATE 不啟用視窗
SWP_NOMOVE 保持當前位置 (x和y設定將被忽略) &H2
SWP_NOREDRAW 視窗不自動重畫
SWP_NOSIZE 保持當前大小 (cx和cy會被忽略) &H1
SWP_NOZORDER 保持視窗在列表的當前位置 (hWndInsertAfter將被忽略)
SWP_SHOWWINDOW 顯示視窗 &H40
SWP_FRAMECHANGED   強迫一條WM_NCCALCSIZE訊息進入視窗,即使視窗的大小沒有改變

  函式的使用很簡單,我們只須在Form_Load中加入如下語句即可:

retValue = SetWindowPos(Me.hwnd, HWND_TOPMOST, Me.CurrentX, Me.CurrentY, 300, 300, SWP_SHOWWINDOW)

  這樣窗體就能保持在所有窗體的前面了。

  為了學習方便,下面提供了原始碼:

註釋:-------------------------------------------
註釋: 讓一個窗體總是處於最前的例子
註釋:-------------------------------------------
註釋:程式說明:
註釋:本例應用SetWindowPos函式,設定窗體的顯示屬性
註釋:來實現讓一個窗體總是處於其他窗體的前面而不會
註釋:被其他窗體所遮住。
註釋:-------------------------------------------
Option Explicit

註釋:【VB宣告】
註釋: Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long

註釋:【說明】
註釋: 這個函式能為視窗指定一個新位置和狀態。它也可改變視窗在內部視窗列表中的位置。該函式與DeferWindowPos函式相似,只是它的作用是立即表現出來的(在vb裡使用:針對vb窗體,如它們在win32下遮蔽或最小化,則需重設最頂部狀態。如有必要,請用一個子類處理模組來重設最頂部狀態

註釋:【返回值】
註釋: Long,非零表示成功,零表示失敗。會設定GetLastError

註釋:【備註】
註釋: 視窗成為最頂級視窗後,它下屬的所有視窗也會進入最頂級。一旦將其設為非最頂級,則它的所有下屬和物主視窗也會轉為非最頂級。Z序列用垂直於螢幕的一根假想Z軸量化這種從頂部到底部排列的視窗順序

註釋:【引數表】
註釋: hwnd ----------- Long,欲定位的視窗

註釋: hWndInsertAfter - Long,視窗控制代碼。在視窗列表中,視窗hwnd會置於這個視窗控制代碼的後面。也可能選用下述值之一:
註釋: HWND_BOTTOM 將視窗置於視窗列表底部
註釋: HWND_TOP 將視窗置於Z序列的頂部;Z序列代表在分級結構中,視窗針對一個給定級別的視窗顯示的順序
註釋: HWND_TOPMOST 將視窗置於列表頂部,並位於任何最頂部視窗的前面 -1
註釋: HWND_NOTOPMOST 將視窗置於列表頂部,並位於任何最頂部視窗的後面 -2

註釋: x -------------- Long,視窗新的x座標。如hwnd是一個子視窗,則x用父視窗的客戶區座標表示

註釋: y -------------- Long,視窗新的y座標。如hwnd是一個子視窗,則y用父視窗的客戶區座標表示

註釋: cx ------------- Long,指定新的視窗寬度

註釋: cy ------------- Long,指定新的視窗高度

註釋: wFlags --------- Long,包含了旗標的一個整數,是下列之一:
註釋: SWP_DRAWFRAME 圍繞視窗畫一個框
註釋: SWP_HIDEWINDOW 隱藏視窗
註釋: SWP_NOACTIVATE 不啟用視窗 &H10
註釋: SWP_NOMOVE 保持當前位置 (x和y設定將被忽略) &H2
註釋: SWP_NOREDRAW 視窗不自動重畫
註釋: SWP_NOSIZE 保持當前大小 (cx和cy會被忽略) &H1
註釋: SWP_NOZORDER 保持視窗在列表的當前位置 (hWndInsertAfter將被忽略)
註釋: SWP_SHOWWINDOW 顯示視窗 &H40
註釋: SWP_FRAMECHANGED 強迫一條WM_NCCALCSIZE訊息進入視窗,即使視窗的大小沒有改變
Private Declare Function SetWindowPos Lib "user32" ( _
 ByVal hwnd As Long, _
 ByVal hWndInsertAfter As Long, _
 ByVal x As Long, ByVal y As Long, _
 ByVal cx As Long, ByVal cy As Long, _
 ByVal wFlags As Long _
) As Long
 Const HWND_TOPMOST = -1
 Const SWP_SHOWWINDOW = &H40
 Private Sub Form_load()
  Dim retValue As Long
  註釋:將窗體設定為處於所有視窗的頂層,注意在 VB 中執行時,
  ’可能不行,但編譯成EXE後就可以了
  retValue = SetWindowPos(Me.hwnd, HWND_TOPMOST, Me.CurrentX,
        Me.CurrentY, 300, 300, SWP_SHOWWINDOW)
End Sub
'呼叫一個API函式SetWindowPos可實現此功能?

'首先新增一個公用模組,將下面的程式碼放到模組的宣告段中。

Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long

Public Const HWND_TOPMOST = -1
Public Const SWP_NOMOVE = &H2
Public Const SWP_NOSIZE = &H1
Public Const SWP_NOZORDER = &H8

'將下面的子程式放到模組中

Public Sub SetFormTopmost(TheForm As Form)

SetWindowPos TheForm.hwnd, HWND_TOPMOST, 0, 0, 0, 0, _
SWP_NOZORDER + SWP_NOMOVE + SWP_NOSIZE




End Sub

'最後,通過呼叫該子程式設定你想要放置的窗體。例如,你想將窗體frmMyForm放在最前面,程式碼如下:



Private Sub Form_Load()
SetFormTopmost frmMyForm
End Sub