Show/Hide controls in CDialog

I would like to place a button Hide Details on a CDialog derived dialog box which contains several controls. When the user presses the button, some of the controls are hidden and the dialog box is resized correspondingly. Button caption changes to Show Details. When the user presses the button, those hidden controls are shown and dialog box resizes back to original size.
For simplicity, you can assume that controls to hide take the whole line in the dialog so that the dialog is resized only vertically. At the same time, they are not necessarily located at the top or bottom of the dialog.
Please provide detailed code sample for showing/hiding controls and resizing dialog box on a button click event and OnInitDialog().
polyanovskyAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

AndyAinscowFreelance programmer / ConsultantCommented:
To show or hide
GetDlgItem(IDC_EDIT1)->ShowWindow(SW_SHOW);  //SW_HIDE

To resize
CRect rc;
GetWindowRect(&rc);
int iWidth = rc.Width();
int iHeight = rc.Height() - 30;  //make it 30 pixels smaller vertically
SetWindowPos(NULL, 0, 0, iWidth, iHeight, SWP_NOMOVE | SWP_NOZORDER);

You can use GetWindowRect and ScreenToClient to find the widht, height and position of any window.
0
polyanovskyAuthor Commented:
How would I calculate corresponding change in vertical size so that remaining controls are still spaced properly in vertical direction? Replacing 30 pixels in the example above with calculated value is the most difficult part of this question. You may assume that I know the highest top point and the lowest bottom point for controls in the line to hide. Then probably spacing from  controls above and below controls to hide should be taken into account.
0
AndyAinscowFreelance programmer / ConsultantCommented:
Say you have the following over three 'lines' in the dialog
A
B
C
and you want to hide line B.
Find the top of line B and the top of line C, the difference is what you need to move line C up and is also the reduction in height of the dialog.

(Trick - there is nothing to stop you having a hidden control of two to help with the sizing/moving. )
0
Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

polyanovskyAuthor Commented:
(Trick - there is nothing to stop you having a hidden control of two to help with the sizing/moving. )
I did not quite understand what you mean in this remark.
0
AndyAinscowFreelance programmer / ConsultantCommented:
A hidden control doesn't need to be moved - that can help when you are moving other controls and then later moving them back to the original location.
0
polyanovskyAuthor Commented:
Thanks. Actually, I have to move not only line C in the example above but all lines below line B. Is there any way to iterate through all dialog controls? Then I would shift up only controls whose top is below line B bottom.
0
AndyAinscowFreelance programmer / ConsultantCommented:
CWnd::GetWindow
use GW_CHILD to get the first then GW_HWNDNEXT inside a loop.  For each window found check if it need to be moved.
0
polyanovskyAuthor Commented:
Please give me a couple of days to implement this solution (I work on other projects too). If it works as expected I'll accept it.
0
AndyAinscowFreelance programmer / ConsultantCommented:
No problems
0
polyanovskyAuthor Commented:
Hidden controls overlap with shown controls so that when restoring them I have do distinguish between hidden and shown controls to move everything back properly. How could I do that?
0
AndyAinscowFreelance programmer / ConsultantCommented:
pWnd->IsWindowVisible();
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
polyanovskyAuthor Commented:
Here is complete solution for grateful future generations:
MyDlg
A
B
C
D
E
F
G

class CMyDlg: public CDialog
{
.....

private:
      void HideLine(CUIntArray&, int&);
      void ShowLine(CUIntArray&, int);
      void ResizeDialog(int);
      void ShowCtrls(CUIntArray&, int);
      void MoveCtrlsBelow(int, int, int);
      int GetShift(CRect);
      CUIntArray m_arrayCtrlsLineA;
      int m_iShiftLineA;
      int m_iShiftLineF;
      CUIntArray m_arrayCtrlsLineF;
      CRect GetLineRect(CUIntArray&);
      BOOL m_bHide;
}
BOOL CMyDlg::OnInitDialog()
{
      CWfDlg::OnInitDialog();
      .......
      m_arrayCtrlsLineA.Add(IDC_CHECK_LineA);
      m_arrayCtrlsLineA.Add(IDC_STATIC_LineA);
      m_arrayCtrlsLineA.Add(IDC_COMBO_LineA);
      m_arrayCtrlsLineF.Add(IDC_CHECK_LineF);
      m_arrayCtrlsLineF.Add(IDC_STATIC_LineF);
      m_arrayCtrlsLineF.Add(IDC_COMBO_LineF);
      return TRUE;  // return TRUE unless you set the focus to a control
                    // EXCEPTION: OCX Property Pages should return FALSE
}
void CMyDlg::OnButtonShowHideLines()
{
      // TODO: Add your control notification handler code here
      if(m_bHide)
      {
            HideLine(m_arrayCtrlsLineA,m_iShiftLineA);
            HideLine(m_arrayCtrlsLineF,m_iShiftLineF);
            m_bHide=FALSE;
      }
      else
      {
            ShowLine(m_arrayCtrlsLineA,m_iShiftLineA);
            ShowLine(m_arrayCtrlsLineF,m_iShiftLineF);
            m_bHide=TRUE;
      }
}

void CMyDlg::HideLine(CUIntArray& arrayCtrlIDs, int& iShift)
{
            CRect rc=GetLineRect(arrayCtrlIDs);
            iShift=GetShift(rc);
            ShowCtrls(arrayCtrlIDs,SW_HIDE);
            MoveCtrlsBelow(rc.bottom, -iShift, MOVE_VISIBLE|MOVE_HIDDEN);//move all up      
            ResizeDialog(-iShift);
}

void CMyDlg::ShowLine(CUIntArray& arrayCtrlIDs, int iShift)
{
            CRect rc=GetLineRect(arrayCtrlIDs);
            //here is the trik
            MoveCtrlsBelow(rc.top,iShift, MOVE_VISIBLE);//move visible down
            ShowCtrls(arrayCtrlIDs,SW_SHOW);//must be here
            MoveCtrlsBelow(rc.top,iShift, MOVE_HIDDEN);//move hidden down
            ResizeDialog(iShift);
}


CRect CMyDlg::GetLineRect(CUIntArray & arrayCtrlIDs)
{
  CRect rcLine;
  rcLine.top=rcLine.bottom=rcLine.left=rcLine.right=0;
  for(int i=0; i<arrayCtrlIDs.GetSize();++i)
  {
      CWnd* pWnd=GetDlgItem(arrayCtrlIDs.GetAt(i));
      if(!pWnd)
            continue;

      CRect rc;
      pWnd->GetWindowRect(rc);
      if(!rcLine.top||rc.top<rcLine.top)
            rcLine.top=rc.top;
      if(!rcLine.bottom||rc.bottom>rcLine.bottom)
            rcLine.bottom=rc.bottom;
      if(!rcLine.left||rc.left<rcLine.left)
            rcLine.left=rc.left;
      if(!rcLine.right||rc.right>rcLine.right)
            rcLine.right=rc.right;
  }
  return rcLine;
}

int CMyDlg::GetShift(CRect rcLine)
{
      CRect rc;
      GetWindowRect(rc);
      int iMinTop=rc.bottom;//dialog's bottom if there is no controls below
      CWnd* pWnd=GetWindow(GW_CHILD);
      while(pWnd)
      {
            pWnd->GetWindowRect(rc);
            
            if(rc.top>rcLine.bottom&&rc.top<iMinTop)//below the line but higher than other
                  iMinTop=rc.top;
                  
            pWnd=pWnd->GetWindow(GW_HWNDNEXT);  
      }

      return iMinTop-rcLine.top;
}

void CMyDlg::ShowCtrls(CUIntArray & arrayCtrlIDs, int iCmd)
{
      
  for(int i=0; i<arrayCtrlIDs.GetSize();++i)
  {
      CWnd* pWnd=GetDlgItem(arrayCtrlIDs.GetAt(i));
      if(!pWnd)
            continue;

      pWnd->ShowWindow(iCmd);  
  }
}

void CMyDlg::MoveCtrlsBelow(int iY, int iShift, int iType)
{
  //move everything below iY
    CRect rc;
    CWnd* pWnd;
      pWnd=GetWindow(GW_CHILD);
      while(pWnd)
      {
            pWnd->GetWindowRect(rc);
            if(rc.top>=iY&&(
                  ((iType&MOVE_VISIBLE)&&pWnd->IsWindowVisible())||
                  ((iType&MOVE_HIDDEN)&&!pWnd->IsWindowVisible())))
            {
                  ScreenToClient(rc);
                  rc.OffsetRect(0,iShift);
                  pWnd->MoveWindow(rc);
            }

            pWnd=pWnd->GetWindow(GW_HWNDNEXT);  
      }
}

void CMyDlg::ResizeDialog(int iShift)
{
  //resize dlg
      CRect rc;
      GetWindowRect(&rc);
      int iWidth = rc.Width();
      int iHeight = rc.Height() + iShift;  
      SetWindowPos(NULL, 0, 0, iWidth, iHeight, SWP_NOMOVE | SWP_NOZORDER);
      RedrawWindow();
}

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.