当前位置:编程学习 > VB >>

Bitblt导致无法用API绘图

去掉Bitblt那句代码,就能画出圆,加上却画不出。我已经用GetDC获得了窗体的场景,为什么复制场景后画不出图了,请问这是什么原因?

Option Explicit
Private Declare Function GetDC& Lib "user32" (ByVal hwnd As Long)
Private Declare Function Ellipse& Lib "gdi32" (ByVal hdc As Long, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long)
Private Declare Function ReleaseDC& Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long)
Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long

Private Sub Command1_Click()
    Dim PicDC As Long
    Form1.AutoRedraw = True
    'BitBlt hdc, 0, 0, 1000, 1000, Picture1.hdc, 0, 0, vbSrcCopy
    PicDC = GetDC(hwnd)        '获取设备场景句柄
    Ellipse PicDC, 0, 0, 100, 100         '画空心圆
    ReleaseDC hwnd, PicDC     '释放设备场景
End Sub

没人知道? 应该是你的两个DC不是兼容的DC,你可以使用CreateCompatibleDC,创建一个和Me.hdc相兼容的DC再使用BitBlt
引用 2 楼 veron_04 的回复:
应该是你的两个DC不是兼容的DC,你可以使用CreateCompatibleDC,创建一个和Me.hdc相兼容的DC再使用BitBlt

您好,我不明白您的意思,我知道当AutoRedraw=True的时候,Form1.hdc与GetDC(Form1.hwnd)得到的不是同一个hdc。但GetDC(Form1.hwnd)不就是显示出来的设备场景么?
当没用Bitblt的时候,是可以在这个场景中画图的,但是用了之后,到底哪里发生变化了,怎么就画不了了,Bitblt不只是复制设备场景内容而已么? BitBlt的参数中有两个DC,一个源DC,一个目标DC,这两个DC必须是“相兼容”的。
引用 2 楼 veron_04 的回复:
应该是你的两个DC不是兼容的DC,你可以使用CreateCompatibleDC,创建一个和Me.hdc相兼容的DC再使用BitBlt

您好,在AutoRedraw=True的情况下,使用Bitblt后,用Form1.Refresh是可以看到复制的场景的,我的疑问是为什么用API画圆就失效了呢?用API画圆本身就没有什么兼容不兼容的问题啊
引用 2 楼 veron_04 的回复:
应该是你的两个DC不是兼容的DC,你可以使用CreateCompatibleDC,创建一个和Me.hdc相兼容的DC再使用BitBlt

您好,在AutoRedraw=True的情况下,使用Bitblt后,用Form1.Refresh是可以看到复制的场景的,我的疑问是为什么用API画圆就失效了呢?用API画圆本身就没有什么兼容不兼容的问题啊
引用 4 楼 veron_04 的回复:
BitBlt的参数中有两个DC,一个源DC,一个目标DC,这两个DC必须是“相兼容”的。

Form1.hDC和Picture1.hDC应该是兼容的吧?要不Form1.Refresh也刷新不了啊。 看看这个例子:

'Example Name:Draw On Screen
'This Project needs
'- two timers, interval=100
'- a button

'in general section
Private Type POINTAPI
    x As Long
    y As Long
End Type

Private Declare Function GetActiveWindow Lib "user32" () As Long
Private Declare Function GetWindowDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function Ellipse Lib "gdi32" (ByVal hdc As Long, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long

Private Declare Function TextOut Lib "gdi32" Alias "TextOutA" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal lpString As String, ByVal nCount As Long) As Long
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Sub Form_Load()
    Timer1.Interval = 100
    Timer1.Enabled = True
    Timer2.Interval = 100
    Timer2.Enabled = True
    Command1.Caption = "Draw Text"
End Sub
'This will draw an Ellipse on the active window
Sub Timer1_Timer()
    Dim Position As POINTAPI
    'Get the cursor position
    GetCursorPos Position
    'Draw the Ellipse on the Screen's DC
    Ellipse GetWindowDC(0), Position.x - 5, Position.y - 5, Position.x + 5, Position.y + 5
End Sub
Sub Command1_Click()
    'KPD-Team 1998
    'URL: http://www.allapi.net/
    'E-Mail: KPDTeam@Allapi.net

    Dim intCount As Integer, strString As String
    strString = "Cool, text on screen !"
    For intCount = 0 To 30
        'Draw the text on the screen
        TextOut GetWindowDC(0), intCount * 20, intCount * 20, strString, Len(strString)
    Next intCount
End Sub
Private Sub Timer2_Timer()
    'Draw the text to the active window
    TextOut GetWindowDC(GetActiveWindow), 50, 50, "This is a form", 14
End Sub


引用 8 楼 veron_04 的回复:
看看这个例子:
VB code

'Example Name:Draw On Screen
'This Project needs
'- two timers, interval=100
'- a button

'in general section
Private Type POINTAPI
    x As Long
    y As Long
End Type

Private De……

谢谢,运行了一下这个例子。但是还是无法解释Bitblt如何导致绘制不上椭圆的问题。我主要的疑问是为什么Bitblt会导致绘制不上这种情况。 不是BitBlt不能绘制,而是Ellipse绘制了,但没有显示出来而已,你可以单步执行,看看Ellipse函数的返回值是否是非0,如果是非0,那么执行成功。
引用 10 楼 veron_04 的回复:
不是BitBlt不能绘制,而是Ellipse绘制了,但没有显示出来而已,你可以单步执行,看看Ellipse函数的返回值是否是非0,如果是非0,那么执行成功。

您好,GetDC得到的不是当前显示的设备场景么?既然画在当前显示的场景上,应该立即输出才对啊? Option Explicit
Private Declare Function GetDC& Lib "user32" (ByVal hwnd As Long)
Private Declare Function Ellipse& Lib "gdi32" (ByVal hdc As Long, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long)
Private Declare Function ReleaseDC& Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long)
Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long

Private Sub Command1_Click()
    Dim PicDC As Long
    Form1.AutoRedraw = True
    BitBlt hdc, 0, 0, 1000, 1000, Picture1.hdc, 0, 0, vbSrcCopy
'    PicDC = GetDC(hwnd)        '获取设备场景句柄
    Ellipse hdc, 0, 0, 100, 100         '画空心圆
'    ReleaseDC hwnd, PicDC'释放设备场景
Refresh

End Sub

红色的语句可以同时去除,不需要getdc

引用 7 楼 knightgy 的回复:
引用 4 楼 veron_04 的回复:

BitBlt的参数中有两个DC,一个源DC,一个目标DC,这两个DC必须是“相兼容”的。

Form1.hDC和Picture1.hDC应该是兼容的吧?要不Form1.Refresh也刷新不了啊。


你使用了别的dc,使用刷新也没有效果,但应该可以去掉设置autoredraw=false可立即显示
引用 13 楼 worldy 的回复:
引用 7 楼 knightgy 的回复:
引用 4 楼 veron_04 的回复:

BitBlt的参数中有两个DC,一个源DC,一个目标DC,这两个DC必须是“相兼容”的。

Form1.hDC和Picture1.hDC应该是兼容的吧?要不Form1.Refresh也刷新不了啊。


你使用了别的dc,使用刷新也没有效果,但应该可以去掉设置autoredraw=false可立即……


您好,我知道怎么让椭圆显示,我现在只是对出现的情况感到疑惑,因为从头到尾我用GetDC得到的场景都是不变的,我只是用了一句Bitblt向另一个hDC复制了一次,就无法显示出我绘制的椭圆了。下面的代码对此进行了测试。

Option Explicit
Private Declare Function GetDC& Lib "user32" (ByVal hwnd As Long)
Private Declare Function Ellipse& Lib "gdi32" (ByVal hdc As Long, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long)
Private Declare Function ReleaseDC& Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long)
Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long

Private Sub Command1_Click()
    Dim PicDC As Long
    Form1.AutoRedraw = True
    Debug.Print "GetDC(hwnd)="; GetDC(hwnd)
    Debug.Print "hdc="; hdc
    BitBlt hdc, 0, 0, 100, 100, Picture1.hdc, 0, 0, vbSrcCopy
    Debug.Print "hdc="; hdc
    PicDC = GetDC(hwnd)        '获取设备场景句柄
    Debug.Print "GetDC(hwnd)="; GetDC(hwnd)
    Dim r As Long
    r = Ellipse(PicDC, 100, 100, 200, 200)        '画空心圆
    Debug.Print "GetDC(hwnd)="; GetDC(hwnd)
    ReleaseDC hwnd, PicDC     '释放设备场景
End Sub

Private Sub Picture1_Click()
    Dim PicDC As Long
    Form1.AutoRedraw = False
    Debug.Print "GetDC(hwnd)="; GetDC(hwnd)
    Debug.Print "hdc="; hdc
    BitBlt hdc, 0, 0, 100, 100, Picture1.hdc, 0, 0, vbSrcCopy
    Debug.Print "hdc="; hdc
    PicDC = GetDC(hwnd)        '获取设备场景句柄
    Debug.Print "GetDC(hwnd)="; GetDC(hwnd)
    Dim r As Long
    r = Ellipse(PicDC, 100, 100, 200, 200)        '画空心圆
    Debug.Print "GetDC(hwnd)="; GetDC(hwnd)
    ReleaseDC hwnd, PicDC     '释放设备场景
End Sub

从Debug返回的结果来看,这两个过程GetDC都是同一个设备场景,只是因为第一个过程AutoRedraw=True,第二个过程AutoRedraw=False就出现不同的输出效果。
MSDN:
hDC 属性

AutoRedraw 属性能引起 hDC 属性改变。如果窗体或 窗体 PictureBox 容器的 AutoRedraw 属性设置为 True,hDC 将作为持久图形 的设备关联句柄(等价于 Image 属性)。当 AutoRedraw 属性为 False 时,hDC 属性是窗体窗口或 PictureBox 容器的真正的 hDC 值。

就是说
A)当 AutoRedraw = False 时 Form1.hDC = GetDC(Form1.hWnd)
无论 API 绘图还是 VB 绘图,都是向同一个设备输出,所见即所得。

B)当 AutoRedraw = True 时 Form1.hDC <> GetDC(Form1.hWnd)
Form1.hDC 其实是 VB 创建的缓冲设备,VB 会在必要的时候将 hDC 上内容复制到真正的显示设备 GetDC(Form1.hWnd) 上,所以直接在 GetDC(Form1.hWnd) 上的绘图就可能被覆盖。
引用 15 楼 tiger_zhao 的回复:
MSDN:hDC 属性

AutoRedraw 属性能引起 hDC 属性改变。如果窗体或 窗体 PictureBox 容器的 AutoRedraw 属性设置为 True,hDC 将作为持久图形 的设备关联句柄(等价于 Image 属性)。当 AutoRedraw 属性为 False 时,hDC 属性是窗体窗口或 PictureBox 容器的真正的 hDC 值。
就是说
A)当 AutoR……

您好,经过测试,在Autoredraw=true时,执行过Bitblt后,如果不刷新,并不显示复制的内容,也就应该不会覆盖GetDC得到的场景,即便不覆盖也不能显示绘制的内容。我清楚hDC和GetDC的区别,但是这并不能解释这个现象。显然大家并没有认真分析这短短的几行代码。
求破解 你已经糊涂了!
Private Sub Command1_Click()
    Form1.AutoRedraw = True '有显示和缓冲两个设备
    BitBlt hdc, 0, 0, 100, 100, Picture1.hdc, 0, 0, vbSrcCopy '向缓冲设备绘图
End Sub

没有经过刷新,缓冲设备的内容没有复制到显示设备上,怎么可能看得到?
补充:VB ,  API
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,