📄 85.txt
字号:
由於 Picture 属性中的图片是常驻的, 因此当我们将表单的 Image 属性(等於表单上的图像)设定给它,便可以将 AutoRedraw 属性设定为 False, 以避免不必要的重绘动作。
以上程式使用了 AutoRedraw、Image、及 Picture 属性, 这些属性除了适用於表单物件之外,也适用於 PictureBox 物件, 而实际上, 笔者所撰写的 CopyScr.vbp 并不是把萤幕复制到表单上,而是复制到 PictureBox 物件之中。
浏览图片的操作介面
--------------------------------------------------------------------------------
除了将萤幕图像复制到 PictureBox 之外, 另一个问题则是萤幕总是比表单的显示区域来得大,以致被复制到 PictureBox 的图像会超出表单的显示区域, 为了让使用者可以看到萤幕的全貌,我们必须在表单上布置卷动轴, 并提供浏览的操作介面。
有关大图片浏览程式, 常见的作法是把显示图片的 PictureBox 布置在另一个 PictureBox 里面, 然後再利用卷动轴调整内部 PictureBox 相对於外部 PictureBox 的位置, 而达到浏览图片的目的, 如图-3。
图-3 图片浏览程式所需之控制元件及其布置
至於相关程式则请参考 CopyScr.frm 的 SetPicture 副程式、VScroll1_Change、及 HScroll1_Change 事件程序。
图片的存档
--------------------------------------------------------------------------------
最後就是图片的存档了, VB 提供的存档叙述是 SavePicture, 呼叫格式如下:
SavePicture 图片, 档案名称
其中「图片」参数可以是物件的 Picture 属性或利用 LoadPicture 所载入的 Picture 物件, 以本程式为例, 则指定成 PictureBox 的 Picture 属性。
--------------------------------------------------------------------------------
萤幕保护程式的制作
--------------------------------------------------------------------------------
笔者所撰写的萤幕保护程式, 是将萤幕切割成 M×N 个方块, 然後在萤幕保护程式启动时,随机变换任意两个方块, 此时所需执行的动作是:
(1) 将 (M1, N1) 座标的方块复制到一暂存区。
(2) 将 (M2, N2) 座标的方块复制到 (M1, N1) 座标。
(3) 将暂存区的方块复制到 (M2, N2) 座标。
假设每一方块的边长等於 80, 则所需执行的 BitBlt 叙述如下:
' hDCMem 为暂存区之 hDC
' hDCScreen 为萤幕之 hDC
ret = BitBlt(hDCMem, 0, 0, 80, 80, hDCScreen, M1 * 80, N1 * 80, SRCCOPY)
ret = BitBlt(hDCScreen, M1 * 80, N1 * 80, 80, 80, hDCScreen, M2 * 80, M2 * 80, SRCCOPY)
ret = BitBlt(hDCScreen, M2 * 80, M2 * 80, 80, 80, hDCMem, 0, 0, SRCCOPY)
暂存区 DC 的取得与释回
--------------------------------------------------------------------------------
在以上程式中, hDCScreen 是利用 GetDC(0) 取得, 而 hDCMem(暂存区的 DC)则必须利用 CreateCompatibleDC 函数来取得, 如下:
Dim hDCMem As Long
hDCMem = CreateCompatibleDC(hDCScreen)
此一函数的作用是建立相容性 DC, 由於传入的是 hDCScreen(萤幕的 hDC),所以建立出来的 hDCMem 将与萤幕相容(主要是色盘之颜色数目相同)。
暂存区 DC 不再使用时应将其释回, 此时呼叫之 API 是 DeleteDC, 如下:(释回萤幕 DC 的函数是 ReleaseDC, 两者不可以混合使用)
ret = DeleteDC(hDCMem)
CreateCompatibleBitmap:为 DC 建立点阵图
--------------------------------------------------------------------------------
取得 hDCMem 之後, 利用 BitBlt 应该就可以将 hDCScreen 的图像复制到暂存区 DC 中, 但实际上不然, BitBlt 只对含有「点阵图」(Bitmap)的 DC 有作用,而经由 CreateCompatibleDC 所建立的暂存区 DC 一开始是不含点阵图的, 所以呼叫 BitBlt 函数并没有作用, 为了让 BitBlt 能够复制图像到暂存区 DC, 以及从暂存区 DC 读取图像, 我们必须为暂存区 DC 建立点阵图, 此时呼叫之 API 如下:
Dim hBitmap As Long
hBitmap = CreateCompatibleBitmap(hDCScreen, 宽, 高) ' 建立点阵图
ret = SelectObject(hDCMem, hBitmap) ' 将点阵图设定给 hDCMem
请特别注意传入 CreateCompatibleBitmap 的 hDC 是萤幕的 hDC, 不是暂存区的 hDC, 其作用是建立与萤幕相容的点阵图(颜色数目与萤幕相同的点阵图), 而接下来必须呼叫 SelectObject 让此一点阵图的 handle(hBitmap) 附属於 hDCMem, 也就是让暂存区 DC 含有点阵图, 如此一来 hDCMem 方可用於 BitBlt 函数。
点阵图的释回
--------------------------------------------------------------------------------
不使用点阵图时, 可呼叫 DeleteObject(hBitmap) 将其释回, 但请注意附属於 DC 的点阵图是不可以释回的, 除非 DC 也已经被释回系统, 例如:
' hBitmap 附属於 hDCMem
ret = DeleteDC(hDCMem) ' 先释回 DC
ret = DeleteObject(hBitmap) ' 再释回点阵图
萤幕保护程式之动画
--------------------------------------------------------------------------------
使用以上所介绍的 API 函数, 总算可以达到随机变换萤幕任意两个方块的目的了,请看笔者所完成的副程式:(此一副程式放置 saver.vbp 专案的 saver.bas 档案中,也包含在下载的档案中)
Sub Saver()
Dim M1 As Long, M2 As Long, N1 As Long, N2 As Long, ret As Long
Dim hDCMem As Long, hDCScreen As Long, hBitmap As Long
Dim sx As Integer, sy As Integer
sx = Screen.Width \ Screen.TwipsPerPixelX ' 以 pixel 为单位之萤幕宽
sy = Screen.Height \ Screen.TwipsPerPixelY ' 以 pixel 为单位之萤幕高
hDCScreen = GetDC(0) ' 取得萤幕 DC
hDCMem = CreateCompatibleDC(hDCScreen) ' 建立暂存区 DC
hBitmap = CreateCompatibleBitmap(hDCScreen, BSize, BSize) ' 建立点阵图
ret = SelectObject(hDCMem, hBitmap) ' 将点阵图设定给暂存区 DC
M1 = CInt(Rnd * sx \ BSize)
N1 = CInt(Rnd * sy \ BSize) ' (M1, N1) 为方块一
M2 = CInt(Rnd * sx \ BSize)
N2 = CInt(Rnd * sy \ BSize) ' (M2, N2) 为方块二
' 方块一与方块二互换
ret = BitBlt(hDCMem, 0, 0, BSize, BSize, hDCScreen, M1 * BSize, N1 * BSize, SRCCOPY)
ret = BitBlt(hDCScreen, M1 * BSize, N1 * BSize, BSize, BSi
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -