VB6就不说了,要快速写一个程序,.NET(C#)可能还更好更强大,但是要说安全,VB6反到强过他们
有时候两者就是一种矛盾,所以越是用户友好,越是易维护和扩展的程序,越容易被破解.
MDI窗口没有refresh方法,没有paint事件,没有hDC,更没有PaintPicture方法.等等,我们先说动态绘制的必要性.
MDI父窗口有个Picture属性,可以加载一幅图像,然而动态绘制可以根据窗口的大小调整背景图片.
不要告诉我,你要做Width * Height张图片,每次都用LoadPicture,那你的程序还真是大系统了...
由于上面所说的MDI窗体的限制,常规的方法是不行了,现在先提供一个笨一点的方法,越笨越实用,也越简单
Public Sub Draw1(mf As MDIForm,sp As StdPicture,p As PictureBox) p.ScaleMode = vbPixels p.Width = mf.ScaleWidth '注意单位 p.Height = mf.ScaleHeight '注意单位 p.AutoRedraw = True p.PaintPicture sp,p.ScaleWidth,p.ScaleHeight mf.Picture = p.Picture mf.BackColor = vbWhite 'force refresh End Sub
首先要注意的是PictureBox的容器ScaleMode会对度量有影响,关键后面要赋值背景色,这样会强迫MDI窗体重绘,图片当然覆盖背景色,就实现了
调整PaintPicture的参数可以实现居中,平铺(缩放)等等各种效果
但是限制是需要一个PictureBox控件,该控件放到MDI中会触动Align属性,即使隐藏了,设计的时候也很不雅观,人爱面子树爱皮,程序爱UI
所以,必须加一个PictureBox,往往要加一个Form.能不能把PictureBox封装到类中呢?我觉得应该可以,甚至可以
Private WithEvents m_Draw As PictureBox
只是到现在我还没实现出来.
那么,还有没有其他替代方案呢,当然,PictureBox最重要的属性是Picture,是一个IPictureDisp(StdPicture),而PaintPicture方法就是
对StdPicture的Render方法封装.只是Render方法原图形的度量是按Himetric算的,要经过换算,用Render方法可以直接渲染到DC上
2.待研究的Render方法,常规的Form是没问题,如
Option Explicit Dim p As StdPicture Private Sub Form_Load() Me.ScaleMode = vbPixels 'Me.AutoRedraw = True Set p = LoadPicture("F:\Codes\VBCode\1.bmp") End Sub Private Sub Form_Resize() p.Render Me.hDC,Me.ScaleWidth,Me.ScaleHeight,p.Height,p.Width,-p.Height,ByVal 0 End Sub Private Sub Form_Unload(Cancel As Integer) Set p = Nothing End Sub
但是注意的一点是,MDI窗体没有hDC,那怎么办,对API直接取DC,如:
hDC1 = GetDC(mf.hWnd) Call GetClientRect(mf.hWnd,rc) p.Render hDC1,rc.Right - rc.Left,rc.Bottom - rc.Top,ByVal 0 mf.BackColor = &HF0F0F7 '.Refresh Call ReleaseDC(mf.hWnd,hDC1)
然而,问题来了,提示无效参数,毛啊!用SPY++,发现MDI窗体的客户区其实是VB自己创建的一个子窗口(WS_CHILD),其类名是MDIClient
那么我们修改一下,而且用GetWindowDC代替成对的GetDC,如下
hClient = FindWindowEx(mf.hWnd,"MDIClient",vbNullChar) Call GetClientRect(hClient,rc) hDC1 = GetWindowDC(hClient) p.Render hDC1,ByVal 0 mf.BackColor = &HF0F0F7 '.Refresh
问题依旧,没办法了,目前来说,暂时委屈一下吧,难道我们天生就是奴隶?
VB很像一个东西,那就MFC类库,其实都是对Windows API的封装,那么其最终的实现都是API调用,那么就想到另外一招:
3.无敌的内存绘图
Public Sub Draw1(mf As MDIForm,p As StdPicture) Dim hClient As Long,hOld As Long Dim hDC1 As Long,hDC2 As Long Dim rc As RECT hClient = FindWindowEx(mf.hWnd,vbNullChar) Call GetClientRect(hClient,rc) hDC1 = GetWindowDC(hClient) hDC2 = CreateCompatibleDC(hDC1) hOld = SelectObject(hDC2,p.Handle) BitBlt hDC1,hDC2,vbSrcCopy SelectObject hDC2,hOld DeleteDC hDC2 'p.Render hDC1,ByVal 0 mf.BackColor = &HF0F0F7 '.Refresh End Sub
调整BitBlt的参数,就跟调整PaintPicture的参数一样简单,说白了PaintPicture最终还是封装了BitBlt,当然你可以使用其他的绘图API,甚至直接操作位图的像素
但是那样的投入就太大了,一开始我还想用C/C++写个动态库,那样可能效率高点,但是牺牲开发效率来换取执行效率,不见得是明智的选择.
这是我研究出最卑鄙无耻下流银剑的方法了.
原文链接:https://www.f2er.com/vb/258607.html