现在很多软件都采用按钮调整工作区大小,使用起来十分方便,这里我自己设计了一个示例程序,与大家共享。
实现思路是:当我们单击按钮时,在按钮的单击响应函数中修改控件的位置和大小,从而达到调整的目的(如图所示),所以实现这个功能的核心是调节控件的位置和大小。
图1
图2
这里我采用了CWnd类的SetWindowPos()函数,使用该函数之前必须先获得控件的指针,我使用GetDlgItem()来做到这一点。两个函数的原型如下:
CWnd* GetDlgItem(int nID)const; |
返回值:指向给定控件或子窗口的指针;
参数:nID为控件或子窗口的ID值。
BOOL SetWindowPos(const CWnd* pWndInsertAfter,int x,int y,int cx,int cy,UINT nFlags); |
功能:改变窗口的大小、位置和Z次序;
参数:
第一个参数是改变窗口的Z次序,这里不用,可设为NULL;
x、y:窗口新位置;cx、cy:窗口新宽度和高度;
nFlags常用取值:
SWP_NOZORDER:忽略第一个参数;
SWP_NOMOVE:忽略x、y,维持位置不变,在只调整大小时使用;
SWP_NOSIZE:忽略cx、cy,维持大小不变,在只调整位置时使用;
这样,当需要重新设定某控件位置时,可采用:
CWnd *pWnd; //窗口指针,用于指向控件 pWnd = GetDlgItem( IDC_EDIT1 ); //获取控件指针,IDC_EDIT1为控件ID号 pWnd->SetWindowPos( NULL,x,y,0,0,SWP_NOZORDER | SWP_NOSIZE ); //把控件移到窗口的(x,y)处,大小不变 |
当需要重新设定某控件大小时,可采用:
pWnd = GetDlgItem( IDC_EDIT1 ); pWnd->SetWindowPos( NULL,0,0,cx,cy,SWP_NOZORDER | SWP_NOMOVE ); //把控件的大小改为(cx,cy),位置不变 |
当采用:
pWnd = GetDlgItem( IDC_EDIT1 ); pWnd->SetWindowPos( NULL,x,y,cx,cy,SWP_NOZORDER ); |
则控件的大小和位置都会改变。
我制作了一个基于对话框的示例程序,在对话框中,我放置了一个编辑控件(IDC_EDIT1)作为工作区,四个按钮控件放在编辑控件四周(如图1),按钮采用了自画的CPluckButton按钮。按钮的位置是通过计算设置的,所以在放置时只需把大小调整合适,位置可以随意放置。在编辑控件周围画了一个深颜色的圆角矩形背景把编辑控件与按钮整合在一起。当单击按钮控件时,我用上述方法调整编辑控件的大小和位置,同时调整按钮的位置并重画背景,这样工作区就得到调整。
在程序中,我设定了一组常量表示当前工作区的状态:
#define WS_NORMAL 0 #define WS_LEFT 1 #define WS_LEFT_UP 2 #define WS_LEFT_UP_RIGHT 3 #define WS_LEFT_UP_RIGHT_DOWN 4 #define WS_LEFT_DOWN 5 #define WS_LEFT_RIGHT_DOWN 6 #define WS_LEFT_UP_DOWN 7 #define WS_LEFT_RIGHT 8 #define WS_UP 9 #define WS_UP_RIGHT 10 #define WS_UP_RIGHT_DOWN 11 #define WS_UP_DOWN 12 #define WS_RIGHT 13 #define WS_RIGHT_DOWN 14 #define WS_DOWN 15 |
WS_NORMAL表示工作区为最初的正常状态(如图1),WS_LEFT表示工作区向左伸展,其余类推。(例如图2的工作区状态为WS_UP_RIGHT)。
另外,我定义了一个CRect数组m_Rect[16],存放编辑控件在不同状态下的位置,用一个变量m_start表示工作区的当前状态。数组值在初始化函数OnInitDialog()中计算出来:
BOOL CPluckBoxDlg::OnInitDialog() { CDialog::OnInitDialog(); ………… m_start = WS_NORMAL; //窗口初始状态(正常) CWnd *pWnd = GetDlgItem( IDC_EDIT1 ); //求编辑框尺寸和正常时的位置 pWnd->GetWindowRect( &m_Rect[WS_NORMAL] ); ScreenToClient( &m_Rect[WS_NORMAL] ); CRect m_ClientRect; this->GetClientRect( &m_ClientRect ); //获取客户区尺寸 //求各状态下工作区坐标: //工作区向左伸展 m_Rect[WS_LEFT].SetRect( 8, m_Rect[WS_NORMAL].top, m_Rect[WS_NORMAL].right, m_Rect[WS_NORMAL].bottom ); //工作区向左、向上伸展 m_Rect[WS_LEFT_UP].SetRect( 8, 8, m_Rect[WS_NORMAL].right, m_Rect[WS_NORMAL].bottom ); //工作区向左、向上、向右伸展 m_Rect[WS_LEFT_UP_RIGHT].SetRect( 8, 8, m_ClientRect.right-8, m_Rect[WS_NORMAL].bottom ); //工作区向四周伸展 m_Rect[WS_LEFT_UP_RIGHT_DOWN].SetRect( 8, 8, m_ClientRect.right-8, m_ClientRect.bottom-8 ); //工作区向下伸展 m_Rect[WS_LEFT_DOWN].SetRect( 8, m_Rect[WS_NORMAL].top, m_Rect[WS_NORMAL].right, m_ClientRect.bottom-8 ); //工作区向下、向右伸展 m_Rect[WS_LEFT_RIGHT_DOWN].SetRect( 8, m_Rect[WS_NORMAL].top, m_ClientRect.right-8, m_ClientRect.bottom-8 ); //工作区向下、向左、向右伸展 m_Rect[WS_LEFT_UP_DOWN].SetRect( 8, 8, m_Rect[WS_NORMAL].right, m_ClientRect.bottom-8 ); //工作区向左、向右伸展 m_Rect[WS_LEFT_RIGHT].SetRect( 8, m_Rect[WS_NORMAL].top, m_ClientRect.right-8, m_Rect[WS_NORMAL].bottom ); //工作区向上伸展 m_Rect[WS_UP].SetRect( m_Rect[WS_NORMAL].left, 8, m_Rect[WS_NORMAL].right, m_Rect[WS_NORMAL].bottom ); //工作区向上、向右伸展 m_Rect[WS_UP_RIGHT].SetRect( m_Rect[WS_NORMAL].left, 8, m_ClientRect.right-8, m_Rect[WS_NORMAL].bottom ); //工作区向上、向右、向下伸展 m_Rect[WS_UP_RIGHT_DOWN].SetRect( m_Rect[WS_NORMAL].left, 8, m_ClientRect.right-8, m_ClientRect.bottom-8 ); //工作区向上、向下伸展 m_Rect[WS_UP_DOWN].SetRect( m_Rect[WS_NORMAL].left, 8, m_Rect[WS_NORMAL].right, m_ClientRect.bottom-8 ); //工作区向右伸展 m_Rect[WS_RIGHT].SetRect( m_Rect[WS_NORMAL].left, m_Rect[WS_NORMAL].top, m_ClientRect.right-8, m_Rect[WS_NORMAL].bottom ); //工作区向右、向下伸展 m_Rect[WS_RIGHT_DOWN].SetRect( m_Rect[WS_NORMAL].left, m_Rect[WS_NORMAL].top, m_ClientRect.right-8, m_ClientRect.bottom-8 ); //工作区向下伸展 m_Rect[WS_DOWN].SetRect( m_Rect[WS_NORMAL].left, m_Rect[WS_NORMAL].top, m_Rect[WS_NORMAL].right, m_ClientRect.bottom-8 ); return TRUE; // return TRUE unless you set the focus to a control } |
在函数OnPaint()中,根据工作区状态调整编辑控件和按钮的位置:
void CPluckBoxDlg::OnPaint() { CPaintDC dc(this); // device context for painting ………… DrawWorkings(&dc); //绘制工作区 } |
其中DrawWorkings()函数为:
void CPluckBoxDlg::DrawWorkings(CPaintDC *pdc) { CWnd *pWnd = GetDlgItem( IDC_EDIT1 ); //调整编辑框位置 pWnd->SetWindowPos( NULL, m_Rect[m_start].left, m_Rect[m_start].top, m_Rect[m_start].Width(), m_Rect[m_start].Height(), SWP_NOZORDER ); CBrush Brush; //画深色边框 Brush.CreateSolidBrush( RGB(97,120,140) ); pdc->SelectObject( &Brush ); pdc->RoundRect(m_Rect[m_start].left-9, m_Rect[m_start].top-9, m_Rect[m_start].right+9, m_Rect[m_start].bottom+9, 10, 10 ); //以下根据编辑框坐标调整各按钮位置 pWnd = GetDlgItem( IDC_BUTTONLEFT ); //调整左边按钮位置 pWnd->SetWindowPos( NULL, m_Rect[m_start].left-9, m_Rect[m_start].CenterPoint().y-30, 0, 0, SWP_NOSIZE | SWP_NOZORDER ); pWnd = GetDlgItem( IDC_BUTTONUP ); //调整上边按钮位置 pWnd->SetWindowPos( NULL, m_Rect[m_start].CenterPoint().x-30, m_Rect[m_start].top-9, 0, 0, SWP_NOSIZE | SWP_NOZORDER ); pWnd = GetDlgItem( IDC_BUTTONRIGHT ); //调整右边按钮位置 pWnd->SetWindowPos( NULL, m_Rect[m_start].right, m_Rect[m_start].CenterPoint().y-30, 0, 0, SWP_NOSIZE | SWP_NOZORDER ); pWnd = GetDlgItem( IDC_BUTTONDOWN ); //调整下边按钮位置 pWnd->SetWindowPos( NULL, m_Rect[m_start].CenterPoint().x-30, m_Rect[m_start].bottom, 0, 0, SWP_NOSIZE | SWP_NOZORDER ); } |
OnPaint()函数在初建对话框和用Invalidate()函数刷新对话框时自动执行,所以在单击按钮时,先根据当前状态调整出新状态,再重绘对话框即可。
以下为按钮的单击响应函数:
//单击下边按钮
void CPluckBoxDlg::OnButtondown() { switch(m_start) //更改位置 { case WS_NORMAL: m_start = WS_DOWN; break; case WS_LEFT: m_start = WS_LEFT_DOWN; break; case WS_LEFT_UP: m_start = WS_LEFT_UP_DOWN; break; case WS_LEFT_UP_RIGHT: m_start = WS_LEFT_UP_RIGHT_DOWN; break; case WS_LEFT_UP_RIGHT_DOWN: m_start = WS_LEFT_UP_RIGHT; break; case WS_LEFT_DOWN: m_start = WS_LEFT; break; case WS_LEFT_RIGHT_DOWN: m_start = WS_LEFT_RIGHT; break; case WS_LEFT_UP_DOWN: m_start = WS_LEFT_UP; break; case WS_LEFT_RIGHT: m_start = WS_LEFT_RIGHT_DOWN; break; case WS_UP: m_start = WS_UP_DOWN; break; case WS_UP_RIGHT: m_start = WS_UP_RIGHT_DOWN; break; case WS_UP_RIGHT_DOWN: m_start = WS_UP_RIGHT; break; case WS_UP_DOWN: m_start = WS_UP; break; case WS_RIGHT: m_start = WS_RIGHT_DOWN; break; case WS_RIGHT_DOWN: m_start = WS_RIGHT;break; case WS_DOWN: m_start = WS_NORMAL; break; } Invalidate(); //重绘对话框 } |
//单击左边按钮
void CPluckBoxDlg::OnButtonleft() { switch(m_start) { case WS_NORMAL: m_start = WS_LEFT; break; case WS_LEFT: m_start = WS_NORMAL; break; case WS_LEFT_UP: m_start = WS_UP; break; case WS_LEFT_UP_RIGHT: m_start = WS_UP_RIGHT; break; case WS_LEFT_UP_RIGHT_DOWN: m_start = WS_UP_RIGHT_DOWN; break; case WS_LEFT_DOWN: m_start = WS_DOWN; break; case WS_LEFT_RIGHT_DOWN: m_start = WS_RIGHT_DOWN; break; case WS_LEFT_UP_DOWN: m_start = WS_UP_DOWN; break; case WS_LEFT_RIGHT: m_start = WS_RIGHT; break; case WS_UP: m_start = WS_LEFT_UP; break; case WS_UP_RIGHT: m_start = WS_LEFT_UP_RIGHT; break; case WS_UP_RIGHT_DOWN: m_start = WS_LEFT_UP_RIGHT_DOWN; break; case WS_UP_DOWN: m_start = WS_LEFT_UP_DOWN; break; case WS_RIGHT: m_start = WS_LEFT_RIGHT; break; case WS_RIGHT_DOWN: m_start = WS_LEFT_RIGHT_DOWN; break; case WS_DOWN: m_start = WS_LEFT_DOWN; break; } Invalidate(); } |
//单击右边按钮
void CPluckBoxDlg::OnButtonright() { switch(m_start) { case WS_NORMAL: m_start = WS_RIGHT; break; case WS_LEFT: m_start = WS_LEFT_RIGHT; break; case WS_LEFT_UP: m_start = WS_LEFT_UP_RIGHT; break; case WS_LEFT_UP_RIGHT: m_start = WS_LEFT_UP; break; case WS_LEFT_UP_RIGHT_DOWN: m_start = WS_LEFT_UP_DOWN; break; case WS_LEFT_DOWN: m_start = WS_LEFT_RIGHT_DOWN; break; case WS_LEFT_RIGHT_DOWN: m_start = WS_LEFT_DOWN; break; case WS_LEFT_UP_DOWN: m_start = WS_LEFT_UP_RIGHT_DOWN; break; case WS_LEFT_RIGHT: m_start = WS_LEFT; break; case WS_UP: m_start = WS_UP_RIGHT; break; case WS_UP_RIGHT: m_start = WS_UP; break; case WS_UP_RIGHT_DOWN: m_start = WS_UP_DOWN; break; case WS_UP_DOWN: m_start = WS_UP_RIGHT_DOWN; break; case WS_RIGHT: m_start = WS_NORMAL; break; case WS_RIGHT_DOWN: m_start = WS_DOWN; break; case WS_DOWN: m_start = WS_RIGHT_DOWN; break; } Invalidate(); } |
//单击上边按钮
void CPluckBoxDlg::OnButtonup() { switch(m_start) { case WS_NORMAL: m_start = WS_UP; break; case WS_LEFT: m_start = WS_LEFT_UP; break; case WS_LEFT_UP: m_start = WS_LEFT; break; case WS_LEFT_UP_RIGHT: m_start = WS_LEFT_RIGHT; break; case WS_LEFT_UP_RIGHT_DOWN: m_start = WS_LEFT_RIGHT_DOWN; break; case WS_LEFT_DOWN: m_start = WS_LEFT_UP_DOWN; break; case WS_LEFT_RIGHT_DOWN: m_start = WS_LEFT_UP_RIGHT_DOWN; break; case WS_LEFT_UP_DOWN: m_start = WS_LEFT_DOWN; break; case WS_LEFT_RIGHT: m_start = WS_LEFT_UP_RIGHT; break; case WS_UP: m_start = WS_NORMAL; break; case WS_UP_RIGHT: m_start = WS_RIGHT; break; case WS_UP_RIGHT_DOWN: m_start = WS_RIGHT_DOWN; break; case WS_UP_DOWN: m_start = WS_DOWN; break; case WS_RIGHT: m_start = WS_UP_RIGHT; break; case WS_RIGHT_DOWN: m_start = WS_UP_RIGHT_DOWN; break; case WS_DOWN: m_start = WS_UP_DOWN; break; } Invalidate(); } |
完整代码参见示例程序。
本文所用MFC函数速查:
CBrush::CreateSolidBrush
CDC::RoundRect
CDC::SelectObject
CRect::SetRect
CWnd::GetClientRect
CWnd::GetDlgItem
CWnd::GetWindowRect
CWnd::Invalidate
CWnd::ScreenToClient
CWnd::SetWindowPos
http://221.199.150.103/jsj/Html/vc/wen/vcwen06.htm