2

There is a CTreeCtrl in an arbitrary position on a fixed size CDialog. Could you please advice how to position this CTreeCtrl in OnInitDialog so that its left, right and bottom sides were touched to the dialog sides, and there was an indent N on top? I've been experimenting for several hours now, but it doesn't stick correctly to right and bottom:

CRect rect;
GetWindowRect(&rect);
rect.top = N;
m_Tree.MoveWindow(&rect);

I also tried GetClientRect.

I need to get the following:

enter image description here

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
ViH
  • 419
  • 2
  • 14
  • Try `GetClientRect` in place of `GetWindowRect` – Igor Tandetnik Jan 23 '22 at 13:56
  • I tryed it — same problem. – ViH Jan 23 '22 at 14:33
  • What problem? What outcome do you observe, and how does it differ from what you expect? What does `SetControlPosition` do? – Igor Tandetnik Jan 23 '22 at 14:37
  • Where **does** it end up, with `GetClientRect`? (Forget `GetWindowRect`, it's a wrong thing to use here and ain't gonna work.) Again, what does `SetControlPosition` look like? It's not a function provided by MFC, it's likely something you wrote. – Igor Tandetnik Jan 23 '22 at 14:45
  • Sorry, I've updated the question. – ViH Jan 23 '22 at 14:53
  • Can you show a screenshot of the resulting dialog, when using `GetClientRect` (and not `GetWindowRect`, which, for the third time, is a wrong function to use)? – Igor Tandetnik Jan 23 '22 at 14:57
  • The problem was an extra line of code that I forgot about. Thanks for your tips, they helped me find the bug. – ViH Jan 23 '22 at 15:19
  • 2
    MFC provides the infrastructure for [dynamic layout](https://learn.microsoft.com/en-us/cpp/mfc/dynamic-layout), if you don't feel like writing the layout code yourself. – IInspectable Jan 23 '22 at 15:25
  • @IInspectable That is what I immediately thought of so I added an answer. – Andrew Truckle Jan 23 '22 at 20:08

1 Answers1

2

By far the easiest solution in this case it to just use the inbuilt Dynamic Layout functionality:

enter image description here

  • Select the control in the IDE.
  • Set the Sizing Type property to Both.
  • Set Sizing X and Sizing Y to 100.

Then, as long as your dialog Border property is set to Resizing the tree control will stretch as you wanted:

enter image description here

No coding required as you can see:

enter image description here

Much easier!


Manual Method

But, if you do things manually you need to be sure that you understand what type of coordinates the API calls provide you. Coordinates can be relative:

  • Screen Coordinates
  • Client Coordinates

For example:

The dimensions are given in screen coordinates relative to the upper-left corner of the display screen. The dimensions of the caption, border, and scroll bars, if present, are included.

The client coordinates specify the upper-left and lower-right corners of the client area. Since client coordinates are relative to the upper-left corners of the CWnd client area, the coordinates of the upper-left corner are (0,0).

For a top-level CWnd object, the x and y parameters are relative to the upper-left corner of the screen. For a child CWnd object, they are relative to the upper-left corner of the parent window's client area.

Your tree control is a child so when you move it, the coordinates need to be relative to the upper-left corner of the parent window's client area.

Note, there is a handy CWnd::ScreenToClient API to translate from one system to the other. But this is not required in this instance.


Manual Method — Example

Putting it all together:

CRect rct;
GetClientRect(&rct);     // The client area of your window (in client coordinates)
rct.top += N;            // Adjust the top margin as required
myTree.MoveWindow(&rct); // Now move the child control

Please note that I have not debugged this to verify the code but it conveys the ideas.

Where possible I use the built in dynamic resizing, althought it can be very tricky to work out the sizing values. But in your case it is simple - 100.


I should point out that the above code will manually get it to the right place. But then you have to resize it as the window resizes. Try the Dynamic Layout approach instead.

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
  • 2
    Note that, besides being in screen coordinates, `GetWindowRect` returns the window rectangle including title and borders; the origin is the top-left corner of the window. Applying `ScreenToClient` on it would give you a rectangle with negative `top` and `left`, since the top-left corner of the window is at negative offsets from the top-left corner of the client area. If you want the rectangle of the client area, there's `GetClientRect`. It returns coordinates relative to the client area; in other words, `top` and `left` are always zero. – Igor Tandetnik Jan 24 '22 at 05:03
  • @IgorTandetnik I realise this. But usually if you want to move a control you want to move the whole thing. But of course, one is free to use GetClientRect. The principle still stands to be aware of what coordinates you are actually using. – Andrew Truckle Jan 24 '22 at 05:37
  • @IgorTandetnik Also, keep in mind we are talking about a control and not the actual window. So there should not be an issue in this case. But it is a valid thing to be aware of. Calling GetClientRect can be insufficient for moving a child control because it is not returning the full dimensions. IMHO. – Andrew Truckle Jan 25 '22 at 05:12
  • 1
    You would be calling `GetClientRect` on the parent window, not on the child. Recall that you are positioning the child control relative to the client area of its parent. `GetClientRect` is exactly what you want for this. `GetWindowRect` / `ScreenToClient` combo will give you a rectangle that's bigger than the client area and shifted up and to the left from the client area's origin - if you move the control to that rectangle, it'll be too big and its edges will be chopped off. – Igor Tandetnik Jan 25 '22 at 05:38
  • @IgorTandetnik I have revised my answer. Let me know if we can remove these comments. – Andrew Truckle Jan 25 '22 at 08:37