No announcement yet.

BeginPaint vs GetDC (in WM_PAINT)

  • Filter
  • Time
  • Show
Clear All
new posts

  • BeginPaint vs GetDC (in WM_PAINT)

    Guys --
    In WM_PAINT (Win2000) I create memory DC and then copy it (BitBlt) to window's hDC.
    Somebody can explain, why I have troubles with BeginPaint/EndPaint (not always updates), unlike GetDC/ReleaseDC works fine ?

    E-MAIL: [email protected]

  • #2
    If your window has invalidated parts it should redraw when Windows is idle.
    You can force it with updatewindow of course.
    I saw an example that returned 1 instead of 0 in SDK window
    It's 0 for SDK, 1 for Dialogboxes !

    Ever considered using the WM_ERASBKGROUND instead?



    • #3
      Do you use the hDC returned by BeginPaint, or the one in its PAINTSTRUCT
      member? Should be same, but maybe Win2000 thinks differently, so using
      the returned hDC is safer there?



      • #4
        Guys --
        try to move any second window over this.
        With BeginPaint visible problems.
        Funny, but counter is updated.
        I tried to add Function = 1 to WM_PAINT. Doesn't help. More than strange.

           #Compile Exe
           #Dim All
           #Register None
           #Include "WIN32API.INC"
           CallBack Function DlgProc
              Select Case CbMsg
                 Case %WM_PAINT
                    Dim hBrush As Long, hFont As Long, rc As RECT, ps As PAINTSTRUCT, hMemDC As Long, hMemBmp As Long
                    Dim zText As Asciiz * 255, i As Long, j As Long, sz As SIZEL
                    Dim dx As Long, dy As Long, dw As Long, dh As Long, ddx As Long, n As Long
                    ps.hDC = BeginPaint (CbHndl, ps) ' <----------   ps.hDC = GetDC(CbHndl)
                    GetClientRect CbHndl, rc
                    hMemDC = CreateCompatibleDC(ps.hDC)
                    hMemBmp = CreateCompatibleBitMap (ps.hDC, rc.nRight, rc.nBottom)
                    SelectObject hMemDC, hMemBmp
                    hBrush = CreateSolidBrush (GetNearestColor(ps.hDC, %Blue)) ' Rgb(0, 128, 192)))
                    hFont = CreateFont(rc.nBottom / 6, 0, 0, 0, %FW_NORMAL, _
                       0, 0, 0, %RUSSIAN_CHARSET, 0, 0, 0, 0, "Times New Roman")
                    FillRect hMemDC, rc, hBrush
                    SelectObject hMemDC, hFont
                    SetBkMode hMemDC, %TRANSPARENT
                    Static h As Long
                    Incr h
                    zText = Str$(h) ' $Text
                    dx = 10: dy = 10 ' Initial x, y
                    ddx = 5 ' distance between letters
                    dw = 10: dh = 5 ' size of shadow
                    n = Max(dw, dh)
                    For i = 1 To Len(zText)
                       For j = 0 To n
                          SetTextColor hMemDC, Rgb(j * 255 / n, j * 255 / n, 0)
                          TextOut hMemDC, dx + (n - j) * dw / n, dy + (n - j) * dh / n, Mid$(zText, i, 1), 1
                       GetTextExtentPoint32 hMemDC, Mid$(zText, i, 1), 1, sz
                       dx = dx + + ddx
                    BitBlt ps.hDC, rc.nLeft, rc.nTop, rc.nRight, rc.nBottom, hMemDC, 0, 0, %SRCCOPY
                    EndPaint CbHndl, ps ' <---- ReleaseDc CbHndl, ps.hDc
                    DeleteDC hMemDC
                    DeleteObject hMemBmp
                    DeleteObject hBrush
                    DeleteObject hFont
                 Case %WM_ERASEBKGND
                    Function = 1: Exit Function
              End Select
           End Function
           Function PbMain () As Long
              Local hDlg As Long
              Dialog New 0, "Polus", ,, 0, 0, %WS_MAXIMIZE  Or %WS_SYSMENU  To hDlg
              Dialog Show Modal hDlg Call DlgProc
          End Function
        [This message has been edited by Semen Matusovski (edited March 17, 2001).]


        • #5
          I think the painting that you do not see is supposed to happen in the WM_ERASEBKGND event.

          From MSDN:
          The BeginPaint function automatically sets the clipping region of the device context to exclude any area outside the update region.

          Try copying the GetDC version of your code to the WM_ERASEBKGND event.
          Use the BeginPaint version in WM_PAINT
          To know wich one is executing change one of them to:

          hBrush = CreateSolidBrush (GetNearestColor(myhDC, %Red))

          Best Regards
          Peter Scheutz

          Best Regards
          Peter Scheutz


          • #6
            Yes, it clips, so in this case, it is "normal" behaviour. Either
            use GetDc, or add InvalidateRect to %WM_ERASEBKGND, like:
                     CASE %WM_ERASEBKGND
                        InvalidateRect CBHNDL, BYVAL %NULL, 0 '<- last one must be zero, otherwise endless problem..
                        UpdateWindow CBHNDL
                        FUNCTION = 1



            • #7

              I noticed you were using the same variable to receive the return value
              from BeginPaint as you are using as a parameter to BeginPaint (in BeginPaint it is
              the UDT ps, but the return value is put into a member of that same UDT).

              I would suggest using a different value to store the return value !

              By using a member to return a value that is a part of a UDT passed as
              a member, maybe some confusion can occur. Using GetDC, no UDT is being
              passed to conflict with the return variable.

              Even if it does work it is not a good habit.

              Chris Boss
              Computer Workshop
              Developer of "EZGUI"


              • #8

                I am aware of this problem and to avoid it I use InvalidateRect
                just before BeginPaint.

                    CASE %WM_PAINT
                         ARRAY SCAN hWinShadow&(), = hWnd&, TO Item&
                         IF Item& > 1 THEN
                            DECR Item& 
                            CALL GetWindowRect (hWnd&, rc) 
                            XShadow& = rc.nRight - rc.nLeft: YShadow& = rc.nBottom - rc.nTop
                            CALL InvalidateRect(hWnd&, BYVAL %NULL, 0) ' <-- SEMEN
                            hDC& = BeginPaint(hWnd&, ps)
                Patrice Terrier
                mailto[email protected][email protected]</A>
                Patrice Terrier
                Addons: GDImage.DLL 32/64-bit (Graphic library), WinLIFT.DLL 32/64-bit (Skin Engine).


                • #9
                  Guys --
                  Thanx for replies.
                  I see two simple ways, which works -
                  single InvalidateRect CbHndl, BYVAL %NULL, 0 in WM_ERASEBKGND + BeginPaint
                  or GetDC instead of BeginPaint in WM_PAINT

                  Interesting, is InvalidateRect a part of DefWindowProc in WM_ERASEBKGND ?

                  [This message has been edited by Semen Matusovski (edited March 18, 2001).]


                  • #10
                    I disagree, invalidaterect forces WM_PAINT but option set to 1 will erasebackground.
                    How can you use invalidaterect FROM WM_PAINT, it looks recursive behaviour to me.
                    I'm not gonna maintain a static, it's simply bad.

                    Did i miss the point?



                    • #11

                      I tried Semen's first code example above, added FUNCTION = 1 to the WM_PAINT event and it works perfectly...

                      Anyone else try this "simple" solution without the need to GetDC, InvalidateRect, etc?

                      Later: Hmmm... it's almost perfect... I did not drag a window across the text counter.

                      When adding InvalidateRect() it certainly fixes the problem at the cost of doubling the WM_PAINT events: You are just forcibly changing the update region to the entire dialog, this seems like a crazy approach to solve the problem.

                      I'll experiment with this later (when I have some time), but moving the background painting to WM_ERASEBKGND and retaining the foreground painting in WM_PAINT is likely the best avenue for experimentation here, and the closest to how an app is "supposed" to work.

                      PowerBASIC Support
                      mailto:[email protected][email protected]</A>
                      mailto:[email protected]


                      • #12
                        Lance --
                        I added InvalidateRect CbHndl, ByVal 0, 0 exactly before BeginPaint and don't see double WM_PAINT under Win2000.
                        Is known that BeginPaint (unlike GetDC) repaints invalidated areas only.

                        If DefWindowProc for EraseBkgnd includes InvalidateRect, all is clear.
                        If not, I understand nothing.

                        Edwin --
                        With what exactly are you disagree ?

                        E-MAIL: [email protected]


                        • #13
                          I have to agree with Lance and Edwin, your code shows poor use of the
                          WM_PAINT message. If you are going to forcefully invalidate the entire
                          client area in WM_PAINT then do your painting in WM_ERASEBKGND.

                          Anyway, I cannot test your code because I do not use DDT but the following
                          may help to explain your problem.

                          First, using the rectangle returned by GetClientRect in WM_PAINT will only
                          work if you use the DC returned by GetDC or if you forcefully invalidate the
                          entire client area and use tps.hdc. This is because the tps.hdc context is
                          clipped so any drawing you do outside of the invalid area(tps.rcPaint) will
                          not be seen.
                          Second, mapping and clipping.
                          For example,

                          1. Given a bitmap located at (x,y) in the client area of a window
                          2. Given the invalid area from BeginPaint, tps.rcPaint = (x1,y1,x2,y2)
                          3. The memory dc for this area would be(0, 0, x2 - x1 + 1, y2 - y1 + 1)
                          The upper left corner of the bitmap in the memory dc would be (x - x1, y - y1).
                          However, when the entire client area is invalid,
                          rcClient = tps.rcPaint = rcMemDC and the bitmap would be located at (x,y) in
                          the memory dc since x1 = y1 = 0.
                          rcClient = bounding rectangle of client area
                          rcMemDC = bounding rectangle of memory dc

                          Dominic Mitchell
                          Dominic Mitchell
                          Phoenix Visual Designer


                          • #14
                            If you create your offscreen Dib in the WM_RESIZE event, you can get a 1:1 relation between screen/offscreen coords.

                            Edited to correct the following wrong information. Sorry!
                            On systems with more than one monitor, upper left corner is not always (0,0)
                            That is correct for window coords, not GetClientRect upper left.
                            Those are always at (0,0,)...I think, maybee...almost sure...

                            Best Regards
                            Peter Scheutz

                            [This message has been edited by Peter Scheutz (edited March 23, 2001).]
                            Best Regards
                            Peter Scheutz