用VC++制作变形窗体
首先,我们要建立一个基于对话框的工程distort,这样生成了三个类,即CAboutDlg , CDistort , CDistortDlg ,我们将要进行大改动的是CDistortDlg类,因此我们给出此文件的原代码,有改动的地方 我们用粉色字表出,并加人注释。
// distortDlg.h : header file
//
#if !defined(AFX_DISTORTDLG_H__B21CDC69_5A48_11D7_A464_00055DE445C1__INCLUDED_)
#define AFX_DISTORTDLG_H__B21CDC69_5A48_11D7_A464_00055DE445C1__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// CDistortDlg dialog
class CDistortDlg : public CDialog
{
// Construction
public:
CDistortDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
{{AFX_DATA(CDistortDlg)
enum { IDD = IDD_DISTORT_DIALOG };
// NOTE: the ClassWizard will add data members here
}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CDistortDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
//{{AFX_MSG(CDistortDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
}}AFX_MSG
//重载 WM_NCTHITEST 消息,单激对话框任何部位都可移动对话框
afx_msg UINT OnNcHitTest(CPoint point);
//定时器,使窗体可以变形
afx_msg void OnTimer(UINT nIDEEvent);
//在撤销对话框时关闭定时器
afx_msg void OnDestroy();
DECLARE_MESSAGE_MAP()
private:
//窗体初始的矩形对象
CRect m_rectWnd;
//设置窗体所在区域
CRgn m_rgn;
};
{{AFX_INSERT_LOCATION}}
#endif // !defined(AFX_DISTORTDLG_H__B21CDC69_5A48_11D7_A464_00055DE445C1
__INCLUDED_)
下一步,我们先将对话框的属性中的stype设为popup ,而Border设为none,如图:
在此类的实现文件中,我们就将系统自动生成的函数略去了,只写出有改动的地方
// distortDlg.cpp : implementation file
//
#include "stdafx.h"
#include "distort.h"
#include "distortDlg.h"
#if def _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
///////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
//略去系统自动生成的类成员
......
//此处为消息宏映射
BEGIN_MESSAGE_MAP(CDistortDlg, CDialog)
{{AFX_MSG_MAP(CDistortDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_NCHITTEST()
ON_WM_TIMER()
}}AFX_MSG_MAP
END_MESSAGE_MAP()
//下面我们将要加入对话框程序一般都要重载的虚函数 OnInitDiolog(),它是消息响应函数,处理 //WM_INITDIALOG 消息
#define EVENT_REDRAW 0
BOOL CDistortDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
//获得对话框客户区的尺寸
GetClientRect(m_rectWnd);
//创建窗体对话框客户区的尺寸
m_rgn.CreateEllipticRgn(0,0,m_rectWnd.right,m_rectWnd.bottom);
//设置重画窗口定时器,每0.1秒重绘一次 SetWindowRgn((HRGN)m_rgn,TRUE);
this->SetTimer(EVENT_REDRAW,100,NULL);
//-------------------------set time----------------------------
return TRUE;
// return TRUE unless you set the focus to a control
其中椭圆效果是通过 int SetWindowRgn(HRGN hRgn,BOOL bRedraw);
而参数 hRgn 是窗体区的句柄, 参数 bRedraw 是决定是否要重画窗体,在本例中Windows 向窗体发送 WM_PAINT消息,从而调用 OnPaint()函数,
下面我们来修改此函数
void CDistortDlg::OnPaint()
{
CPaintDC dc(this);
if (IsIconic())
{
// device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
//add by myself---------------------------------------------------
dc.SelectStockObject(NULL_PEN);//绘制不带边的椭圆
//获得客户区的尺寸
CRect rect;
GetClientRect(rect);
CBrush *pBrushOld;
CBrush brushNew;
//定义画刷,在此你可以更改颜色
brushNew.CreateSolidBrush(RGB(204,255,66));
//选取画刷作为画图设备
pBrushOld=dc.SelectObject(&brushNew);
//绘制椭圆
dc.Ellipse(rect);
//还原画刷,并释放
dc.SelectObject(pBrushOld);
brushNew.DeleteObject();
}
}
//下面编写实现窗体任意托动的函数
HCURSOR CDistortDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
UINT CDistortDlg::OnNcHitTest(CPoint point)
{
UINT nHitTest=CDialog::OnNcHitTest(point);
return(nHitTest==HTCLIENT)?HTCAPTION:nHitTest;
}
//下面编写定时器实数
//若想结果n次变化后正好便为圆形,则设此值为 1.035
#define MULTI 1.1
void CDistortDlg::OnTimer(UINT nIDEvent)
{
static nCount=0;//窗体变化次数,每次增1
static bOrder=1;//表示变大或变小
static double dMulti=1;//窗体的变化倍数
CRect rectWnd;
CPoint ptMiddle,ptTopLeft,ptBtmRight;
//确定窗体区域中心
ptMiddle=m_rectWnd.CenterPoint();
//分情况处理各种定时事件
switch(nIDEvent)
{
case EVENT_REDRAW:
nCount++;
if(bOrder==1)
{//表示变大
dMulti*=MULTI;
}
else
{//表示变小
dMulti/=MULTI;
}
//确定窗体的矩形大小
ptTopLeft.x=(long)(ptMiddle.x-m_rectWnd.Width()/(2*dMulti));
ptTopLeft.y=(long)(ptMiddle.y-m_rectWnd.Height()/2);
ptBtmRight.x=(long)(ptMiddle.x+m_rectWnd.Width()/(2*dMulti));
ptBtmRight.y=(long)(ptMiddle.y+m_rectWnd.Height()/2);
rectWnd.SetRect(ptTopLeft,ptBtmRight);
//释放对象
m_rgn.Detach();
//创建椭圆区域
m_rgn.CreateEllipticRgn(ptTopLeft.x,ptTopLeft.y,ptBtmRight.x,ptBtmRight.y);
SetWindowRgn((HRGN)m_rgn,TRUE);
if(nCount==10)//设置变化次数,此为10次
{
nCount=0;
bOrder=(bOrder==1)?-1:1;//10次之后反向变化
}
break;
}
CDialog::OnTimer(nIDEvent);
}
最后的效果如图:
希望大家通过对本例的实践,初步了解 MFC 的对话框机制 (细节请参见《Vicual c++ 高级编程》)