From: nano on
Hi,


Good day.

When i develop my Start Bar feature.

I add the StatusBar to the bottom of my main window form.
When i change the main window size,
The status Bar can't move to the new position with my mouse action.

Could you please give me some suggestion

Thanks in advance.
==========================================

BOOL CMyAppDlg::OnInitDialog()
{
/////////////////////////////////// Move
Window ////////////////////////////////
int screenx = GetSystemMetrics(SM_CXSCREEN);
int screeny = GetSystemMetrics(SM_CYSCREEN);
screenx = screenx * 1/3;
screeny = screeny * 3/5;
int mainwndx = 500;
int mainwndy = 150;
MoveWindow(mainwndx, mainwndy, screenx, screeny);
GetWindowRect(m_mainPos);
CRect rect;
GetClientRect(&rect);

m_TreeCommand.MoveWindow(GetTreeRect(), TRUE);

m_bar.Create(this); //We create the status bar
m_bar.SetIndicators(indicators,2); //Set the number of panes
//Size the two panes
m_bar.SetPaneInfo(0,ID_INDICATOR_NISH,
SBPS_NORMAL,rect.Width()-100);
m_bar.SetPaneInfo(1,ID_INDICATOR_TIME,SBPS_STRETCH ,0);
//This is where we actually draw it on the screen
RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,
ID_INDICATOR_TIME);
//m_bar.GetStatusBarCtrl().SetBkColor(RGB(180,180,180));
m_bar.GetStatusBarCtrl().SetTimer(100,1000,NULL);

m_bar.MoveWindow(GetStatusBarRect(),TRUE);
}

==========================================

CRect CMyAppDlg::GetTreeRect()
{
CRect rect, rectHead;
GetClientRect(&rect);
rectHead.left = static_cast<int>(rect.left + rect.Width() * 0.02);
rectHead.top = static_cast<int>(rect.top + 95);
rectHead.right = static_cast<int>(rect.left + rect.Width() * 0.98);
//rectHead.bottom = static_cast<int>(rect.top + rect.Height() *
0.95);
rectHead.bottom = static_cast<int>(rect.bottom - 25);

return rectHead;
}

CRect CMyAppDlg::GetStatusBarRect()
{
CRect rect, rectHead;
GetClientRect(&rect);
rectHead.left = static_cast<int>(rect.left + rect.Width() * 0.02);
rectHead.top = static_cast<int>(rect.bottom - 25);
rectHead.right = static_cast<int>(rect.left + rect.Width() * 0.98);
rectHead.bottom = static_cast<int>(rect.bottom);
//rectHead.bottom = static_cast<int>(rect.top + 445);

return rectHead;
}


==========================================

void CMyAppDlg::OnSize(UINT nType, int cx, int cy)
{
if(m_bInit == true)
{


m_TreeCommand.MoveWindow(GetTreeRect(), TRUE);
//m_bar.MoveWindow(GetStatusBarRect(), TRUE); // when i
uncommented this line, will jumped out runtime error..
}
Invalidate();

CDialog::OnSize(nType, cx, cy);
if ( !IsWindowVisible() )
return;
}

==========================================
From: Joseph M. Newcomer on
See below...
On Mon, 26 Oct 2009 02:30:13 -0700 (PDT), nano <nano.he(a)gmail.com> wrote:

>Hi,
>
>
>Good day.
>
>When i develop my Start Bar feature.
>
>I add the StatusBar to the bottom of my main window form.
>When i change the main window size,
>The status Bar can't move to the new position with my mouse action.
>
>Could you please give me some suggestion
>
>Thanks in advance.
>==========================================
>
>BOOL CMyAppDlg::OnInitDialog()
>{
> /////////////////////////////////// Move
>Window ////////////////////////////////
> int screenx = GetSystemMetrics(SM_CXSCREEN);
> int screeny = GetSystemMetrics(SM_CYSCREEN);
****
I have no idea what this is intended for, because it cannot possibly work in a
multiple-monitor situation. If I want this in the second monitor, you have sized it to my
primary monitor. You should ask for the size of the monitor in which the application is
currently displayed. Which may not be the primary monitor.
****
> screenx = screenx * 1/3;
****
This turns out to say
screenx = 0;
****
> screeny = screeny * 3/5;
****
This turns out to say
screeny = 0;
Perhaps you meant to write
screenx = (screenx * 1) / 3;
screeny = (screeny * 3) / 5
or possibly
screenx = (int)((double)screenx * 1.0/3.0);
screeny = (int)((double)screeny * 3.0/5.0);
****
> int mainwndx = 500;
> int mainwndy = 150;
****
The choice of random numbers here seems a bit strange. Why do you think these numbers
have meaning on any machine but your own, this week, with your current settings, including
your current display, your current display driver, your current screen resolution, and
your current default font? They probably won't make sense on your machine next week if
you change any one of these parameters, and they certainly won't make sense on my machine,
which has two monitors, which run at two different resolutions, and which use a default
font somewhat larger than normal.
****
> MoveWindow(mainwndx, mainwndy, screenx, screeny);
> GetWindowRect(m_mainPos);
> CRect rect;
> GetClientRect(&rect);
>
> m_TreeCommand.MoveWindow(GetTreeRect(), TRUE);
>
> m_bar.Create(this); //We create the status bar
****
I see no test to validate this creation worked
****
> m_bar.SetIndicators(indicators,2); //Set the number of panes
****
m_bar.SetIndicators(indicators, _countof(indicators));
****
> //Size the two panes
> m_bar.SetPaneInfo(0,ID_INDICATOR_NISH,
> SBPS_NORMAL,rect.Width()-100);
****
Evert comma should be followed by a space to make parameter lists readable!

How is it that the semirandom number 100 is supposed to have meaning on my machine? It
may have meaning on your machine this week (see above).
****
> m_bar.SetPaneInfo(1,ID_INDICATOR_TIME,SBPS_STRETCH ,0);
> //This is where we actually draw it on the screen
> RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,
> ID_INDICATOR_TIME);
> //m_bar.GetStatusBarCtrl().SetBkColor(RGB(180,180,180));
> m_bar.GetStatusBarCtrl().SetTimer(100,1000,NULL);
****
Why are you setting a timer on the status bar? You have not shown that you have a derived
subclass of the status bar...in fact, you have not shown the declaration of m_bar at all!
****
>
> m_bar.MoveWindow(GetStatusBarRect(),TRUE);
>}
>
>==========================================
>
>CRect CMyAppDlg::GetTreeRect()
>{
> CRect rect, rectHead;
> GetClientRect(&rect);
> rectHead.left = static_cast<int>(rect.left + rect.Width() * 0.02);
> rectHead.top = static_cast<int>(rect.top + 95);
****
How does 95 have meaning?
****
> rectHead.right = static_cast<int>(rect.left + rect.Width() * 0.98);
> //rectHead.bottom = static_cast<int>(rect.top + rect.Height() *
>0.95);
> rectHead.bottom = static_cast<int>(rect.bottom - 25);
****
How does 25 have meaning? I see no place in the code that creates a status bar that
suggests or implies that its height is 25. If you want to eliminate the status bar size
from your area, you would first ask the status bar how high it is and subtract THAT value!
****
>
> return rectHead;
>}
>
>CRect CMyAppDlg::GetStatusBarRect()
>{
> CRect rect, rectHead;
> GetClientRect(&rect);
> rectHead.left = static_cast<int>(rect.left + rect.Width() * 0.02);
> rectHead.top = static_cast<int>(rect.bottom - 25);
> rectHead.right = static_cast<int>(rect.left + rect.Width() * 0.98);
> rectHead.bottom = static_cast<int>(rect.bottom);
> //rectHead.bottom = static_cast<int>(rect.top + 445);
****
Similar comments here. You are using "magic numbers" that have no meaning. How did you
determine 2% and 98% were meaningful values? What are 25 and 445 and how could they
possibly make sense? If I have a 1920-wide monitor, how does 2% translate into pixels (38
pixels). I can display this window as 2944 pixels wide (across two monitors) so why
should I have to deal with a 58-pixel border if I have a wide window? It doesn't make
sense to create values that can vary depending on the window size in such a situation. A
fixed border value would make sense. You can either use the client area (which takes the
window borders into account) or use a fixed size such as 2 * ::GetSystemMetrics(SM_CXEDGE)
which is computed based on the border sizes on a particular monitor environment and
therefore will make sense across many machines in many contexts.

Would it not make more sense to do
{
CRect rect;
GetClientRect(&rect);
CRect bar;
m_bar.GetWindowRect(&bar);
ScreenToClient(&bar);
rect.top = rect.bottom - bar.Height();
return rect;
}
Note that the client rect already takes into account the border thicknesses, so the 2%-98%
split is not necessary, and the position is merely the bottom of the client rect minus the
height of the bar. The *actual* height of the bar, not some random number (25) that may
or may not represent the height of the bar.

You would also be better served using SetWindowPos instead of MoveWindow since
SetWindowPos wants a width, height rather than absolute coordinates. I rarely write a
MoveWindow call, and have used them only infrequently in the last 20 years. Also,
SetWindowPos allows you to move without resizing and resize without moving, which is often
convenient (although you must do both to handle a status bar resize)
****
>
> return rectHead;
>}
>
>
>==========================================
>
>void CMyAppDlg::OnSize(UINT nType, int cx, int cy)
>{
> if(m_bInit == true)
****
I don't understand. If m_bInit is a BOOL (or bool), it is *already* true or false, so why
are you comparing it to true? You don't write
if( (a > 0) == true)
so why the unnecessary test here? You could write
if(m_bInit)
and it would be done!
> {
>
>
> m_TreeCommand.MoveWindow(GetTreeRect(), TRUE);
> //m_bar.MoveWindow(GetStatusBarRect(), TRUE); // when i
>uncommented this line, will jumped out runtime error..
> }
> Invalidate();
>
> CDialog::OnSize(nType, cx, cy);
> if ( !IsWindowVisible() )
> return;
***
Most of the above code is confused. The correct code would be
CDialog::OnSize(nType, cx, cy);

if(m_TreeCommand.GetSafeHwnd() != NULL)
{
m_TreeCommand.MoveWindow(GetTreeRect(), TRUE);
}
if(m_bar.GetSafeHwnd() != NULL)
{
m_bar.MoveWindow(GetStatusBarRect(), TRUE);
}
Conspicuous changes:
Do the CDialog::OnSize FIRST!
Testing validity of windows before attempting to use them!
No tests of visibility required since nothing happens anyway
No Invalidate() call because it is pointless
>}
>
>==========================================
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm