Announcement

Collapse
No announcement yet.

How to make dialogs less flashy when updating?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to make dialogs less flashy when updating?

    I have a form with 3 list boxes and 8 text boxes. After I save the data I clear the dialog by sending RESET to the list boxes and setting the text to "" on the text box.
    There is a fairly un-cool screen flash - like it is redrawing the entire window.

    What can I do the reduce all the flashing? I thought a while back I saw something about "suspend update"?? Double-buffering etc.

    I am I correct in my asssumption that SendMessage hCtrl, %WM_SETREDRAW, %FALSE, 0& needs to be done for each control, not the parent dialog?

    When I "walk" the code in the debugger it looks like the entire screen is redrawn by sending RESET to each listbox?

  • #2
    Would something like this work?
    I get the idea of painting to a bitmap and then Blit the bitmap into the screen.
    Would that work for an entire dialog?


    Code:
    CustomDoubleBuffer(HWND hwnd, PAINTSTRUCT* pPaintStruct)
    {
    int cx = pPaintStruct->rcPaint.right - pPaintStruct->rcPaint.left;
    int cy = pPaintStruct->rcPaint.bottom - pPaintStruct->rcPaint.top;
    HDC hMemDC;
    HBITMAP hBmp;
    HBITMAP hOldBmp;
    POINT ptOldOrigin;
    
    // Create new bitmap-back device context, large as the dirty rectangle.
    hMemDC = CreateCompatibleDC(pPaintStruct->hdc);
    hBmp = CreateCompatibleBitmap(pPaintStruct->hdc, cx, cy);
    hOldBmp = SelectObject(hMemDC, hBmp);
    
    // Do the painting into the memory bitmap.
    OffsetViewportOrgEx(hMemDC, -(pPaintStruct->rcPaint.left),
    -(pPaintStruct->rcPaint.top), &ptOldOrigin);
    CustomPaint(hwnd, hMemDC, &pPaintStruct->rcPaint, TRUE);
    SetViewportOrgEx(hMemDC, ptOldOrigin.x, ptOldOrigin.y, NULL);
    
    // Blit the bitmap into the screen. This is really fast operation and although
    // the CustomPaint() can be complex and slow there will be no flicker any more.
    BitBlt(pPaintStruct->hdc, pPaintStruct->rcPaint.left, pPaintStruct->rcPaint.top,
    cx, cy, hMemDC, 0, 0, SRCCOPY);
    
    // Clean up.
    SelectObject(hMemDC, hOldBmp);
    DeleteObject(hBmp);
    DeleteDC(hMemDC);
    }
    
    static LRESULT CALLBACK
    CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    switch(uMsg) {
    // ...
    
    case WM_ERASEBKGND:
    return FALSE; // Defer erasing into WM_PAINT
    
    case WM_PAINT:
    {
    PAINTSTRUCT ps;
    BeginPaint(hwnd, &ps);
    if(GetWindowLong(hwnd, GWL_STYLE) & XXS_DOUBLEBUFFER)
    CustomDoubleBuffer(hwnd, &ps);
    else
    CustomPaint(hwnd, ps.hdc, &ps.rcPaint, ps.fErase);
    EndPaint(hwnd, &ps);
    return 0;
    }

    Comment


    • #3
      When I "walk" the code in the debugger it looks like the entire screen is redrawn by sending RESET to each listbox?
      How [CONTROL] RESET is implemented by DDT is proprietary to PowerBASIC. Also I would not rely pn behavior observed in the stepping debugger to be duplicated in "real life."

      I am I correct in my assumption that SendMessage hCtrl, %WM_SETREDRAW, %FALSE, 0& needs to be done for each control, not the parent dialog?
      Here's the doc... https://docs.microsoft.com/en-us/win...i/wm-setredraw

      I think you just posted somethng like "I forgot that eveyrthing is a window. That's a hint.

      FWIW, were I emptying a listbox, I would turn off the redraw, remove the items, and then reenable redraw. But I'm an old fart WinAPI user.

      Were I, for some reason (such as creating a demo to be posted here) using DDT for my screen management, I would more than likely TRY STUFF.

      Michael Mattias
      Tal Systems Inc. (retired)
      Racine WI USA
      [email protected]
      http://www.talsystems.com

      Comment


      • #4
        Don't understand the problem. I have database "dialogs" with lots of listboxes (some of them carrying 1000's of items) and textboxes, etc. and see no "flash" when I clear (reset) and refill them. Need to se code that shows problem. What styles are you using for dialog + controls?

        Comment


        • #5
          First huge improvement came from turning off some tracing / debugging. Sometimes it is perfect, no flash just instant update. Other times there is a perceptible flash.
          I'm going to give this a try: "I would turn off the redraw, remove the items, and then reenable redraw."

          Click image for larger version

Name:	Snap23159.jpg
Views:	66
Size:	183.7 KB
ID:	796023

          Comment


          • #6
            Should be instant. Sometimes a simple SLEEP 0 before reset code can do wonders, like if system is busy doing other stuff at same time.

            Comment


            • #7
              Borje, listboxes are a little different since the all the strings being held by the listbox need to be deallocated and that can be a [relatively] slow process. (Assuming you are using the HASSTRINGS style).

              Frankly I'd be shocked if the DDT "LISTBOX RESET" statement does not simply generate a LB_RESETCONTENT messsage and that is how that works.

              But let us take heart from Mr. Clarke's commitment to "TRY" things rather than wait for some one to provide him a magic bullet!
              Michael Mattias
              Tal Systems Inc. (retired)
              Racine WI USA
              [email protected]
              http://www.talsystems.com

              Comment


              • #8
                This helped a lot (not that it was all that bad) SendMessage CONTROL_HANDLE_1, %WM_SETREDRAW, %FALSE, 0

                Code:
                FUNCTION DB_LOAD_ACCESS_GROUPS_LISTBOX(hDlg AS DWORD, LISTBOX_SOURCE AS LONG, LISTBOX_DESTINATION AS LONG)AS LONG
                
                LOCAL CONTROL_HANDLE_1 AS DWORD : CONTROL HANDLE LISTBOX_SOURCE , LISTBOX_SOURCE TO CONTROL_HANDLE_1
                LOCAL CONTROL_HANDLE_2 AS DWORD : CONTROL HANDLE LISTBOX_DESTINATION , LISTBOX_SOURCE TO CONTROL_HANDLE_2
                
                SendMessage CONTROL_HANDLE_1, %WM_SETREDRAW, %FALSE, 0
                SendMessage CONTROL_HANDLE_2, %WM_SETREDRAW, %FALSE, 0
                
                LISTBOX RESET hDlg, LISTBOX_SOURCE
                LISTBOX RESET hDlg, LISTBOX_DESTINATION
                
                SQL_Statement 1, 1, %SQL_STMT_IMMEDIATE, "SELECT * FROM AG_NAMES"
                DO
                  SQL_FetchResult (1,1, %NEXT_ROW)
                  MACRO_CHECK_FOR_SQL_ERROR
                  IF SQL_EndOfData(1, 1) THEN EXIT DO
                  LISTBOX ADD hDlg, LISTBOX_SOURCE, FORMAT$(SQL_ResColNumeric(1),"00") + CHR$(9) + SQL_ResColString(2)
                LOOP
                
                SendMessage CONTROL_HANDLE_1, %WM_SETREDRAW, %TRUE, 0
                SendMessage CONTROL_HANDLE_2, %WM_SETREDRAW, %TRUE, 0
                
                END FUNCTION

                Comment


                • #9
                  Yes, but computers are so fast these days. Wrapped up a quickie where 3 lists are filled with 10000 items, etc. using my old homebuildt dialog test designer and when clicking "Fill/Clear" button, I can see no flicker at all. So guess something else is going on at same time when David runs his code.
                  '
                  Code:
                  #COMPILE EXE
                  #DIM ALL
                  #INCLUDE "WIN32API.INC"
                  '--------------------------------------------------------------------
                  %IDC_TEXTBOX1       = 131
                  %IDC_TEXTBOX2       = 132
                  %IDC_TEXTBOX3       = 133
                  %IDC_TEXTBOX4       = 134
                  %IDC_TEXTBOX5       = 135
                  %IDC_TEXTBOX6       = 136
                  %IDC_LISTBOX1       = 161
                  %IDC_LISTBOX2       = 162
                  %IDC_LISTBOX3       = 163
                  
                  '====================================================================
                  FUNCTION PBMAIN () AS LONG
                    LOCAL hDlg AS DWORD
                  
                    DIALOG NEW 0, "Dialog1",,, 311, 148, %WS_CAPTION OR %WS_SYSMENU, 0 TO hDlg
                  
                    '------------------------------------------------------------------
                    CONTROL ADD LISTBOX, hDlg, %IDC_LISTBOX1, , 5, 5, 100, 40, _
                              %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %LBS_NOTIFY OR _
                              %LBS_NOINTEGRALHEIGHT, %WS_EX_CLIENTEDGE
                  
                    CONTROL ADD LISTBOX, hDlg, %IDC_LISTBOX2, , 5, 45, 100, 40, _
                              %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %LBS_NOTIFY OR _
                              %LBS_NOINTEGRALHEIGHT, %WS_EX_CLIENTEDGE
                  
                    CONTROL ADD LISTBOX, hDlg, %IDC_LISTBOX3, , 5, 85, 100, 40, _
                              %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %LBS_NOTIFY OR _
                              %LBS_NOINTEGRALHEIGHT, %WS_EX_CLIENTEDGE
                  
                    CONTROL ADD TEXTBOX, hDlg, %IDC_TEXTBOX1, "", 105, 5, 100, 40, _
                              %WS_CHILD OR %WS_VISIBLE OR %WS_VSCROLL OR %ES_MULTILINE OR _
                              %ES_WANTRETURN, %WS_EX_CLIENTEDGE
                  
                    CONTROL ADD TEXTBOX, hDlg, %IDC_TEXTBOX2, "", 105, 45, 100, 40, _
                              %WS_CHILD OR %WS_VISIBLE OR %WS_VSCROLL OR %ES_MULTILINE OR _
                              %ES_WANTRETURN, %WS_EX_CLIENTEDGE
                  
                    CONTROL ADD TEXTBOX, hDlg, %IDC_TEXTBOX3, "", 105, 85, 100, 40, _
                              %WS_CHILD OR %WS_VISIBLE OR %WS_VSCROLL OR %ES_MULTILINE OR _
                              %ES_WANTRETURN, %WS_EX_CLIENTEDGE
                  
                    CONTROL ADD TEXTBOX, hDlg, %IDC_TEXTBOX4, "", 205, 5, 100, 40, _
                              %WS_CHILD OR %WS_VISIBLE OR %WS_VSCROLL OR %ES_MULTILINE OR _
                              %ES_WANTRETURN, %WS_EX_CLIENTEDGE
                  
                    CONTROL ADD TEXTBOX, hDlg, %IDC_TEXTBOX5, "", 205, 45, 100, 40, _
                              %WS_CHILD OR %WS_VISIBLE OR %WS_VSCROLL OR %ES_MULTILINE OR _
                              %ES_WANTRETURN, %WS_EX_CLIENTEDGE
                  
                    CONTROL ADD TEXTBOX, hDlg, %IDC_TEXTBOX6, "", 205, 85, 100, 40, _
                              %WS_CHILD OR %WS_VISIBLE OR %WS_VSCROLL OR %ES_MULTILINE OR _
                              %ES_WANTRETURN, %WS_EX_CLIENTEDGE
                  
                    CONTROL ADD BUTTON, hDlg, %IDOK,     "Fill/Clear", 200, 130, 50, 14
                    CONTROL ADD BUTTON, hDlg, %IDCANCEL, "Exit",       255, 130, 50, 14
                  
                    '-------------------------------------------------------------------
                    DIALOG SHOW MODAL hDlg, CALL DlgProc
                  
                  END FUNCTION
                  
                  '======================================================================
                  CALLBACK FUNCTION DlgProc() AS LONG
                    LOCAL c AS LONG, sBuf AS STRING
                    STATIC iReset AS LONG
                  
                    SELECT CASE CB.MSG
                    CASE %WM_INITDIALOG
                        CONTROL POST CB.HNDL, %IDOK, %BM_CLICK, 0, 0
                  
                    CASE %WM_COMMAND
                        SELECT CASE CB.CTL
                        CASE %IDOK
                            IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN
                                iReset = 1-iReset
                                IF iReset THEN  ' Fill controls
                                    FOR c = 1 TO 10000
                                        LISTBOX ADD CB.HNDL, %IDC_LISTBOX1, "Some ListBox contents"
                                        LISTBOX ADD CB.HNDL, %IDC_LISTBOX2, "Some ListBox contents"
                                        LISTBOX ADD CB.HNDL, %IDC_LISTBOX3, "Some ListBox contents"
                                    NEXT
                                    sBuf = REPEAT$(100, "Some TextBox contents." + $CRLF)
                                ELSE  ' Clear controls
                                    LISTBOX RESET CB.HNDL, %IDC_LISTBOX1
                                    LISTBOX RESET CB.HNDL, %IDC_LISTBOX2
                                    LISTBOX RESET CB.HNDL, %IDC_LISTBOX3
                                    sBuf = ""
                                END IF
                                CONTROL SET TEXT CB.HNDL, %IDC_TEXTBOX1, sBuf
                                CONTROL SET TEXT CB.HNDL, %IDC_TEXTBOX2, sBuf
                                CONTROL SET TEXT CB.HNDL, %IDC_TEXTBOX3, sBuf
                                CONTROL SET TEXT CB.HNDL, %IDC_TEXTBOX4, sBuf
                                CONTROL SET TEXT CB.HNDL, %IDC_TEXTBOX5, sBuf
                                CONTROL SET TEXT CB.HNDL, %IDC_TEXTBOX6, sBuf
                              END IF
                  
                        CASE %IDCANCEL
                            IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN
                                DIALOG END CB.HNDL, 0
                            END IF
                        END SELECT
                  
                    END SELECT
                  
                  END FUNCTION
                  '

                  Comment


                  • #10
                    Ah, David - so you are refilling ListBox from other source. Then of course there can be delays that causes flicker and turning off redraw during refill will help.

                    Comment


                    • #11
                      RE:
                      Code:
                      SQL_Statement 1, 1, %SQL_STMT_IMMEDIATE, "SELECT * FROM AG_NAMES"
                      DO
                         SQL_FetchResult (1,1, %NEXT_ROW)
                         MACRO_CHECK_FOR_SQL_ERROR
                         IF SQL_EndOfData(1, 1) THEN EXIT DO
                         LISTBOX ADD hDlg, LISTBOX_SOURCE, FORMAT$(SQL_ResColNumeric(1),"00") + CHR$(9) + SQL_ResColString(2)
                      LOOP
                      Not that it matters, but why do you "SELECT *" when you are only using two columns? There IS an overhead associated with SELECTing all the unused columns (Not much, but non-zero!) Instead you can SELECT colA, colB from AG_NAMES

                      Or even... depending on your DB, you can get the SELECT Statement to handle all the formatting for you...
                      Code:
                        SELECT  STR(col_A)  ||  SYMBOL(9)  || STR (Col_B)  FROM AG_NAMES
                      ... will return one column with the tab character already inserted.

                      (Maybe it is not too late for that "All things Database" special interest group... which could include "Help with SQL" ) (???)


                      MCM
                      Michael Mattias
                      Tal Systems Inc. (retired)
                      Racine WI USA
                      [email protected]
                      http://www.talsystems.com

                      Comment


                      • #12
                        Do you have the wm_clipchildren style for each control?. Also, sometimes the non-client area may not freeze when turning off the drawing, possibly temporarily trap the WM_NCPAINT or WM_ERASEBKGND. Not tested, theory only.
                        Best regards
                        Jules
                        www.rpmarchildon.com

                        Comment


                        • #13
                          Ownerdrawn listboxes could probably solve ev. flicker. Instant view once item count is set..

                          Comment


                          • #14
                            Originally posted by David Clarke View Post
                            First huge improvement came from turning off some tracing / debugging. Sometimes it is perfect, no flash just instant update. Other times there is a perceptible flash.
                            I'm going to give this a try: "I would turn off the redraw, remove the items, and then reenable redraw."

                            Click image for larger version

Name:	Snap23159.jpg
Views:	66
Size:	183.7 KB
ID:	796023
                            BTW, I like your simplistic entry dialog!

                            This is how one of the products I supported looks like...

                            Click image for larger version

Name:	combine.jpg
Views:	67
Size:	74.9 KB
ID:	796046
                            Time Groups and Access Groups settings are small simple popups. (not shown)
                            Best regards
                            Jules
                            www.rpmarchildon.com

                            Comment


                            • #15
                              Thanks everybody!

                              Michael you are right about the Select * - that is only for development. Then I move to stored procedures and focus on making things clean and tight.

                              Thanks Jules - those "simple" dialogs can take days to make - frequently the look and feel drives the function which in turn drives the look and feel!
                              The other nice thing is each of those "zones" is a stand alone module, almost like a control, so "Select Users" can be used anyplace I need to select a user.
                              I do it with functions but they are candidates to become real objects.

                              Many Thanks to Borje who showed me how to do owner drawn listbox and opened my eyes to owner drawn!
                              "Ownerdrawn listboxes could probably solve ev. flicker. Instant view once item count is set.." Yes!


                              "Ah, David - so you are refilling ListBox from other source." Yes Database.


                              I don't mind things taking time to refill (local sql server is very fast) it is just the flash that can be jarring.

                              It is very acceptable now.

                              SendMessage CONTROL_HANDLE_1, %WM_SETREDRAW, %FALSE, 0 is nice!




                              Comment


                              • #16
                                SendMessage CONTROL_HANDLE_1, %WM_SETREDRAW, %FALSE, 0 is nice!
                                Use MACROs to make your life really easy. Here's what I have in y "skeleton" program:

                                Code:
                                MACRO Redraw_Off (hCtrl)
                                 SendMessage hCtrl, %WM_SETREDRAW, %FALSE, 0&
                                END MACRO
                                MACRO Redraw_On (hCtrl)
                                 SendMessage hCtrl, %WM_SETREDRAW, %TRUE, 0&
                                END MACRO
                                ===>

                                Code:
                                Redraw _On (hctl)
                                Redraw _Off (hctl)
                                IWH
                                Michael Mattias
                                Tal Systems Inc. (retired)
                                Racine WI USA
                                [email protected]
                                http://www.talsystems.com

                                Comment


                                • #17
                                  MACRO - Also an nice touch Michael.

                                  Comment

                                  Working...
                                  X