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

使用 DrawAnimatedRects() 函数

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.95/5 (9投票s)

2000 年 1 月 2 日

CPOL
viewsIcon

106497

downloadIcon

3169

展示如何使用 DrawAnimatedRects 函数来改善你的应用程序的外观。

引言

如果你查看 MS Word 并调用查找对话框,你可以看到一个简洁的动画。我希望模仿这个动画,然后发现了 DrawAnimatedRects() 函数。DrawAnimatedRects() 函数绘制一个线框矩形,并通过动画来指示图标的打开,或者窗口的最小化或最大化。语法如下

BOOL WINAPI DrawAnimatedRects(
  HWND hwnd,            // handle to clipping window
  int idAni,            // type of animation
  CONST RECT *lprcFrom, // rectangle coordinates (minimized)
  CONST RECT *lprcTo    // rectangle coordinates (restored)
);

lprcFrom 参数设置动画的起点,lprcTo 值设置动画的终点。例如,如果你希望使一个窗口看起来像是从一个按钮扩展到窗口,你可以将 lprcFrom 设置为按钮的尺寸,将 lprcTo 设置为最终窗口位置的尺寸。效果不如 MS Word 好,但如果任何 GUI 专家能够提供 MS Word 示例,那将非常有帮助。

使用该函数

示例应用程序展示了该函数的一个很好的用法。在演示中,关于框通过动画显示,使其看起来像是从对话框内部的一个按钮展开和折叠。

为了实现这一点,你只需在“关于框”对话框类中重写 OnCreateOnDestroy 函数,并在适当的位置添加对 DrawAnimatedRects() 的调用。

为了使事情简单,我们首先存储“关于框”将从其展开的按钮的尺寸。我们向“关于框”类添加一个成员变量 m_rectFrom,为了使“关于框”出现,我们使用以下方法。

    CAboutDlg about;
    m_ctlButton.GetWindowRect(about.m_rectFrom);
    about.DoModal();

其中 m_ctlButton 是“关于框”似乎要从其展开的按钮控件。

接下来,你需要在你的“关于框”类中添加对 OnCreateOnDestroy 的重写

int CAboutDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
    if (CDialog::OnCreate(lpCreateStruct) == -1)
        return -1;

    if (!m_rectFrom.IsRectEmpty())
    {
        CRect rectTo(lpCreateStruct->x,lpCreateStruct->y, 
            lpCreateStruct->x + lpCreateStruct->cx,
            lpCreateStruct->y + lpCreateStruct->cy);

        DrawAnimatedRects(m_hWnd, IDANI_CAPTION, m_rectFrom, rectTo);
    }

    return 0;
}

void CAboutDlg::OnDestroy() 
{
    CDialog::OnDestroy();
    if (!m_rectFrom.IsRectEmpty())
    {
        CRect rect;
        GetWindowRect(rect);
        DrawAnimatedRects(m_hWnd, IDANI_CAPTION, rect, m_rectFrom);
    }
}

这有效地在窗口本身出现之前或窗口消失之后绘制 Windows 动画序列。

就是这样!一个简单但有效的方法。


已更新: Norm Almond 提供了一些使用线框生成窗口爆炸/内爆效果的代码。他的函数的语法如下

void WINAPI DrawWireRects(LPRECT lprcFrom, LPRECT lprcTo, UINT nMilliSecSpeed)

lprcFrom 参数设置动画的起点,lprcTo 值设置动画的终点。nMilliSecSpeed 是每个线框显示之间的延迟时间(以毫秒为单位)(20 毫秒的值效果很好)。

////////////////////////////////////////////////////////////////////////////
//
// FUNCTION:    DrawWireRects
//
// DESCRIPTION: Creates exploding wire rectanges
//
// INPUTS:  LPRECT lprcFrom      Source Rectangle
//          LPRECT lprcTo        Destination Rectangle
//          UINT nMilliSecSpeed  Speed in millisecs for animation
//
// RETURN:    None
// NOTES:    None
//
//  Maintenance Log
//  Author      Date    Version     Notes
//  NT Almond   011199  1.0         Origin
//  CJ Maunder  010899  1.1         Modified rectangle transition code
//
/////////////////////////////////////////////////////////////////////////
void WINAPI DrawWireRects(LPRECT lprcFrom, LPRECT lprcTo, UINT nMilliSecSpeed)
{
    const int nNumSteps = 10;

    GdiFlush();
    Sleep(50);  // Let the desktop window sort itself out

    // if hwnd is null - "you have the CON".
    HDC hDC = ::GetDC(NULL);

    // Pen size, urmmm not too thick
    HPEN hPen = ::CreatePen(PS_SOLID, 2, RGB(0,0,0));

    int nMode = ::SetROP2(hDC, R2_NOT);
    HPEN hOldPen = (HPEN) ::SelectObject(hDC, hPen);

    for (int i = 0; i < nNumSteps; i++)
    {
        double dFraction = (double) i / (double) nNumSteps;

        RECT transition;
        transition.left   = lprcFrom->left + 
            (int)((lprcTo->left - lprcFrom->left) * dFraction);
        transition.right  = lprcFrom->right + 
            (int)((lprcTo->right - lprcFrom->right) * dFraction);
        transition.top    = lprcFrom->top + 
            (int)((lprcTo->top - lprcFrom->top) * dFraction);
        transition.bottom = lprcFrom->bottom + 
            (int)((lprcTo->bottom - lprcFrom->bottom) * dFraction);

        POINT pt[5];
        pt[0] = CPoint(transition.left, transition.top);
        pt[1] = CPoint(transition.right,transition.top);
        pt[2] = CPoint(transition.right,transition.bottom);
        pt[3] = CPoint(transition.left, transition.bottom);
        pt[4] = CPoint(transition.left, transition.top);

        // We use Polyline because we can determine our own pen size
        // Draw Sides
        ::Polyline(hDC,pt,5);

        GdiFlush();

        Sleep(nMilliSecSpeed);

        // UnDraw Sides
        ::Polyline(hDC,pt,5);

        GdiFlush();
    }

    ::SetROP2(hDC, nMode);
    ::SelectObject(hDC, hOldPen);

    ::ReleaseDC(NULL,hDC);
}

演示项目编号 1 包含此新代码。 Norm 还创建了一个类,该类是 演示项目编号 2 的一部分,演示了一个类 CZoomRect,该类可用于实现他更新的 Zoom Rect 代码。

要使用他的类,请包含 ZoomRect.h 头文件,创建一个 CZoomRect 对象并调用其 Draw() 方法

CRect rcStart(10,600,10,600);
CRect rcEnd(600,0,800,200);
int   nDelay = 10;

CZoomRect ZoomRect;
ZoomRect.Draw(NULL, rcStart, rcEnd, nDelay);

第一个参数是用于绘图的窗口句柄(或 NULL 用于桌面窗口),第二个和第三个是开始和目标矩形,最后一个是帧之间的延迟(以毫秒为单位)。


Michael Dunn 写道,关于 Word 97 的缩放轮廓效果,他记得很久以前一位同事提到过,早期版本的 Win 95(1994 年的版本)使用了相同的效果。它可能类似于 CE 2.0 在打开/关闭应用程序时的效果。

如果你查看 winuser.h,你会发现两个遗留常量 IDANI_OPENIDANI_CLOSE。第一个想法是将它们传递给 DrawAnimatedRects() 会产生缩放轮廓效果,但不幸的是,事实并非如此。 DrawAnimatedRects() 只有在你传递 IDANI_CAPTION 时才有效。

这更多地变成了一堂历史课,而不是一个解决方案 :),但我只是想传递这个花絮,以防你对其他两个 IDANI_* 常数感到好奇。

© . All rights reserved.