65.9K
CodeProject 正在变化。 阅读更多。
Home

CMagDialog

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (12投票s)

2005 年 11 月 9 日

CPOL

3分钟阅读

viewsIcon

77814

downloadIcon

3377

CMagDialog:一个使对话框能够并排停靠的类。

Screenshot of demo application

引言

我开始编写这个类是因为我经常需要在主对话框周围弹出额外的对话框。通常,这些对话框会给用户带来一些麻烦;例如,他必须一个接一个地移动/关闭它们……一个可以使应用程序看起来更坚固,并且可以使各种窗口的管理更容易的解决方案是,将所有对话框并排停靠(例如,像 Winamp 那样)。

背景

首先:当我说父对话框时,我指的是主对话框,子对话框是可以停靠在父对话框上的对话框。我知道这不完全是 MS 赋予这些词的含义,但我无法想到更好的 ;) 类代码非常简单。我的所有工作都集中在两个方面:“磁场”管理,使对话框能够停靠,并避免在强制窗口停靠时出现闪烁(即,您在磁场内;))。第一个问题并不是真正的问题:我的解决方案是在父对话框周围构建四个矩形(每边一个);如果相应子窗口边缘的中心点位于矩形内,则子窗口将停靠。

这是代码的快照

//m_pMagParentDlg: pointer to parent window
//pRect: pointer to child window rect
//m_dwMagType: Type of dock (left,right,top,bottom or any side...)

m_pMagParentDlg->GetWindowRect(rectParent);

// Magnetic fields!
rectRight = CRect(rectParent.right-rHight,rectParent.top-rWidth,
     rectParent.right+rHight,rectParent.bottom+rWidth);
//Right magnetic field of parent dialog

curPl = CPoint(pRect->left, 
        pRect->top+(pRect->bottom-pRect->top)/2);
//center point of child's left edge

if ((m_dwMagType == DKDLG_RIGHT || m_dwMagType == DKDLG_ANY) && 

     rectRight.PtInRect(curPl))
{
   m_pMagParentDlg->DockMagneticDialog(this,DKDLG_RIGHT);
   nEdge        = DKDLG_RIGHT;    
   m_bDocked    = TRUE;
}

我花了一些时间来寻找解决第二个问题(避免闪烁)的方案。我想重现 Winamp 对话框的相同效果:进入父对话框“磁场”的子对话框将被推到停靠位置。此效果背后的代码很简单(一个MoveWindow就足够了……)。真正的问题是:将代码放在哪里?使用ON_WM_MOVING消息是不好的,因为此消息是在实际窗口移动之后发送的,因此产生的结果非常难看(比简单的闪烁还要糟糕!)。经过一番研究,我找到了要捕获的正确消息:ON_WM_WINDOWPOSCHANGING

此函数的原型是

void CMagDialog::OnWindowPosChanging(WINDOWPOS* lpwndpos)

其中lpwndpos是一个包含窗口将被移动到的坐标的结构。根据我的需要过滤这些坐标是关键。

void CMagDialog::OnWindowPosChanging(WINDOWPOS* lpwndpos)
{
    if ((m_bDocked) &  // This is a fix on movement... 
        (m_pMagParentDlg != NULL) &&
         // I need it only if the windows is docked
         // and I'm trying to move it:
        (m_bDisablePosFix == FALSE))
        // when this window is dragged
        // by parent window I don't need this fix
    {
      CRect tmpRect,rectParent;
      GetWindowRect(tmpRect);
      m_pMagParentDlg->GetWindowRect(rectParent);
      if (nEdge == DKDLG_RIGHT)
      {
        tmpRect.MoveToXY(rectParent.right,lpwndpos->y);
    
      }
    }

    lpwndpos->x  = tmpRect.left;
    lpwndpos->y  = tmpRect.top;
    lpwndpos->cx = tmpRect.Width();
    lpwndpos->cy = tmpRect.Height();

    CDialog::OnWindowPosChanging(lpwndpos);
    //commit changes
}

使用代码

要在您的项目中使用磁性对话框,只需从 CMagDialog 类派生父对话框和子对话框(请参阅背景部分关于的定义)。子对话框必须都是非模态对话框,并且应该在父对话框类中定义(当您在 DOC/View 架构中使用可停靠窗口时,也会发生同样的事情)。然后,您必须为每个子对话框在父对话框中调用 AddMagneticDialogEnableMagnetic 方法。

假设 m_MyMagDlg 是在父对话框类中声明的非模态对话框。OnInitDialog 将如下所示

BOOL CCMagTestDlg::OnInitDialog()
{
   //this child will pop up docked on right side of parent window
   AddMagneticDialog(&m_MyMagDlg,TRUE,DKDLG_RIGHT);
   //and can dock to any side
   m_MyMagDlg.EnableMagnetic(DKDLG_ANY,this);
   m_MyMagDlg.Create(IDD_DIALOG_LIBPREVIEW,this);
   return TRUE;
}

正如您在演示中看到的那样,该类还记得子对话框和父对话框之间的相对位置,因此,如果您关闭一个子对话框并移动父对话框,当您再次显示子对话框时,它将位于之前所处的相同相对位置。

概述

这些是 CMagDialog 的两个公共方法的定义

void AddMagneticDialog(CMagDialog* pDialog, 
         BOOL bDocked = FALSE,DWORD dwMagWhere =0);
  • PDialog - 指子对话框。
  • bDocked - 如果 true,则子窗口弹出窗口已经停靠。
  • dwMagWhere - 对话框停靠的位置;可以具有以下值
    • DKDLG_ANY
    • DKDLG_LEFT
    • DKDLG_RIGHT
    • DKDLG_TOP
    • DKDLG_BOTTOM
void EnableMagnetic(DWORD dwMagType,CMagDialog* pMagParentDlg);
  • dwMagType - 对话框可以停靠的位置;值与先前描述的 dwMagWhere 相同。
  • pMagParentDlg - 指向父对话框窗口的指针。

备注

dwMagWhere 指的是父窗口的侧面。因此,DKDLG_LEFT 意味着子窗口将停靠在父窗口的左侧。

历史

2005/11/07

  • 首次公开发布。

许可证

此程序/代码是免费的,并按“原样”提供,不提供任何明示或暗示的保证。 使用风险自负!

© . All rights reserved.