CreateCompatibleDC + SetPixel -> BitBlt

  • VB6

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von Mad Andy.

    CreateCompatibleDC + SetPixel -> BitBlt

    Hi!

    Folgender Ablauf:
    Ich hab 4 Bilder, die per SetPixel gezeichnet werden. Dise sollen aber in getrennte DCs gepackt werden, weil das Neuzeichnen zu lange dauert (-> flackern), und dann per BitBlt in eine Picturebox gebltet werden.

    Mein bisheriger Code:

    APIs, UDTs und Consts:

    Visual Basic-Quellcode

    1. Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
    2. Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
    3. Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hDC As Long) As Long
    4. Private Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As Long
    5. Private Declare Function SetPixel Lib "gdi32" (ByVal hDC As Long, ByVal x As Long, ByVal y As Long, ByVal crColor As Long) As Long
    6. 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
    7. Private Declare Function GetPixel Lib "gdi32" (ByVal hDC As Long, ByVal x As Long, ByVal y As Long) As Long
    8. Private Type COLORREF
    9. rgbRed As Byte
    10. rgbGreen As Byte
    11. rgbBlue As Byte
    12. rgbReserved As Byte
    13. End Type
    14. Private Const SRCCOPY = &HCC0020 ' (DWORD) dest = source
    Programm:

    Visual Basic-Quellcode

    1. 'Bildauswahl
    2. Private cSel As Byte 'Farbe: cGn
    3. Private cSelOld As Byte 'zur Änderungsprüfung
    4. Private cmdDown As Boolean 'Farbe:cCn
    5. Private cmdDownOld As Boolean 'zur Änderungsprüfung
    6. 'Farbwerte (Anfang & Ende von Verlauf)
    7. Private cG1 As COLORREF
    8. Private cG2 As COLORREF
    9. Private cC1 As COLORREF
    10. Private cC2 As COLORREF
    11. 'DCs
    12. Private hDCn As Long 'normal
    13. Private hDCh As Long 'hover
    14. Private hDCnd As Long 'normal, down
    15. Private hDChd As Long 'hover, down
    16. Private Sub Form_Load()
    17. cG1 = NewColor(225, 222, 213)
    18. cG2 = NewColor(179, 176, 170)
    19. cC1 = NewColor(173, 201, 237)
    20. cC2 = NewColor(130, 151, 179)
    21. cSel = 0
    22. cSelOld = 1
    23. cmdDown = False
    24. cmdDownOld = True
    25. hDCn = CreateCompatibleDC(GetDC(0))
    26. hDCh = CreateCompatibleDC(GetDC(0))
    27. hDCnd = CreateCompatibleDC(GetDC(0))
    28. hDChd = CreateCompatibleDC(GetDC(0))
    29. picBG_Resize
    30. End Sub
    31. Private Sub picBG_Resize()
    32. DrawNiceButton hDCn, cG1, cG2, picBG.Width / 15, picBG.Height / 15, False
    33. DrawNiceButton hDCh, cC1, cC2, picBG.Width / 15, picBG.Height / 15, False
    34. DrawNiceButton hDCnd, cG1, cG2, picBG.Width / 15, picBG.Height / 15, True
    35. DrawNiceButton hDChd, cC1, cC2, picBG.Width / 15, picBG.Height / 15, True
    36. End Sub
    37. Private Sub DrawNiceButton(hDC As Long, cStart As COLORREF, cEnd As COLORREF, Width As Long, Height As Long, Pressed As Boolean)
    38. 'Debug-Output liefert gültige DCs und die richtigen Werte
    39. Debug.Print "DrawNiceButton: hDC=" & hDC & ", cStart=(" & cStart.rgbRed & ", " & cStart.rgbGreen & ", " & cStart.rgbBlue & "), cEnd=(" & cEnd.rgbRed & ", " & cEnd.rgbGreen & ", " & cEnd.rgbBlue & "), width=" & Width & ", height=" & Height & ", pressed=" & Pressed
    40. '...
    41. 'cThis hat den richtigen Wert, gleicher Code hat mit picBG.hDC funktioniert
    42. cThis = BalanceColor(cRowStart, cRowEnd, CSng(y) / ymax)
    43. CopyMemory lThis, cThis, 4
    44. SetPixel hDC, x, y, lThis
    45. '...
    46. End Sub
    47. Private Sub picBG_Paint()
    48. If cmdDown Then
    49. If cSel = 0 Then
    50. BitBlt picBG.hDC, 0, 0, picBG.Width / 15 - 1, picBG.Height / 15 - 1, hDCnd, 0, 0, SRCCOPY
    51. Else
    52. BitBlt picBG.hDC, 0, 0, picBG.Width / 15 - 1, picBG.Height / 15 - 1, hDChd, 0, 0, SRCCOPY
    53. End If
    54. Else
    55. If cSel = 0 Then
    56. Debug.Print BitBlt(picBG.hDC, 0, 0, picBG.Width / 15 - 1, picBG.Height / 15 - 1, hDCn, 0, 0, SRCCOPY)
    57. Else
    58. BitBlt picBG.hDC, 0, 0, picBG.Width / 15 - 1, picBG.Height / 15 - 1, hDCh, 0, 0, SRCCOPY
    59. End If
    60. End If
    61. End Sub
    BitBlt gibt 1 zurück -> scheinbar kein Fehler.

    Wenn ich mit

    Visual Basic-Quellcode

    1. lThis = GetPixel(hDCn, x, y)
    2. CopyMemory cThis, lThis, 4
    einen beliebigen Punkt vom "normal"-DC augebe, kommt immer 255, 255, 255.

    Hab ich vllt. irgendwas vergessen? Muss man irgendeine Region o.Ä. bei nem eigenen DC setzen?


    so long..
    Andy

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Mad Andy“ ()

    Du bist kein unbeschriebenes Blatt in Sachen Programmierung,
    da hättest du ruhig wissen können, dass man zuerst in
    die MSDN guckt!

    Egal. Das Problem ist, dass CreateCompatibleDC nur einen
    - wie der Name schon sagt - kompatiblen Gerätekontext
    anlegt, keine Kopie. Deshalb ist dein DC nur einen Pixel
    breit, einen Pixel hoch und monochrom. Du musst den
    DC also mit einer Bitmap dimensionieren. Achte dabei darauf,
    dass du eine Bitmap erstellst, die kompatibel zu dem
    Bildschirm ist, ansonsten bleibt der DC monochrom.

    Übrigens kannst du dir das GetDC(0) beim erstellen
    des DCs sparen, da die Übergabe von 0 als Parameter
    den gleichen Effekt hat.
    War ja klar, dass du das wieder weißt ^^
    Scheinbar is die Mail doch nicht ins Nirvana geliefert worden :)
    Werds morgen gleich ausprobieren, danke.

    Das mit der MSDN stimmt eigentlich, auf msdn.microsoft.com findet man aber nix mehr und die 1998er, die ich hier rumliegen hab, hab ich noch nich oben..


    so long..
    Andy
    Brauch ich außer CreateCompatibleBitmap und DeleteObject noch was?

    einfach nur

    Visual Basic-Quellcode

    1. CreateCompatibleBitmap(hdc, Width, Height)
    in DrawNiceButton reinzupacken hat nix geholfen. Wenn das DC kompatibel zum Screen ist (was es ja durch den Parameter 0 (= vom Programm übernehmen) sein sollte), müsste die Bitmap doch genauso kompatibel sein?

    Gibts sonst noch was? :-\
    Was ist hdc ? Dein gerade mit CreateCompatibleDC
    erstelltes DC ? Wenn ja: Da muss der DC des Bildschirms
    hin. (Leider kann man hier nicht einfach 0 übergeben)

    Die Bitmap ist Kompatibel zum Bildschirm, wenn du
    dein erstelltes DC verwendest, allerdings werden
    auch die Farbinformationen von deinem DC übernommen,
    wodurch dein DC monochrom bleiben würde.

    Und ja, du musst die Bitmap noch mit SelectObject in
    den DC selektieren.
    Bin jetzt endlich damit fertig geworden :)

    picBG ist die Picturebox, die als Button dient. (Der Name ist so, weil da noch ein Label, ein Icon, etc.. rein kommt)

    Ich verwende zur Farbwahl eine Struct, die in C++ dafür verwendet wird: COLORREF. In VB6 kann man diese leider nicht an SetPixel übergeben. Mit CopyMemory stopf ich das also erst in einen Long, bevor ichs zeichne.

    APIs, Structs, Consts:

    Visual Basic-Quellcode

    1. Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
    2. Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
    3. Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hDC As Long) As Long
    4. Private Declare Function CreateCompatibleBitmap Lib "gdi32" (ByVal hDC As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
    5. Private Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As Long
    6. Private Declare Function SelectObject Lib "gdi32" (ByVal hDC As Long, ByVal hObject As Long) As Long
    7. Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
    8. Private Declare Function SetPixel Lib "gdi32" (ByVal hDC As Long, ByVal X As Long, ByVal Y As Long, ByVal crColor As Long) As Long
    9. 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
    10. Private Type COLORREF
    11. rgbRed As Byte
    12. rgbGreen As Byte
    13. rgbBlue As Byte
    14. rgbReserved As Byte
    15. End Type
    16. Private Const SRCCOPY = &HCC0020 ' (DWORD) dest = source


    Variablen:

    Visual Basic-Quellcode

    1. 'Colors
    2. Private cG1 As COLORREF 'Gray color 1
    3. Private cG2 As COLORREF 'Gray color 2
    4. Private cC1 As COLORREF 'Active color 1
    5. Private cC2 As COLORREF 'Active color 2
    6. 'State
    7. Private cSel As Byte 'Active or Gray?
    8. Private cSelOld As Byte 'Helper to see if we have to redraw it
    9. Private cmdDown As Boolean 'Down ("Pressed") or not?
    10. Private cmdDownOld As Boolean 'Helper to see if we have to redraw it
    11. 'DCs and BMPs
    12. Private hDCn As Long 'normal
    13. Private hDCh As Long 'hover
    14. Private hDCnd As Long 'normal, down
    15. Private hDChd As Long 'hover, down
    16. Private hBMPn As Long 'normal
    17. Private hBMPh As Long 'hover
    18. Private hBMPnd As Long 'normal, down
    19. Private hBMPhd As Long 'hover, down


    General Functions:

    Visual Basic-Quellcode

    1. Private Function NewColor(r As Byte, g As Byte, b As Byte) As COLORREF
    2. 'Creates a new color with single R, G and B values
    3. NewColor.rgbRed = r
    4. NewColor.rgbGreen = g
    5. NewColor.rgbBlue = b
    6. End Function
    7. Private Function BalanceColor(c1 As COLORREF, c2 As COLORREF, Balance As Single) As COLORREF
    8. 'Balances a color between 2 colors with a given ratio
    9. BalanceColor.rgbBlue = c1.rgbBlue * (1 - Balance) + c2.rgbBlue * Balance
    10. BalanceColor.rgbGreen = c1.rgbGreen * (1 - Balance) + c2.rgbGreen * Balance
    11. BalanceColor.rgbRed = c1.rgbRed * (1 - Balance) + c2.rgbRed * Balance
    12. End Function


    Program:

    Visual Basic-Quellcode

    1. Private Sub Form_Load()
    2. 'Set colors
    3. cG1 = NewColor(225, 222, 213)
    4. cG2 = NewColor(179, 176, 170)
    5. cC1 = NewColor(173, 201, 237)
    6. cC2 = NewColor(130, 151, 179)
    7. 'Set state
    8. cSel = 0
    9. cSelOld = 1
    10. cmdDown = False
    11. cmdDownOld = True
    12. 'Create and draw the DCs
    13. picBG_Resize
    14. End Sub
    15. Private Sub Form_Unload(Cancel As Integer)
    16. 'Delete DCs and BMPs
    17. DeleteDC hDCn
    18. DeleteDC hDCh
    19. DeleteDC hDCnd
    20. DeleteDC hDChd
    21. DeleteObject hBMPn
    22. DeleteObject hBMPh
    23. DeleteObject hBMPnd
    24. DeleteObject hBMPhd
    25. End Sub
    26. Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    27. cSel = 0 'Hover = false
    28. PaintCmd 'Check if we have to repaint it
    29. End Sub
    30. Private Sub picBG_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    31. cSel = 1 'Hover = true
    32. PaintCmd 'Check if we have to repaint it
    33. End Sub
    34. Private Sub picBG_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    35. cmdDown = True 'Pressed = true
    36. PaintCmd 'Check if we have to repaint it
    37. End Sub
    38. Private Sub picBG_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    39. cmdDown = False 'Pressed = false
    40. PaintCmd 'Check if we have to repaint it
    41. End Sub


    Drawing:

    Visual Basic-Quellcode

    1. Private Sub PaintCmd()
    2. 'We do the repaint check here because the redraw event
    3. 'is used for "general" redraw (via win msg) too.
    4. 'If hover changed -> redraw
    5. If cSelOld <> cSel Then
    6. cSelOld = cSel
    7. picBG_Paint
    8. End If
    9. 'If down-state changed -> redraw
    10. If cmdDownOld <> cmdDown Then
    11. cmdDownOld = cmdDown
    12. picBG_Paint
    13. End If
    14. End Sub
    15. Private Sub picBG_Paint()
    16. 'Copy the matching DC to our picBox via BitBlt.
    17. If cmdDown Then
    18. If cSel = 0 Then
    19. BitBlt picBG.hDC, 0, 0, picBG.Width \ 15, picBG.Height \ 15, hDCnd, 0, 0, SRCCOPY
    20. Else
    21. BitBlt picBG.hDC, 0, 0, picBG.Width \ 15, picBG.Height \ 15, hDChd, 0, 0, SRCCOPY
    22. End If
    23. Else
    24. If cSel = 0 Then
    25. BitBlt picBG.hDC, 0, 0, picBG.Width \ 15, picBG.Height \ 15, hDCn, 0, 0, SRCCOPY
    26. Else
    27. BitBlt picBG.hDC, 0, 0, picBG.Width \ 15, picBG.Height \ 15, hDCh, 0, 0, SRCCOPY
    28. End If
    29. End If
    30. End Sub


    Creation:

    Visual Basic-Quellcode

    1. Private Sub picBG_Resize()
    2. 'We have to recreate and redraw the button's DCs when the size changed
    3. DrawNiceButton hDCn, hBMPn, cG1, cG2, picBG.Width / 15, picBG.Height / 15, False
    4. DrawNiceButton hDCh, hBMPh, cC1, cC2, picBG.Width / 15, picBG.Height / 15, False
    5. DrawNiceButton hDCnd, hBMPnd, cG1, cG2, picBG.Width / 15, picBG.Height / 15, True
    6. DrawNiceButton hDChd, hBMPhd, cC1, cC2, picBG.Width / 15, picBG.Height / 15, True
    7. End Sub
    8. Private Sub DrawNiceButton(hDC As Long, hBMP As Long, cStart As COLORREF, cEnd As COLORREF, Width As Long, Height As Long, Pressed As Boolean)
    9. 'Delete the old DC and the old BMP
    10. If hDC > 0 Then DeleteDC hDC
    11. If hBMP > 0 Then DeleteObject hBMP
    12. 'CreateCompatibleDC
    13. hDC = CreateCompatibleDC(GetDC(0))
    14. If hDC = 0 Then
    15. Debug.Print "CreateCompatibleDC failed!"
    16. Exit Sub
    17. End If
    18. 'CreateCompatibleBitmap
    19. hBMP = CreateCompatibleBitmap(GetDC(0), Width, Height)
    20. If hBMP = 0 Then
    21. Debug.Print "CreateCompatibleBitmap failed!"
    22. Exit Sub
    23. End If
    24. 'Select the BMP to the DC
    25. If SelectObject(hDC, hBMP) = 0 Then
    26. Debug.Print "Selectobject failed!"
    27. Exit Sub
    28. End If
    29. 'Colors
    30. ' cStart and cEnd are the color values for two of the corners, cMid for the other two.
    31. ' cRowStart contains the color value for the first px in the row, cRowEnd for the
    32. ' last px in the row.
    33. ' cThis and lThis contains the color values for the current pixel.
    34. Dim cMid As COLORREF
    35. Dim cRowStart As COLORREF
    36. Dim cRowEnd As COLORREF
    37. Dim cThis As COLORREF
    38. Dim lThis&
    39. 'Counter vars
    40. Dim X&, Y&
    41. Dim xmax&, ymax&
    42. 'Set the counter maximums
    43. xmax = Width - 1
    44. ymax = Height - 1
    45. 'Get the color for 2 of the corners
    46. cMid = BalanceColor(cStart, cEnd, 0.5)
    47. 'Pressed buttons are drawn bottom-up
    48. If Pressed Then
    49. For X = 0 To xmax
    50. cRowStart = BalanceColor(cStart, cMid, CSng(X) / xmax)
    51. cRowEnd = BalanceColor(cMid, cEnd, CSng(X) / xmax)
    52. For Y = 0 To ymax
    53. cThis = BalanceColor(cRowStart, cRowEnd, CSng(Y) / ymax)
    54. CopyMemory lThis, cThis, 4
    55. SetPixel hDC, X, ymax - Y, lThis
    56. Next Y
    57. Next X
    58. Else
    59. For X = 0 To xmax
    60. cRowStart = BalanceColor(cStart, cMid, CSng(X) / xmax)
    61. cRowEnd = BalanceColor(cMid, cEnd, CSng(X) / xmax)
    62. For Y = 0 To ymax
    63. cThis = BalanceColor(cRowStart, cRowEnd, CSng(Y) / ymax)
    64. CopyMemory lThis, cThis, 4
    65. SetPixel hDC, X, Y, lThis
    66. Next Y
    67. Next X
    68. End If
    69. End Sub



    Wenns fragen dazu gibt, einfach melden :)


    so long..
    Andy

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Mad Andy“ ()