how do a calculation for scroolbars?

Aug 10, 2015 at 11:28am
we have the window size. we can add a child control to a position more big than size. i can calculate that size. so now i have 2 RECT's:
1
2
3
4
RECT window;
RECT childwindow;
GetClientRect(hwndwindow, &window);
GetClientRect(hwndchildwindow, &childwindow);

now we have the 2 windows sizes.
using the window styles, i can use WS_VSCROLL and WS_HSCROLL styles for add the scroolbars. using the GetScrollInfo() and SetScrollInfo() i can control the scroolbars values.
from that 2 RECTS, how can i calculate the scroolbar for get the nMax of the SCROLLINFO structure?(maybe we need minus the scroolbar size too)
Aug 11, 2015 at 12:33pm
i have almost done:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
class ChildWindows
{
private:
    vector<HWND> HwndChildWindows;
    BOOL EnumWindowsMethod( HWND hWnd )
    {
        HwndChildWindows.push_back( hWnd );
        return TRUE;
    }

    static BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam)
    {
        return reinterpret_cast <ChildWindows*> (lParam)->EnumWindowsMethod( hwnd );
    }
public:
    ChildWindows(HWND parent=ActivatedForm)
    {
        EnumChildWindows(parent, EnumChildProc, (LPARAM)this);
    }

    HWND& operator[](int index)
    {
        if(index>=HwndChildWindows.size())
        {
            index=HwndChildWindows.size()-1;
        }
        return HwndChildWindows[index];
    }

    int count()
    {
        return HwndChildWindows.size();
    }
};

POINT GetClientWindowSize(HWND Window=ActivatedForm)
{
    ChildWindows ahwndChildWindows;
    POINT ptSize{0,0};
    RECT rectparent, rectwindow;
    GetClientRect(Window,&rectparent);

    for(int i=0; i<ahwndChildWindows.count(); i++)
    {
        GetWindowRect(ahwndChildWindows[i],&rectwindow);
        ScreenToClient(Window,&rectwindow);
        if(rectwindow.bottom > rectparent.bottom)
        {
            ptSize.y=rectwindow.bottom;
        }

        if(rectwindow.right > rectparent.right)
        {
            ptSize.x=rectwindow.right;
        }
    }
    return ptSize;
}

when i click on a button:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
btnarray[5].MouseClick=[]()//button click
    {
        POINT ws=GetClientWindowSize();
        RECT rtcParent;
        GetClientRect(ActivatedForm,&rtcParent);
        DebugText((string)to_string(ws.y) + "\t" + to_string(rtcParent.bottom));
        if(ws.y>rtcParent.bottom)
        {
            SetWindowLong(ActivatedForm, GWL_STYLE,GetWindowLong(ActivatedForm, GWL_STYLE) | WS_VSCROLL);
            SCROLLINFO SCinfo;
            SCinfo.cbSize=sizeof(SCROLLINFO);
            SCinfo.fMask=SIF_RANGE;
            SCinfo.nMin =0;            
            if(ws.x>rtcParent.right)
                SCinfo.nMax =ws.y-rtcParent.bottom + GetSystemMetrics(SM_CXVSCROLL) ;
            else
                SCinfo.nMax =ws.y-rtcParent.bottom;
            SetScrollInfo(ActivatedForm,SB_VERT,&SCinfo, TRUE);
            DebugText(to_string(SCinfo.nMax));
        }
        if(ws.x>rtcParent.right)
        {
            SetWindowLong(ActivatedForm, GWL_STYLE,GetWindowLong(ActivatedForm, GWL_STYLE) | WS_HSCROLL);
            SCROLLINFO SCinfo;
            SCinfo.cbSize=sizeof(SCROLLINFO);
            SCinfo.fMask=SIF_RANGE;
            SCinfo.nMin =0;
            if(ws.y>rtcParent.bottom)
                SCinfo.nMax =ws.x-rtcParent.right + GetSystemMetrics(SM_CXHSCROLL) ;
            else
                SCinfo.nMax =ws.x-rtcParent.right;

            SetScrollInfo(ActivatedForm,SB_HORZ,&SCinfo, TRUE);
        }
        SetWindowPos(ActivatedForm,NULL,0,0,0,0,SWP_NOSIZE | SWP_NOZORDER | SWP_NOMOVE | SWP_DRAWFRAME);
    };

when the WM_VSCROLL is called:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
case WM_VSCROLL:
                {
                    static bool Vstops=false;
                    SCROLLINFO si;
                    ZeroMemory(&si, sizeof(si));
                    si.cbSize = sizeof(si);
                    si.fMask = SIF_ALL;
                    GetScrollInfo(inst->hwnd,SB_VERT, &si);//the nMax is 34, in these case

                    if( LOWORD(wParam)==SB_LINEDOWN && si.nPos<si.nMax)
                    {
                        SetScrollPos(inst->hwnd,SB_VERT, GetScrollPos(inst->hwnd,SB_VERT) +1,TRUE);
                        ScrollWindowEx(inst->hwnd,0,-1,NULL,NULL,NULL,NULL,SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE);
                    }
                    else if( LOWORD(wParam)==SB_LINEUP)
                    {
                        if(GetScrollPos(inst->hwnd,SB_VERT)>0)
                        {
                            SetScrollPos(inst->hwnd,SB_VERT, GetScrollPos(inst->hwnd,SB_VERT) -1,TRUE);
                            ScrollWindowEx(inst->hwnd,0,+1,NULL,NULL,NULL,NULL,SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE);
                        }
                    }
                    else if(LOWORD(wParam)==SB_THUMBPOSITION && Vstops==false)//when the user up the click
                    {
                        int thumbposition = HIWORD(wParam);
                        bool upthumb=(thumbposition<si.nPos);

                        SetScrollPos(inst->hwnd,SB_VERT, thumbposition,TRUE);

                        int newposition=0;

                        if(upthumb==false)
                        {
                            newposition= +si.nPos - thumbposition;
                        }
                        else
                        {
                            newposition =  si.nPos - thumbposition;
                        }
                        ScrollWindowEx(inst->hwnd,0,newposition,NULL,NULL,NULL,NULL,SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE);
                    }

                    else if(LOWORD(wParam)==SB_THUMBTRACK && Vstops==false)//while draggind
                    {
                        int thumbposition = HIWORD(wParam);
                        bool upthumb=(thumbposition<si.nPos);

                        SetScrollPos(inst->hwnd,SB_VERT, thumbposition,TRUE);

                        int newposition=0;

                        if(upthumb==false)
                        {
                            newposition= +si.nPos - thumbposition;
                        }
                        else
                        {
                            newposition =  si.nPos - thumbposition;
                        }
                        ScrollWindowEx(inst->hwnd,0,newposition,NULL,NULL,NULL,NULL,SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE);
                    }

                    else if(LOWORD(wParam)==SB_TOP && Vstops==false)
                    {
                        static int i=i+1;
                        SetWindowText(inst->hwnd,to_string(i).c_str());
                    }
                }
                break;

now works greate ;)
but i need more information for complete the code:
1 - what is the scrollbar notification or property\some strutucte member for when i click on shaft scrollbar section(between the thumb and the arrows buttons)?
2 - the scrollbars values must be changed:
1 - the window is sized;
2 - add\remove a child control;
3 - move or resize a child control.
can anyone advice me more about these?
(maybe for avoid several code and user handle messages)
Aug 12, 2015 at 10:09am
that code works. but i'm doing 1 important thing wrong that i don't understand correctly.
how can i calculate the nMax and nPage if they are dependent?
Aug 12, 2015 at 10:24am
how can i calculate the nMax and nPage if they are dependent?
What do you mean?

Max is usually the complete needed size for the graphics/text.
Page is usually the client window size.
Aug 12, 2015 at 10:38am
thanks for that.
when i use the SB_PAGEUP or SB_PAGEDOWN: the position is calculated: int thumbposition =si.nPos+si.nPage;
is these correct?
Aug 12, 2015 at 10:55am
The only difference between SB_LINE... and SB_PAGE... is the amount to scroll. Hence it should look alike. The SB_THUMB... doesn't apply.

Take a look at this:
1
2
3
4
5
6
7
8
                        if(upthumb==false)
                        {
                            newposition= +si.nPos - thumbposition; // How does this line
                        }
                        else
                        {
                            newposition =  si.nPos - thumbposition; // differ from the line above?
                        }
I'd say that you can omit the 'if(...)' in both cases.
Aug 12, 2015 at 11:12am
thanks for correct me that.
but the SB_PAGE isn't for use the nPage value?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
else if(LOWORD(wParam)==SB_PAGEDOWN)//when the user up the click
                    {
                        int thumbposition =si.nPos+si.nPage;
                        if(thumbposition>=si.nMax)
                            thumbposition=si.nMax;
                        SetScrollPos(inst->hwnd,SB_VERT, thumbposition,TRUE);
                        if(GetScrollPos(inst->hwnd,SB_VERT)==si.nMax)
                            ScrollWindowEx(inst->hwnd,0,-(si.nPos-si.nPage),NULL,NULL,NULL,NULL,SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE);
                        else
                            ScrollWindowEx(inst->hwnd,0,-si.nPage,NULL,NULL,NULL,NULL,SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE);
                    }

                    else if(LOWORD(wParam)==SB_PAGEUP)//when the user up the click
                    {
                        int thumbposition =si.nPos-si.nPage;
                        if(thumbposition<=0)
                            thumbposition=0;
                        SetScrollPos(inst->hwnd,SB_VERT, thumbposition,TRUE);
                        if(GetScrollPos(inst->hwnd,SB_VERT)==si.nMax)
                            ScrollWindowEx(inst->hwnd,0,+(si.nPos-si.nPage),NULL,NULL,NULL,NULL,SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE);
                        else
                            ScrollWindowEx(inst->hwnd,0,+si.nPage,NULL,NULL,NULL,NULL,SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE);
                    }
Aug 13, 2015 at 6:44pm
the SB_PAGE works fine.
now i'm having problems with SB_THUMBPOSITION and SB_THUMBTRACK...
while i draging the mouse the scroll is done. but when i release the mouse button, the thumb is positioned on back.. why? what i'm doing wrong?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
else if(LOWORD(wParam)==SB_THUMBPOSITION)//when the user up the click
                    {

                        int thumbposition =HIWORD(wParam);

                        //SetScrollPos(inst->hwnd,SB_VERT, thumbposition,TRUE);

                        int newposition=0;

                        newposition =  si.nPos - thumbposition;

                        //ScrollWindowEx(inst->hwnd,0,newposition,NULL,NULL,NULL,NULL,SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE);
                    }
                    else if(LOWORD(wParam)==SB_THUMBTRACK)//while draggind
                    {
                        int thumbposition = HIWORD(wParam);


                        SetScrollPos(inst->hwnd,SB_VERT, thumbposition,TRUE);

                        int newposition=0;

                        newposition =  si.nPos - thumbposition;

                        ScrollWindowEx(inst->hwnd,0,newposition,NULL,NULL,NULL,NULL,SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE);
                    }

can anyone explain to me what i'm doing wrong?
Aug 14, 2015 at 6:58am
Sorry, yes the SB_PAGE is ok.
The reason why I mentioned SB_LINE is that you usually scroll more than just a pixel. In that case the calculation would be the same. By the way, here is a simplified calculation:

Up:int scroll_amount = std::min(si.nPage, si.nPos);
Down:int scroll_amount = std::min(si.nPage, si.nMax - si.nPos);

the thumb is positioned on back.. why? what i'm doing wrong?
Line 23: thumbposition is already the new position, hence si.nPos - thumbposition is wrong.
Aug 14, 2015 at 9:06am
sorry the thumb position continues on back :(
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
else if(LOWORD(wParam)==SB_THUMBTRACK)//while draggind
                    {
                        int thumbposition =HIWORD(wParam);


                        SetScrollPos(inst->hwnd,SB_HORZ, thumbposition,TRUE);

                        int newposition=0;

                        newposition =  si.nPos - thumbposition;
                        ScrollWindowEx(inst->hwnd,si.nPos - thumbposition,0,NULL,NULL,NULL,NULL,SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE);


                    }
                    else if(LOWORD(wParam)==SB_THUMBPOSITION)//while draggind
                    {
                        int thumbposition =HIWORD(wParam) ;
                        SetScrollPos(inst->hwnd,SB_HORZ, thumbposition,TRUE);
                        ScrollWindowEx(inst->hwnd,si.nPos - thumbposition,0,NULL,NULL,NULL,NULL,SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE);
                    }
Aug 14, 2015 at 9:21am
Aug 14, 2015 at 9:47am
let me ask anotherthing(out of topic): on my form, i see 2 strange things:
1 - i mouve de mouse, on form border, until the cursor icon size been showed. i just click on it(just a mouse click). while i move the mouse, the form is resizing;
2 - when i mouse click on thumb button and release it after moving it, is like i continue doing the mouse click on thumb. why these behavior?
(the 2nd, fo course, can affect the scrolling)
Aug 14, 2015 at 10:52am
ok.. i was doing 1 error on my message loop. and now it's fixed. thanks for all
Aug 14, 2015 at 10:54am
give me 1 information that i don't know calculate it :(
think on nPos. the value is any place. now resize the window. how i know the wright position?
(ok the nPage and the nMax are changed correctly. that i have sure)
Aug 14, 2015 at 11:30am
Changing the size of the window does not affect the position. You just need to change the page size.

Take a look at other programs (like notepad or something). What happens to the scroll bar position if you change the size of the window?



2 - when i mouse click on thumb button and release it after moving it, is like i continue doing the mouse click on thumb. why these behavior?
This is usually lagging. I. e. the response to the event might be too slow.
Aug 14, 2015 at 11:39am
that problem was, too, from my message loop. now don't happens.
see these code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void setAutoScroll(bool autoscroll)
        {
            blnAutoScroll=autoscroll;
            if((GetWindowLong(hwnd,GWL_STYLE)& WS_VSCROLL))
            {
                SetWindowLong(hwnd,GWL_STYLE,GetWindowLong(hwnd,GWL_STYLE) &~WS_VSCROLL);
            }

            if((GetWindowLong(hwnd,GWL_STYLE)& WS_HSCROLL))
            {
                SetWindowLong(hwnd,GWL_STYLE,GetWindowLong(hwnd,GWL_STYLE) &~WS_HSCROLL);
            }

            if(blnAutoScroll==true)
            {
                POINT ws=GetClientWindowSize();
                RECT rtcParent;
                GetClientRect(hwnd,&rtcParent);
                if(ws.y>rtcParent.bottom)
                {
                    SetWindowLong(hwnd, GWL_STYLE,GetWindowLong(hwnd, GWL_STYLE) | WS_VSCROLL);
                    SCROLLINFO SCinfo;
                    SCinfo.cbSize=sizeof(SCROLLINFO);
                    SCinfo.fMask=SIF_RANGE | SIF_PAGE;
                    SCinfo.nMin =0;
                    SCinfo.nMax =ws.y;
                    SCinfo.nPage=rtcParent.bottom;
                    SetScrollInfo(hwnd,SB_VERT,&SCinfo, TRUE);
                }
                if(ws.x>rtcParent.right)
                {
                    SetWindowLong(hwnd, GWL_STYLE,GetWindowLong(hwnd, GWL_STYLE) | WS_HSCROLL);
                    SCROLLINFO SCinfo;
                    SCinfo.cbSize=sizeof(SCROLLINFO);
                    SCinfo.fMask=SIF_RANGE | SIF_PAGE;
                    SCinfo.nMin =0;
                    SCinfo.nMax =ws.x;
                    SCinfo.nPage=rtcParent.right;
                    SetScrollInfo(hwnd,SB_HORZ,&SCinfo, TRUE);
                }
            }
            SetWindowPos(hwnd,NULL,0,0,0,0,SWP_NOSIZE | SWP_NOZORDER | SWP_NOMOVE | SWP_DRAWFRAME);
        }

imagine that i change the nPos(in execute mode) to 1000. i resize the window. when i put both scrollbars to nMax, i can't see the last child control :(
Aug 14, 2015 at 4:12pm
i did a new test coder777. thanks for all.. .thank you. now works fine:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void setAutoScroll(bool autoscroll)
        {
            blnAutoScroll=autoscroll;
            if((GetWindowLong(hwnd,GWL_STYLE)& WS_VSCROLL))
            {
                SetWindowLong(hwnd,GWL_STYLE,GetWindowLong(hwnd,GWL_STYLE) &~WS_VSCROLL);
            }

            if((GetWindowLong(hwnd,GWL_STYLE)& WS_HSCROLL))
            {
                SetWindowLong(hwnd,GWL_STYLE,GetWindowLong(hwnd,GWL_STYLE) &~WS_HSCROLL);
            }

            if(blnAutoScroll==true)
            {
                POINT ws=GetClientWindowSize();
                RECT rtcParent;
                GetClientRect(hwnd,&rtcParent);
                if(ws.y>rtcParent.bottom)
                {
                    SetWindowLong(hwnd, GWL_STYLE,GetWindowLong(hwnd, GWL_STYLE) | WS_VSCROLL);
                    SCROLLINFO SCinfo;
                    SCinfo.cbSize=sizeof(SCROLLINFO);
                    SCinfo.fMask=SIF_RANGE | SIF_PAGE;
                    SCinfo.nMin =0;
                    SCinfo.nMax =ws.y;
                    SCinfo.nPage=rtcParent.bottom;
                    SetScrollInfo(hwnd,SB_VERT,&SCinfo, TRUE);
                }
                if(ws.x>rtcParent.right)
                {
                    SetWindowLong(hwnd, GWL_STYLE,GetWindowLong(hwnd, GWL_STYLE) | WS_HSCROLL);
                    SCROLLINFO SCinfo;
                    SCinfo.cbSize=sizeof(SCROLLINFO);
                    SCinfo.fMask=SIF_RANGE | SIF_PAGE;
                    SCinfo.nMin =0;
                    SCinfo.nMax =ws.x;
                    SCinfo.nPage=rtcParent.right;
                    SetScrollInfo(hwnd,SB_HORZ,&SCinfo, TRUE);
                }
            }
            SetWindowPos(hwnd,NULL,0,0,0,0,SWP_NOSIZE | SWP_NOZORDER | SWP_NOMOVE | SWP_DRAWFRAME);
        }

and parent resize:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//the WM_SIZING is for maximized
                case WM_SIZING:
                case WM_SIZE:
                {
                    if(inst->getAutoScroll()==true)
                    {
                        RECT a;
                        GetClientRect(inst->hwnd,&a);
                        SCROLLINFO SCinfo;
                        SCinfo.cbSize=sizeof(SCROLLINFO);
                        SCinfo.fMask=SIF_PAGE;
                        GetScrollInfo(inst->hwnd,SB_VERT,&SCinfo);
                        SCinfo.nPage=a.bottom;
                        SetScrollInfo(inst->hwnd,SB_VERT,&SCinfo, TRUE);
                        GetScrollInfo(inst->hwnd,SB_HORZ,&SCinfo);
                        SCinfo.nPage=a.right;
                        SetScrollInfo(inst->hwnd,SB_HORZ,&SCinfo, TRUE);
                    }
                    RECT a;
                    GetWindowRect(inst->hwnd,&a);
                    ScreenToClient(GetParent(inst->hwnd),&a);
                    InvalidateRect(inst->hwnd, &a,true);
                    inst->Resize();
                    return 0;
                }
                break;

now i came up with idea for save CPU :P
when i resize\position\add child control, i send a message(SendMessage() ) with it's handle(HWND) and see it's client rectangle for test the bottom\right with nMax or vertical\horizontal scrollbars.
thanks for all.
correct me these please:
can i use these const, in these way:
1
2
3
4
#define WM_GETCHILD (WM_USER+1)
#define WM_LOSECHILD (WM_USER+2)
#define WM_SIZECHILD (WM_USER+3)
#define WM_MOVECHILD (WM_USER+4) 

why i'm asking?
because the OS can use some of them and i don't know about it :(
Aug 17, 2015 at 6:21am
can i use these const, in these way:
Yes, read this:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms644931.aspx
Aug 17, 2015 at 10:21am
thanks for all
Topic archived. No new replies allowed.