News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Creating custom splitter: CPU overhead and painting

Started by Ar0n, August 14, 2015, 08:38:15 AM

Previous topic - Next topic

Ar0n

Hello,
As the title says, I'm trying to create a simple splitter control, but for some reason I am experiencing problems of overhead and repainted. Could someone tell me why it happens and how to fix it...  :redface:
Simple project in attachments...



qWord


  • when start dragging, save the original x-position of the control and the current mouse position
  • whenever the mouse is moved, calculate the difference of x-coordinates for it
  • add that difference to the original x-position of the control to get the current control position
  • UpdateWindow is not needed, because SetWindowPos does redrawing as needed


.data

pt0 POINT <>
xorg SDWORD ?

.....

ControlWndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    LOCAL pt:POINT, rect1:RECT, rect2:RECT
   
   .IF uMsg==WM_LBUTTONDOWN
       
        invoke SetCapture,hWnd
       
        ; save mouse position
        invoke GetCursorPos,ADDR pt0
       
        ; calculate and save control position
        invoke GetWindowRect,hWnd,ADDR rect1
        invoke ScreenToClient,hMainWindow,ADDR rect1
        mrm xorg,rect1.left
       
    .ELSEIF uMsg==WM_LBUTTONUP
        invoke ReleaseCapture
    .ELSEIF uMsg==WM_MOUSEMOVE
        .IF wParam & MK_LBUTTON
           
            ; get current mouse position
            invoke GetCursorPos,ADDR pt
           
            invoke GetClientRect,hMainWindow,ADDR rect1
            invoke GetWindowRect,hWnd,ADDR rect2
           
            ; maximal x-coordinate of control
            ; = MainWindow.client_width - Control.width
            mov ecx,rect1.right
            mov eax,rect2.right
            sub eax,rect2.left
            sub ecx,eax
           
            ; delta_x (mouse)
            mov edx,pt.x
            sub edx,pt0.x
           
            ; new x-position = x_org + delta_x
            add edx,xorg
           
            ; the control should not go out of view
            .if SDWORD ptr edx < 0
            xor edx,edx
            .elseif SDWORD ptr edx >= ecx
            mov edx,ecx
            .endif
           
            invoke SetWindowPos, hWnd, 0, edx, 0, 0, 0, SWP_NOZORDER or SWP_NOSIZE
        .ENDIF
   .ELSE
      invoke DefWindowProc,hWnd,uMsg,wParam,lParam
      ret     
   .ENDIF
   xor eax,eax
   ret
ControlWndProc endp
MREAL macros - when you need floating point arithmetic while assembling!

dedndave

one thing that can drive your CPU usage up is....
you handle WM_PAINT without calling BeginPaint and EndPaint
when you call BeginPaint, the update region is "validated" (opposite of invalidate)
so, the OS continually sends WM_PAINT messages, thinking there is still a region that requires update

another thing i found, when using SetCapture is....
calling ReleaseCapture causes a WM_CAPTURECHANGED message to be sent
most of your actual release code should be handled in WM_CAPTURECHANGED

see the DivWin2 example attached to this post...
http://masm32.com/board/index.php?topic=2977.msg31084#msg31084

Ar0n

qWord, thanks for the help  :t

dedndave, nice example and helpful  :t btw, I think I'm not handling the WM_PAINT event... :-P

Ar0n

Hello guys, sorry for the double post, I was adding the code to my actual application but it seems to have problems. this happens when I drag it to the right:

Any idea?  :dazzled:

Simple project in attachments...  :redface:

Edited:
Project updated but still not working.

dedndave

i am running XP - and i see no listview - just a divider with white (i do see the text on the left)
this is probably because of the lack of a manifest and a call to InitCommonControlsEx

;8CCh = DS_CENTER or DS_MODALFRAME or DS_SETFONT or DS_FIXEDSYS or DS_3DLOOK

    invoke CreateWindowEx, WS_EX_WINDOWEDGE, addr SzWindowClass1, addr SzWindowClass1, \
    WS_VISIBLE or WS_POPUPWINDOW or WS_CLIPSIBLINGS or WS_DLGFRAME or WS_GROUP or 8CCh, \
    CW_USEDEFAULT, CW_USEDEFAULT, 600, 280, NULL, NULL, hPrevInst, NULL
    mov hMainWindow, eax
   
    invoke CreateWindowEx, 0, addr SzWindowClass2, NULL, WS_CHILD or WS_VISIBLE, \
    200, 0, SPLITTER_SIZE, 280, hMainWindow, NULL, hPrevInst, NULL
    mov hSplitter, eax


normally, WS_CLIPSIBLINGS is used on child windows only
and WS_CLIPCHILDREN is used on the parent window
i believe WS_GROUP is also a style used only with child windows

    .ELSEIF uMsg==WM_LBUTTONUP
        invoke ReleaseCapture


you have no code to perform the actual release (i.e. WM_CAPTURECHANGED)
i think this might need to be in the parent WndProc anyways
refer to the DivWin2 example i linked earlier

dedndave

in any case....
the effect you are seeing is due to the fact that the parent window is not being updated when the divider moves
i think moving the capture code to the parent WndProc can help fix that problem

Ar0n

thanks dedndave, I fixed that issue with Windows XP, as you said, it was InitCommonControls.  :t

It's curious but I solved the problem using InvalidateRect.  :biggrin: I'm not sure if it's the right way thou...
Added the project in case it is useful for someone else.