** 从 VB 6到VB.NET——窗体特殊应用 **
李洪根 ** **
** 一、 ** ** 摘要 **
** ** VB .NET做为VB6的升级版本,具备了许多新的功能,它可以简便快捷地创建 .NET 应用程序(包括 XML Web services 和 ASP.NET Web 应用程序),还是一个功能强大的面向对象的编程语言(如继承、接口和重载)。新的语言功能包括自由线程处理和结构化异常处理。VB.NET 还完全集成了.NET 框架和公共语言运行库,.NET 框架和公共语言运行库共同提供语言互操作性、垃圾回收、增强的安全性和改进的版本支持。可以说是一个划时代的产品!
从 VB6到VB.NET的开发过程中,窗体应用始终是一个永恒的话题。任何一个WINDOWS的应用程序,都与窗体密切相关,在许多场合,我们都需要对窗体进行一些特殊的设置或操作,本文用VB6和VB.NET相结合,来说明窗体应用的特殊问题及处理,以及VB.NET给我们带来的新的功能!
** 二、正文 **
** 1、 ** **创建特殊形状的窗体 **
我们还是来看一下在 VB6中的实现,VB6中实现(借助API函数)
做一个古怪的窗口必须要用的也是此程序中最重要的一个函数就是 SetWindowRgn
它的功能就是对指定的窗口进行重画,把这个窗口你选择的部分留下其余的部分抹掉
参数: hWnd:你所要重画的窗口的句柄,比如你想重画form1则应该让此参数为form1.hWnd
hRgn:你要保留的区域的句柄,这个句柄是关键,你需要通过别的渠道来获得
在这里的区域是由 Combinergn合成的新区域
bRedram:是否要马上重画,一般设为true
函数 CombineRgn 将两个区域组合为一个新区域
函数 Createrectrgn为创建一个由点X1,Y1和X2,Y2描述的矩形区域
函数 CreateEllipticRgn 为创建一个 X1,Y1和X2,Y2的椭圆区域
用 DeleteObject 这个函数可删除 GDI对象,比如画笔、刷子、字体、位图、区域以及调色板等等。对象使用的所有系统资源都会被释放
以下是 VB6的代码:
Private Declare Function CreateEllipticRgn Lib "gdi32" ( ByVal X1 As Long , ByVal Y1 As Long , ByVal X2 As Long , ByVal Y2 As Long ) As Long
Private Declare Function CreateRectRgn Lib "gdi32" ( ByVal X1 As Long , ByVal Y1 As Long , ByVal X2 As Long , ByVal Y2 As Long ) As Long
Private Declare Function CombineRgn Lib "gdi32" ( ByVal hDestRgn As Long , ByVal hSrcRgn1 As Long , ByVal hSrcRgn2 As Long , ByVal nCombineMode As Long ) As Long
Private Declare Function SetWindowRgn Lib "user32" ( ByVal hWnd As Long , ByVal hRgn As Long , ByVal bRedraw As Boolean ) As Long
Private Declare Function DeleteObject Lib "gdi32" ( ByVal hObject As Long ) As Long
Private Const RGN_DIFF = 4
Private Sub Form_Load()
Dim rgn As Long
Dim rgnRect As Long
Dim rgnDest As Long
rgn = CreateEllipticRgn(0, 0, Me .Width / Screen.TwipsPerPixelX, Me .Height / Screen.TwipsPerPixelY)
rgnRect = CreateRectRgn(( Me .Width / Screen.TwipsPerPixelX - 20) / 2, ( Me .Height / Screen.TwipsPerPixelY - 20) / 2, ( Me .Width / Screen.TwipsPerPixelX + 20) / 2, ( Me .Height / Screen.TwipsPerPixelY + 20) / 2)
rgnDest = CreateRectRgn(0, 0, 1, 1)
CombineRgn rgnDest, rgn, rgnRect, RGN_DIFF
SetWindowRgn Me .hWnd, rgnDest, True
Call DeleteObject(rgnRect)
Call DeleteObject(rgnDest)
End Sub
Private Sub Command1_Click()
End
End Sub
在 VB.NET中,我们可以使用.NET 框架类库 System.Drawing.Drawing2D的 _ GraphicsPath _ 类(应用程序使用路径来绘制形状的轮廓、填充形状内部和创建剪辑区域),来绘制图形,
然后通过窗体的 Me .Region来设置窗口的可见区域。
以下是 VB.NET的代码:
'声明一个布尔型变量,判断窗体是否正常区域
Dim IsNormalRegion As Boolean = True
Private Sub Button2_Click( ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click
If (IsNormalRegion) Then
'构造一个GraphicsPath对象实例
Dim Graphics As New System.Drawing.Drawing2D.GraphicsPath()
Dim intHeight As Integer = Me .Size.Height
Dim intWidth As Integer = Me .Size.Width
'定义内矩形的左上角坐标
Dim RectTop As Integer = 100
'在窗体上绘制一个大椭圆,左上角的坐标取为(0,0)
Graphics.AddEllipse(0, 0, intWidth, intHeight)
'再绘制一个小矩形
Dim AddRect As New Rectangle(RectTop, RectTop, intHeight - (RectTop * 2), intHeight - (RectTop * 2))
Graphics.AddRectangle(AddRect)
'设置窗口的可见区域
Me .Region = New Region(Graphics)
Else
Me .Region = Nothing
End If
IsNormalRegion = Not IsNormalRegion
End Sub
程序运行的结果如下:
** 2、 ** **使窗体在其他所有窗体之上 (Allway On Top) **
VB6中实现(借助API函数 SetWindowPos )
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变元是窗口的句柄;x,y是窗口的左上角的坐标;cx、cy是窗口宽度和高度;hWndInsertAfter变元是窗口清单中hWnd窗口前面的窗口句柄,有四个可选值:
序号 可 选 值 作 用
1 HWND_BOTTOM 把窗口放在窗口清单的底部
2 HWND_TOP 把窗口放在窗口清单的字符顺序的顶部
3 HWND_TOPMOST 把窗口放在窗口清单的顶部
4 HWND_NOTOPMOST 把窗口放在窗口清单的顶部,最上层窗口之下
---- WFlags变元为整型值,有八个可选值:
序号 可 选 值 作用
1 SWP_DRAWFRAME 在窗口周围画一个方框
2 SWP_HIDEWINDOW 隐藏窗口
3 SWP_NOACTIVATE 不激活窗口
4 SWP_NOMOVE 保持窗口当前位置
5 SWP_NOREDRAW 窗口不自动重画
6 SWP_NOSIZE 保持窗口当前尺寸
7 SWP_NOZORDER 保持窗口在窗口清单中的当前位置
8 SWP_SHOWWINDOW 显示窗口
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 SWP_NOMOVE = 2
Private Const SWP_NOSIZE = 1
Private Const FLAGS = SWP_NOMOVE Or SWP_NOSIZE
Private Const HWND_TOPMOST = -1
Private Const HWND_NOTOPMOST = -2
Private Sub Command1_Click()
'把窗体放在最前面:
res% = SetWindowPos(Form1.hwnd, HWND_TOPMOST, 0, 0, 0, 0, FLAGS)
End Sub
Private Sub Command2_Click()
'使窗体恢复普通模式:
res% = SetWindowPos(Form1.hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, FLAGS)
End Sub
在 VB.NET中,太简单了!系统为窗体提供了 TopMost属性, 我们将 TopMost属性设置为True,就实现了Allways On Top 的功能,要取消此功能,设置为False即可。
Private Sub Form1_Load( ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase .Load
Me .TopMost = True
End Sub
** 3、 ** **窗体透明度渐变效果 **
我们还是来看一下在 VB6中的实现,VB6中实现(借助API函数SetLayeredWindowAttributes)
使用这个函数,可以轻松的控制窗体的透明度。按照微软的要求,透明窗体在创建时应使用 WS_EX_LAYERED参数(用CreateWindowEx),或者在创建后设置该参数(用SetWindowLong),我选用后者。
SetLayeredWindowAttributes 函数 , 其中 hwnd是透明窗体的句柄,crKey为颜色值,bAlpha是透明度,取值范围是[0,255],dwFlags是透明方式,可以取两个值:当取值为LWA_ALPHA时,crKey参数无效,bAlpha参数有效;当取值为LWA_COLORKEY时,bAlpha参数有效而窗体中的所有颜色为crKey的地方将变为透明。 ** **
Const LWA_COLORKEY = &H1
Const LWA_ALPHA = &H2
Const GWL_EXSTYLE = (-20)
Const WS_EX_LAYERED = &H80000
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" ( ByVal hWnd As Long , ByVal nIndex As Long ) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" ( ByVal hWnd As Long , ByVal nIndex As Long , ByVal dwNewLong As Long ) As Long
Private Declare Function SetLayeredWindowAttributes Lib "user32" ( ByVal hWnd As Long , ByVal crKey As Long , ByVal bAlpha As Byte , ByVal dwFlags As Long ) As Long
Private Sub Form_Load()
Dim Ret As Long
'Set the window style to 'Layered'
Ret = GetWindowLong( Me .hWnd, GWL_EXSTYLE)
Ret = Ret Or WS_EX_LAYERED
SetWindowLong Me.hWnd, GWL_EXSTYLE, Ret
'Set the opacity of the layered window to 128
'我们可以设置这个数值来控制透明程度
SetLayeredWindowAttributes Me .hWnd, 0, 128, LWA_ALPHA
End Sub
在 VB.NET中,太简单了!系统为窗体提供了 Opacity属性,来确定 窗体的不透明和透明程度, 0%为透明,100%为不透明。
以下程序通过循环显示窗体的透明度过程,为了让大家看清楚其变化,在循环过程中使用了 System.Threading.Thread.Sleep来停顿。
Private Sub button1_Click( ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles button1.Click
'窗体的透明度渐变过程
button1.Enabled = False
Dim I As Double
For I = 0.01 To 1 Step 0.01
Me .Opacity = I
System.Windows.Forms.Application.DoEvents()
System.Threading.Thread.Sleep(5)
Next
Me .Opacity = 1
button1.Enabled = True
End Sub
** 4、 ** **使窗体右上角的 X无效,禁止Alt+F4关闭窗体 **
在特殊窗体的应用中,我们有时需要把窗体右上角标题栏上的关闭按钮屏幕,当用户点击其它地方(比如说一个 Button)退出,那我们怎么做呢?。
我们还是来看一下在 VB6中的实现,VB6中实现(借助API函数)
Private Declare Function GetSystemMenu Lib "user32" ( ByVal hwnd As Long , ByVal bRevert As Long ) As Long
Private Declare Function GetMenuItemCount Lib "user32" ( ByVal hMenu As Long ) As Long
Private Declare Function DrawMenuBar Lib "user32" ( ByVal hwnd As Long ) As Long
Private Declare Function RemoveMenu Lib "user32" ( ByVal hMenu As Long , ByVal nPosition As Long , ByVal wFlags As Long ) As Long
Const MF_BYPOSITION = &H400&
Const MF_REMOVE = &H1000&
Private Sub Form_Load()
Dim hSysMenu As Long , nCnt As Long
' Get handle to our form's system me