帮网友改一分程序,看了代码,大致就是让一个窗体自动地从椭圆变成圆,再从圆变为椭圆。
他设置了一个定时器,在定时器里每次会改变椭圆的长径,然后创建HRGN,设置HRGN。在OnPaint里,他对椭圆进行一些渲染工作。
  当他在OnTimer里,SetWindowRgn((HRGN)m_Rgn,TRUE);时,一切都没有问题。
  当改为SetWindowRgn((HRGN)m_Rgn,FALSE);   OnPaint();  显式调用重新绘制的函数时,窗体却不再改变大小了~~
  从二者的区别来看,首先,那个设置的区域肯定是在变化的,不然第一种情况就成功不了;其次, 经过我跟踪,OnPaint里的渲染代码是执行了的。
  那么,这个问题到底出在哪里?

解决方案 »

  1.   

    什么意思哦 ?  我干脆把他的代码贴出来好了,ShowMsg是我自己加的,用来调试用的
    // distortDlg.cpp : implementation file
    //#include "stdafx.h"
    #include "distort.h"
    #include "distortDlg.h"#ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endifvoid ShowMsg(HWND hWnd=NULL,CString msg="No Message!");
    /////////////////////////////////////////////////////////////////////////////
    // CAboutDlg dialog used for App Aboutclass CAboutDlg : public CDialog
    {
    public:
    CAboutDlg();// Dialog Data
    //{{AFX_DATA(CAboutDlg)
    enum { IDD = IDD_ABOUTBOX };
    //}}AFX_DATA // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CAboutDlg)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    //}}AFX_VIRTUAL// Implementation
    protected:
    //{{AFX_MSG(CAboutDlg)
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    };CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
    {
    //{{AFX_DATA_INIT(CAboutDlg)
    //}}AFX_DATA_INIT
    }void CAboutDlg::DoDataExchange(CDataExchange* pDX)
    {
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CAboutDlg)
    //}}AFX_DATA_MAP
    }BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
    //{{AFX_MSG_MAP(CAboutDlg)
    // No message handlers
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////
    // CDistortDlg dialogCDistortDlg::CDistortDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CDistortDlg::IDD, pParent)
    {
    //{{AFX_DATA_INIT(CDistortDlg)
    // NOTE: the ClassWizard will add member initialization here
    //}}AFX_DATA_INIT
    // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }void CDistortDlg::DoDataExchange(CDataExchange* pDX)
    {
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CDistortDlg)
    // NOTE: the ClassWizard will add DDX and DDV calls here
    //}}AFX_DATA_MAP
    }BEGIN_MESSAGE_MAP(CDistortDlg, CDialog)
    //{{AFX_MSG_MAP(CDistortDlg)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_WM_NCHITTEST()
    ON_WM_TIMER()
    ON_WM_DESTROY()
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////
    // CDistortDlg message handlers/*
    修改OnInitDialog函数建立一个椭圆区域
    并调用SetWindowRgn将该区域分配给窗口
    */
    // 定义定时器事件号
    #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); 
        SetWindowRgn((HRGN)m_rgn,TRUE);  // 设置重画窗口的定时器
    this->SetTimer(EVENT_REDRAW,500,NULL);

    return TRUE;  // return TRUE  unless you set the focus to a control
    }void CDistortDlg::OnSysCommand(UINT nID, LPARAM lParam)
    {
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
    CAboutDlg dlgAbout;
    dlgAbout.DoModal();
    }
    else
    {
    CDialog::OnSysCommand(nID, lParam);
    }
    }// If you add a minimize button to your dialog, you will need the code below
    //  to draw the icon.  For MFC applications using the document/view model,
    //  this is automatically done for you by the framework./*
    通过建立区域和调用SetWindowRgn,
    已经建立一个不规则形状的窗口,
    下面的例子程序是修改OnPaint函数使窗口形状看起来象一个球形体
      

  2.   

    */
    void CDistortDlg::OnPaint() 
    {
    CPaintDC dc(this); // device context for painting
    if (IsIconic())
    {
    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 {
    //AfxMessageBox("Draw ellipse");
    // 绘制一个不带边界的椭圆
    dc.SelectStockObject(NULL_PEN); // 获得窗口客户区的尺寸
    CRect rect; 
    GetClientRect(rect);
    //////////////////////////////////////


    //////////////////////////////////////
    CBrush *pBrushOld;     // 绘图设备所使用的“旧”画刷 
    CBrush brush; // 用来绘制椭圆的画刷 // 定义画刷 
    brush.CreateSolidBrush(RGB(0,0,255));

    // 选取画刷作为画图设备
    pBrushOld = dc.SelectObject(&brush); 

    // 绘制椭圆 
    dc.Ellipse(rect); 

    // 将画刷还原,并释放所用的画刷
    dc.SelectObject(pBrushOld);
    brush.DeleteObject();
    }
    }// The system calls this to obtain the cursor to display while the user drags
    //  the minimized window.
    HCURSOR CDistortDlg::OnQueryDragIcon()
    {
    return (HCURSOR)m_hIcon;
    }/*
    实现窗体的任意拖动
    */
    UINT CDistortDlg::OnNcHitTest(CPoint point) 
    {
    // TODO: Add your message handler code here and/or call default // 用户点击窗口任何地方时也能拖动窗口 
        UINT nHitTest = CDialog :: OnNcHitTest(point) ; 
        return (nHitTest == HTCLIENT) ? HTCAPTION : nHitTest ;
    }// 定义椭圆长轴变化的倍数
    #define MULTI 1.035/*
    定时时刻到了后,重新设置窗体区域
    */void CDistortDlg::OnTimer(UINT nIDEvent) 
    {
    // TODO: Add your message handler code here and/or call default
    static nCount = 0; // 窗体变化次数计数
    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) // bOrder为1表示窗体变大
    dMulti *= MULTI;
    else 
    dMulti /= MULTI; // 确定窗体所在区域的矩形大小
    ptTopLeft.x = ptMiddle.x - m_rectWnd.Width() / (2 * dMulti);
    ptTopLeft.y = ptMiddle.y - m_rectWnd.Height() / 2;
    ptBtmRight.x = ptMiddle.x + m_rectWnd.Width() / (2 * dMulti);
    ptBtmRight.y = ptMiddle.y + m_rectWnd.Height() / 2;
    rectWnd.SetRect(ptTopLeft,ptBtmRight);

    m_rgn.Detach(); // 释放区域对象,为下次创建作准备
    // 根据前面确定的矩形创建椭圆区域
    m_rgn.CreateEllipticRgn(ptTopLeft.x,ptTopLeft.y,ptBtmRight.x,ptBtmRight.y); 
    // 将窗体限制在该区域内,第二个参数取TRUE表示要重绘窗体
    //if(SetWindowRgn((HRGN)m_rgn,TRUE))
    //AfxMessageBox("Ko Ko");

    CString msg;
    msg.Format("left:%d  top:%d  right:%d  bottom:%d", ptTopLeft.x,ptTopLeft.y,ptBtmRight.x,ptBtmRight.y);
    ShowMsg(NULL,msg);

    SetWindowRgn((HRGN)m_rgn,FALSE);
    //SetWindowRgn((HRGN)m_rgn,TRUE);
    //OnPaint();

    if (nCount == 10) // 若已经经过了10此变化,则反向变化
    {
    nCount = 0;
    bOrder = (bOrder == 1) ? -1 : 1;
    }
    break;
    }
    CDialog::OnTimer(nIDEvent);
    }void CDistortDlg::OnDestroy() 
    {
    CDialog::OnDestroy();

    // TODO: Add your message handler code here

    }void CDistortDlg::zgc()
    { AfxMessageBox("CDistortDlg::zgc was called");
    CPaintDC dc(this); 
    dc.SelectStockObject(NULL_PEN); // 获得窗口客户区的尺寸
    CRect rect; 
    GetClientRect(rect); CBrush *pBrushOld;     // 绘图设备所使用的“旧”画刷 
    CBrush brush; // 用来绘制椭圆的画刷 // 定义画刷 
    brush.CreateSolidBrush(RGB(0,0,255));

    // 选取画刷作为画图设备
    pBrushOld = dc.SelectObject(&brush); 

    // 绘制椭圆 
    dc.Ellipse(rect); 

    // 将画刷还原,并释放所用的画刷
    dc.SelectObject(pBrushOld);
    brush.DeleteObject();
    }
    void ShowMsg(HWND hWnd,CString msg)
    {
    static bool bFirst=true; if(bFirst)
    {
    srand(GetTickCount());
    bFirst=false;
    }
    HDC hdc=GetDC(hWnd);
    HPEN hpen=CreatePen(PS_SOLID,100,RGB(255,255,255));
    SelectObject(hdc,hpen);
    MoveToEx(hdc,0,0,NULL);
    LineTo(hdc,180,0);
    SetTextColor(hdc,RGB(0,0,0));
    SetBkMode(hdc,TRANSPARENT);
    TextOut(hdc,0,0,msg,strlen(msg));
    DeleteObject(hpen);
    ReleaseDC(hWnd,hdc);
    }
      

  3.   

    重新绘制应使用::InvalidateRect(hDlg, NULL, TRUE);
      

  4.   

    OnPaint()是由消息调用的,不要自己调用。
      

  5.   

    自己调用了,就相当于SendMessage(...WM_PAINT了嘛~~只是那样的话 ,消息传递的要快些---WM_PAINT消息优先级别最低~~直接调用也不会有什么妨碍吧?何况~~谁能先把这个程序给搞定?  高手帮忙啊~~都贴了一天了~