Weird rect.bottom value - FTL! - Download example

Pages: 12
I am going crazy again with a function that is supposed to retrieve the window size and position, relative to its parent control.
This is my 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
int window_props(HWND hwnd, int info) {
    RECT rect;
    int value = 0;
    GetClientRect(hwnd, &rect);

    switch (info) {
        case WIDTH:
            value = rect.right  - rect.left;
        break;
        case HEIGHT:
            value = rect.bottom - rect.top;
        break;
        case TOP:
            value = rect.top;
        break;
        case LEFT:
            value = rect.left;
        break;
        case BOTTOM:
            value = rect.bottom;
        break;
        case RIGHT:
            value = rect.right;
        break;
    }
    return value;
}


This is supposed to get me values each time I resize the window. I get the width and height correctly, when the window is maximized and also when it is resized. The problems comes when I am trying to get the bottom of the window. When the window is opened the value is correct. When it is resized I get very big values. Don't know what happens
Last edited on
I get the bottom of the parent control correctly (prect.bottom). rect.bottom is the only value that is wrong, and only when I resize the window (not when is created and maximized)
As I resize the window by sliding its border and making it smaller I get disproportional values to the size of the window (1022, 3565, 2344, etc.)
Last edited on
Can you post the code?
O.K.
The problem now is that I get the wrong bottom and right values only when I re-size the window by double-clicking on the top border or by clicking on the Maximize button. When I re-size the window by dragging its border it works fine.
O.K. I will put my code again because this is driving me crazy
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
70
71
72
73
74
75
76
77
78
// So, this is my WM_CREATE message of my window.
// Here I will create my controls

// This is main_panel, child of the main window.
// I get its bottom and right values correctly, no matter the way I re-size the window
main_panel = CreateWindowEx(
                      0, 
                      "STATIC", 
                      NULL, 
                      WS_CHILD|WS_VISIBLE|SS_BLACKFRAME, 
                      205, 0, 400, 600, 
                      hWnd, 
                      (HMENU)MAIN_PANEL, 
                      hInstance, 
                      NULL
                      );

// This is head_panel, child of main_panel, "grandchild" of the main window
// For this one I get the right and bottom values correctly, too
head_panel = CreateWindowEx(
                       0, 
                       "STATIC", 
                       NULL, 
                       WS_CHILD|WS_VISIBLE|WS_VSCROLL, 
                       5, 21, 390, 580, 
                       main_panel, 
                       (HMENU)HEAD_PANEL, 
                       hInstance, 
                       NULL
                       );

// I sub-classed this control, in order to get some messages that I don't get
// if they are sent to the main window's message handler

orig_hpanel_proc = (WNDPROC)SetWindowLong(head_panel, GWL_WNDPROC, (LONG)head_proc);

// Now, this is the control of which right and bottom 
// values are wrong when I re-size the window (not when the first re-sizing is made)

title_panel = CreateWindowEx(
                     0,
                     "STATIC",
                     "This is my title",
                     WS_VISIBLE|WS_CHILD,
                     5, 10, 300, 20,
                     head_panel,
                     (HMENU)TITLE_PANEL,
                     hInstance,
                     NULL
                     );

// So, I will place the function that gets me all the size and position information here 
int window_props(HWND hwnd, int info) {
    int value = 0;
    GetClientRect(hwnd, &rect);

    switch (info) {
        case WIDTH:
            value = rect.right - rect.left;
        break;
        case HEIGHT:
            value = rect.bottom - rect.top;
        break;
        case TOP:
            value = rect.top;
        break;
        case LEFT:
            value = rect.left;
        break;
        case BOTTOM:
            value = rect.bottom;
        break;
        case RIGHT:
            value = rect.right;
        break;
    }
    return value;
}


I repeat: any first-level and second-level control of the main window values are retrieved correctly. I get wrong bottom and right values only if the control is a third-level one, child of head_panel, which is sub-classed.
If there will be a third WW, you may know that it was me, 'cause I can't take it anymore.
Last edited on
Can't you just post the lot (or if it is too much then drop it on a pastebin site somewhere)
There are 2000 lines of code. I will post the WM_SIZE messages code of the main window messages handler and also for the head_panel (which is sub-classed) messages handler.

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
// WM_SIZE of the main window
case WM_SIZE:
            SendMessage(toolbar, TB_AUTOSIZE, 0, 0);
            toolbar_height = window_props(toolbar, HEIGHT);

            SendMessage(statusbar, WM_SIZE, 0, 0);
            status_height = window_props(statusbar, HEIGHT);

            statwidths[1] = window_props(main_window, WIDTH) - 180;
            SendMessage(statusbar, SB_SETPARTS, sizeof(statwidths)/sizeof(int), (LPARAM)statwidths);

            if (window_props(main_window, WIDTH)>600) {
                // Resize the main panel, it works fine
                MoveWindow(
                                     main_panel, 202, 
                                     toolbar_height, 
                                     window_props(main_window, WIDTH) - 383, 
                                     window_props(main_window, HEIGHT) - status_height - toolbar_height - 3, 
                                     true
                                     );
                // Resize the head_panel control, it works great
                MoveWindow(head_panel, 
                                      5, 
                                      21, 
                                      window_props(main_panel, WIDTH) - 6, 
                                      window_props(main_panel, HEIGHT) - 22, 
                                      true
                                      );
            }
            UpdateWindow(hWnd);
return 0;
break;


Now, this is the messages handler of the head_panel control
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
LRESULT CALLBACK head_proc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam){
    switch (Message) {
        case WM_CTLCOLORSTATIC:
            if((HWND)lParam == title_panel) SetTextColor((HDC)wParam, RGB(111, 63, 0));
            return (LONG)GetStockObject(WHITE_BRUSH);
        break;
        case WM_SIZE:
            if (place == 1) {
                 MoveWindow(title_panel, 
                                       5, 
                                       10, 
                                       window_props(main_panel, WIDTH) - 10,  
                                       text_lines(welc_label, 6) * 20,  // See this function below
                                       true
                                       );
            }
            return 0;
        break;
        default:
            return CallWindowProc(orig_hpanel_proc, hWnd, Message, wParam, lParam);
        break;
    }
}

// This function return the text lines of a control, depending on 
// the characters count, width and the control width
int text_lines(HWND hwnd, int fw) {
    int lines = 0;
    int len = GetWindowTextLength(hwnd);
    lines = ((len*fw)/window_props(hwnd, WIDTH)) + 1;
    return lines;
}
Last edited on
It seems like the problem comes from the fact that the size of the RECT object is calculated before the new size is applied to the controls.
When WM_SIZE happens, the actual size is taken into account, not the new one, after re-sizing the window. That is why, when dragging the window's border it works, but not when you maximize the window or make it normal by clicking on the top bar.
Last edited on
Glad to see you are still persevering..

(Also glad to see you changed your post to head_proc :- - I was fearing for your sanity.)

** Also, why does the head_proc function call like this:

return CallWindowProc(orig_tlb_proc, hWnd, Message, wParam, lParam);
when the original windows prodecure for the head_panel was saved to orig_hpanel_proc ??

Am I missing something here?? ***
Last edited on
Sorry about that. It was "orig_hpanel_proc"
There may be several causes:
1. The subclassing of head_panel
2. title_panel is a child of the child of the child of the main window (the great-grand son of the main window)

I think I will create a simple application just for this and post its code somewhere, so anybody could try it and see what happens. Just a moment. Tonight I will need a few tons of coffee and Red-Bull. Victory in life or honor in death!
Last edited on
O.K.
I simplified everything and you can get the entire project (I created it with CodeBlocks) at this link: http://www.devimperium.info/ResizeTest.zip

Try it on your computer and see the result. Remember: the problem is that the third-level controls are not re-sized and position correctly. See it by yourself and give me a solution, please.
Last edited on
Here is what I observe when I read your code and run the program

1. The title_panel and desc_panel all start at fixed widths and heights (fair enough I suppose).

2. When the head_panel gets resized, you resize the title_panel and desc_panel - BUT you make the widths of them relative to the main panel (The head panel is only marginally
less wide than the main_panel so you don't notice this error much.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
LRESULT CALLBACK hpanel_proc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam){
    SCROLLINFO si;
    int yPos;
    switch (Message) {
        case WM_CTLCOLORSTATIC:
            if((HWND)lParam == title_panel) SetTextColor((HDC)wParam, RGB(111, 63, 0));
            return (LONG)GetStockObject(WHITE_BRUSH);
        break;
        case WM_SIZE: //////////////////////////////************************************
//**  I,m positive  that in the next two lines the title and description window widths should be relative to the head_panel NOT the main panels as they are children of the head panel. ***//
                MoveWindow(title_panel, 5, 10, window_props(main_panel, WIDTH) - 10, text_lines(title_panel, 6) * 20, true);
                MoveWindow(desc_panel, 5, window_props(title_panel, BOTTOM) + 20, window_props(main_panel, WIDTH) - 30, text_lines(desc_panel, 6) * 12, true);
                UpdateWindow(hWnd);
            return 0;



3. What is WRONG is your calculation of the height that the description panel in particular
boxes need to be based on the text size.
1
2
3
4
5
6
int text_lines(HWND hwnd, int fw) {                                                                                    /* Gets control text lines  */
    int lines = 0;
    int len = GetWindowTextLength(hwnd);
    lines = ((len*fw)/window_props(hwnd, WIDTH)) + 1;
    return lines;
}

This is going to give the wrong number of lines in the calulation for the desc_panel - because
GetWindowTextLength will return 59 chars which is true in this program - BUT THE
TEXT CONTAINS 2 CARRIAGE RETURNS
"This is my description. \rThis is the second line. \rThis is the third line!",
so this text will always be printed on at least three lines - but your calculation will say only 1
line - which is why the desc_panel always looks like ugly and wrong.
Last edited on
23:45 in my country. Enough time to fix this

O.K.

If I take

1
2
MoveWindow(title_panel, 5, 10, window_props(main_panel, WIDTH) - 10, text_lines(title_panel, 6) * 20, true);
MoveWindow(desc_panel, 5, window_props(title_panel, BOTTOM) + 20, window_props(main_panel, WIDTH) - 30, text_lines(desc_panel, 6) * 12, true);


and place it into the WM_SIZE message of the main window nothing changes. Should I subclass the main_panel and re-size those two into the WM_SIZE of it?
I'll give it a try


This is going to give the wrong number of lines in the calulation for the desc_panel - because
GetWindowTextLength will return 59 chars which is true in this program - BUT THE
TEXT CONTAINS 2 CARRIAGE RETURNS
"This is my description. \rThis is the second line. \rThis is the third line!",
so this text will always be printed on at least three lines - but your calculation will say only 1
line - which is why the desc_panel always looks like ugly and wrong.


That's right. I will not use carriage return characters. I updated my code
Didn't work for the moment...
What I was saying is that the title and desc panesl are children of the head_panel, so
those two lines were fine in the windrowproc for the head_panel - but should read
1
2
MoveWindow(title_panel, 5, 10, window_props(head_panel, WIDTH) - 10, text_lines(title_panel, 6) * 20, true);
MoveWindow(desc_panel, 5, window_props(title_panel, BOTTOM) + 20, window_props(head_panel, WIDTH) - 30, text_lines(desc_panel, 6) * 12, true);




Now my question is:
How do you want the description panel to behave - when it's width changes do you want the height to recalulate to fit all the text ??
Last edited on
O.K. I get it. I modify the size of the control relative to its parent, not "grandfather" window.
The problem persists.

Now, I have taken five screen-shoots of my window states, when maximized, re-sized, re-sized by dragging the border. These are the links
http://www.devimperium.info/screen1.jpg
http://www.devimperium.info/screen2.jpg
http://www.devimperium.info/screen3.jpg
http://www.devimperium.info/screen4.jpg
http://www.devimperium.info/screen5.jpg
I'll go and try that..
I can't believe I didn't figure it out earlier -
there is an issue with the way (actually there is a problem with the timing) of the calulation of the
height (which is based on the number of lines) of the title and description windows.

A modification needs to be done in the WM_SIZE message of the head_panel window proc.


Here is the issue:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
LRESULT CALLBACK hpanel_proc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam){
    SCROLLINFO si;
    int yPos;
    switch (Message) {
        case WM_CTLCOLORSTATIC:
            if((HWND)lParam == title_panel) SetTextColor((HDC)wParam, RGB(111, 63, 0));
            return (LONG)GetStockObject(WHITE_BRUSH);
        break;
        case WM_SIZE:
                MoveWindow(title_panel, 5, 10, window_props(main_panel, WIDTH) - 10, text_lines(title_panel, 6) * 20, true);
                MoveWindow(desc_panel, 5, window_props(title_panel, BOTTOM) + 20, window_props(main_panel, WIDTH) - 30, text_lines(desc_panel, 6) * 12, true);
                UpdateWindow(hWnd);
            return 0;
        break;
        case WM_VSCROLL:
            si.nMin = 0;
            si.nMax = 


The MoveWindow function sets the NEW size of the windows - but the height you are passing as one of the parameters to MoveWindow is based on the CURRENT window width.

So the problem is you cannot set the window height until the width is set - one solution is to call the window function twice... (there are other solutions - like an additional text_line calulation
function that takes a window width value instead of a HWND ).
**Notice these windows are children of the head_panel - so their positions should be relative to that**

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
LRESULT CALLBACK hpanel_proc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam){
    SCROLLINFO si;
    int yPos;
    switch (Message) {
        case WM_CTLCOLORSTATIC:
            if((HWND)lParam == title_panel) SetTextColor((HDC)wParam, RGB(111, 63, 0));
            return (LONG)GetStockObject(WHITE_BRUSH);
        break;
        case WM_SIZE:
                
            MoveWindow(title_panel, 5, 10, window_props(head_panel, WIDTH) - 10, text_lines(title_panel, 6) * 20, false); //false on first call but I don't think it makes a lot of difference
            MoveWindow(title_panel, 5, 10, window_props(head_panel, WIDTH) - 10, text_lines(title_panel, 6) * 20, true);
                
            MoveWindow(desc_panel, 5, window_props(title_panel, BOTTOM) + 20, window_props(head_panel, WIDTH) - 30, text_lines(desc_panel, 6) * 12, false); //false on first call but I don't think it makes a lot of difference
            MoveWindow(desc_panel, 5, window_props(title_panel, BOTTOM) + 20, window_props(head_panel, WIDTH) - 30, text_lines(desc_panel, 6) * 12, true);

                UpdateWindow(hWnd);
            return 0;



The first call will set the new width (but the height will be incorrect) and the second call will
now set the correct height.

/******/
Another issue is here
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
            title_panel = CreateWindowEx(                                                                              /* Title panel creation     */
                                0,                                                                                     /* No extended style        */
                                "STATIC",                                                                              /* STATIC class             */
                                "This is the title of my application, a large one as you see",                         /* Some text                */
                                WS_VISIBLE|WS_CHILD,                                                                   /* Just a STATIC with text  */
                                5, 10, 380, 20,                                                                        /* Initial position & size  */
                                head_panel,                                                                            /* Parent is head_panel     */
                                (HMENU)TITLE_PANEL,                                                                    /* Control ID               */
                                hInstance,                                                                             /* The control's instance   */
                                NULL                                                                                   /* No lParam                */
                            );
            set_font(title_panel, 20, 6, true);                                                                        /* Set font height and width*/

            desc_panel = CreateWindowEx(                                                                               /* Title panel creation     */
                                0,                                                                                     /* No extended style        */
                                "STATIC",                                                                              /* STATIC class             */
                                "This is my description. This is the second line. This is the third line!",        /* Some text                */
                                WS_VISIBLE|WS_CHILD,                                                                   /* Just a STATIC with text  */
                                5, 30, 380, 100,                                                                       /* Initial position & size  */
                                head_panel,                                                                            /* Parent is head_panel     */
                                (HMENU)TITLE_PANEL,  /******YOU ARE USING THE ID OF THE TITLE PANEL***********/                                                                   /* Control ID               */
                                hInstance,                                                                             /* The control's instance   */
                                NULL                                                                                   /* No lParam                */
                            );



ALSO:
Global functions in header files - come on !
Last edited on
It is exactly what I have been trying to say in the ninth comment. I will implement this and see the result.

As related to the functions in the header file: in my real project, which has about 5000 lines of code, these function are stored in a DLL file. I just simplified the project and wrote those two functions in the header files in order to maintain the idea that they are in a separate place from the main.cpp file

Anyway, I know that I have to improve my code and there are a lot of things that must be changed to make it use less resources, give less errors and be easier to understand. For the moment I just wanna see that everything works, no matter what.
Last edited on
Pages: 12