平滑,3D,iTunes风格的 图像列表控件CListCtrl-CAlbumCtrl类

翻译来源:https://www.codeproject.com/Articles/21006/Not-just-a-image-list-control-Neat-D-iTunes-style

作者:Ashok Jaiswal

图像列表控件显示3D中的所有图像,选择时动画化项目,并控制项目大小,透明度,位置和动画速度


下载AlbumViewerReleaseDemo.zip - 2,803.1 KB

下载AlbumViewerSrc.zip - 408.7 KB

截图 -  AlbumViewer.gif

介绍

灵感来自iTunes专辑列表控制。此图像列表控件允许您以新的3D方式显示图像。没有更无聊的图像一个接一个地显示,但附带一个很酷的动画。未选择项目的缩放级别可以是控件,也可以是阴影的高度,每个未选择项目的透明度,其位置和动画速度。

这对于在GUI丰富的应用程序中显示图像非常有用。控件是从CListCtrl类派生的,所以它可以被扩展,以支持传统的列表控件视图或者冷却动画3D视图。

背景

正如我提到的灵感是iTunes专辑控制。在这些变得越来越酷的周末之中,欣赏音乐,我想知道如何使用iTunes来平滑整洁的动画来显示图像,并采取了很好的控制,从而迎接挑战,发现它只需要大约10个代数方程,并且很好地利用了GDI +实现它。


此控件加载完整大小的图像,在演示中它使用的图像大到800x600,并通过高效使用GDI +,您可以动画,缩放和控制alpha,没有任何闪烁和非常顺利的方式。

这篇文章对于寻求有关使用GDI +绘画的更多信息的开发人员来说最有用。即使GDI +几乎需要所有的东西,但无法像iTunes一样绘制图像。它允许剪切图像,但不允许使图像的两侧的高度不同。我没有真正尝试使用矩阵变换,但我认为图像的动画和定位可以更好地使用它们。

使用代码

要在项目中使用控件,请添加AlubumCtrl.h和AlbumCtrl.cpp,在表单/对话框中添加列表控件,为类型为CAlbumCtrl的此列表控件创建一个成员变量,并在OnInitDialog或其他任何地方添加以下代码您要添加新项目到列表控件:
m_ctlAlbum.AddItem(L"images\\Water lilies.jpg");
m_ctlAlbum.AddItem(L"images\\Sunset.jpg");
m_ctlAlbum.AddItem(L"images\\Winter.jpg");
m_ctlAlbum.AddItem(L"images\\Blue hills.jpg");

m_ctlAlbum.SetCurrentItem(2);

m_sldAlpha.SetRange(0,100);
m_sldAnim.SetRange(0,100);
m_sldShadow.SetRange(0,100);
m_sldZoom.SetRange(0,100);
m_sldElevation.SetRange(-300,100);

m_sldElevation.SetPos(m_ctlAlbum.GetItemElevation());

m_sldAlpha.SetPos(m_ctlAlbum.GetItemAlpha());
m_sldAnim.SetPos(m_ctlAlbum.GetAnimSpeed());
m_sldShadow.SetPos(m_ctlAlbum.GetItemShadow());
m_sldZoom.SetPos(m_ctlAlbum.GetItemZoom());

计算项目位置

以下功能是放置控件和令人惊讶的最小代码部分的大多数导入功能。那么在它来到这之前,它确实需要大约4次迭代代码和代码的微调

RectF CAlbumCtrl::CalcItemRect(const int n, const RectF rcBase, bool bLeft)
{
    float r = m_fRatio;
    float p = pow(r,n);
    int h = rcBase.Height;
    int w = rcBase.Width;
    int y = 0;
    int x = 0;

    for(int j=1;j<=n;j++)
        y += (m_nItemY*h*pow(r,j))/100;

    if( bLeft )
    {

        int x = 0;
        for(int j=2;j<=n+1;j++)
            x += w*pow(r,j);

        return RectF(rcBase.X-x, rcBase.Y-y, w*p, h*p);
    }
        
    x = rcBase.X + w;

    for(int j=1;j<n;j++)
        x += w*pow(r,j);

    for(int j=1;j<n+1;j++)
        x -= (1-r)*w*pow(r,j);

    return RectF(x, rcBase.Y-y, w*p, h*p);
}

绘图项目

这是控制中第二重要的功能。这将拾取项目图像,计算阴影宽度,将alpha应用于图像,并将alpha减少到阴影,如果需要,将文本放置在所选图像上。

void CAlbumCtrl::DrawItem(const int nItem, RectF rc, Graphics &grf, float fAlpha, bool bDrawText)
{
    // centre image
    // draw the items only if they are inside the visible area
    // to keep repainting fast

    if( nItem < 0 || nItem > m_vecItems.size()-1 )
        return;

    Bitmap bitmap(m_vecItems[nItem].wszItem.c_str());

    CRect r;
    GetClientRect(&r);

    RectF rcWnd(r.left, r.top, r.Width(), r.Height());
    if(!rcWnd.IntersectsWith(rc))
        return;

    Bitmap     bmp(rc.Width, rc.Height, PixelFormat32bppARGB );

    Graphics graphic(&bmp);

    ImageAttributes imgAttrb;

    RectF rcDraw(0, 0, rc.Width, rc.Height);
    graphic.DrawImage(&bitmap, rcDraw, 0, 0, bitmap.GetWidth(), bitmap.GetHeight(), UnitPixel, &imgAttrb);

    graphic.DrawRectangle(&Pen(Color(80,80,80), 2),rcDraw);
    
    ColorMatrix bmpAlpha = {
                             1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
                             0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
                             0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
                             0.0f, 0.0f, 0.0f, fAlpha, 0.0f,
                             0.0f, 0.0f, 0.0f, 0.0f, 1.0f
                            };


    imgAttrb.SetColorMatrix(&bmpAlpha);
    grf.DrawImage(&bmp, rc, 0, 0, rc.Width, rc.Height, UnitPixel, &imgAttrb);

    int iHeight = bmp.GetHeight();
    int iWidth = bmp.GetWidth();

    // reflection percent

    if( !m_nItemShadow )
        m_nItemShadow = 1;

    float nRef = 100.0/m_nItemShadow;
    RectF rcRef = RectF(rc.X, rc.Y+rc.Height, rc.Width, rc.Height/nRef);
    Bitmap     bmpRef(rcDraw.Width, rcDraw.Height/nRef, PixelFormat32bppARGB );

    Color color, colorTemp;
    for(UINT iRow = iHeight; iRow > iHeight-iHeight/nRef; iRow--)
    {
       for(UINT iColumn = 0; iColumn < iWidth; iColumn++)
       {
           // decrease the alpha by 1 value for each line in bottom margin
           double dAlpha = (iHeight/nRef-(iHeight-iRow))*255/(iHeight/nRef);
          bmp.GetPixel(iColumn, iRow, &color);
          colorTemp.SetValue(color.MakeARGB(
             //(BYTE)(5*(iHeight/nRef-(iHeight-iRow))), 
             (BYTE)dAlpha,
             color.GetRed(),
             color.GetGreen(),
             color.GetBlue()));
          bmpRef.SetPixel(iColumn, iHeight-iRow, colorTemp);
       }
    }
    grf.DrawImage(&bmpRef, rcRef, 0, 0, rcRef.Width, rcRef.Height, 
    UnitPixel, &imgAttrb);
    if( bDrawText )
    {
        //wstring wszText = m_vecItems[nItem].wszItem; 
        //Font myFont(L"Tahoma",12,FontStyleRegular,UnitPixel);
        //
        //RectF rcText;
        //grf.MeasureString(wszText.c_str(), wszText.length(), &myFont, 
    // rcRef, &rcText);
        //grf.DrawString(wszText.c_str(),wszText.length(), &myFont, 
    // PointF(rcRef.X+rcRef.Width-rcText.Width-14, 
    // rcRef.Y+(rcRef.Height-rcText.Height)/2-rcText.Height), 
    // &SolidBrush(Color(255,255,255))); 
        //wchar_t temp[10];
        //wszText = _itow(nItem+1, temp, 10);
        //grf.DrawString(wszText.c_str(),wszText.length(), &myFont, 
    // PointF(rcRef.X+2, rcRef.Y+(rcRef.Height-rcText.Height)/2-rcText.Height), 
    // &SolidBrush(Color(255,255,255))); 
        //grf.DrawString(wszText.c_str(),wszText.length(), &myFont, 
    // PointF(rcRef.X, rcRef.Y), &SolidBrush(Color(255,255,255))); 
    }
}

幕后涉及数学

控制最感兴趣的部分是涉及定位和动画项目的数学。因为在中心选择项目的左侧和右侧放置/动画物品时存在不同的代数。

将项目置于控件中

计算任何项目的宽度

n  = W   r / 100  n

计算任何物品的高度

n = H  r / 100 n

计算任何项目的Y位置

n = Y - Ñ 
Σ
 1
H / e  r / 100 

计算所选项目左侧项目的X位置

n = X - 的n + 1 
Σ
 2
 r / 100 

计算所选项目右侧项目的X位置

n = X + W + n-1个
Σ
 1
 r / 100 i - 的n + 1 
Σ
 1
 1-r / 100  r / 100 

哪里

H =所选项目的高度

W =所选项目的宽度

X =所选项目的X位置

Y =所选项目的Y位置

r =当前缩放级别,以%

e = Y的当前高程


动画控件中的项目

动画向左的项目

动画左侧的项目

ΔX= c   X  n + 1  -X  n  / l 
n  = X  n  +ΔXΔY 

= c   Y  n + 1  -Y  n  / l 

n  = Y  n  + 


ΔYΔW= c   W  n + 1  -W  n  / 1 
n  = W  n  +ΔWΔH 

= c   H  n + 1  -H  n  / 1 
n  = H  n  +ΔH

动画右侧的物品

ΔX= c  X n + 1 -X n / 1 
n-1 = X n +ΔXΔY 

= c  Y n + 1 -Y n / 1 
n-1 = Y n -ΔY 

ΔW= c  W n + 1 -W n / l 
n = W n -ΔWΔH 

= c  H n + 1 -H n / 1 
n = H n -ΔH

动画物品向右移动

动画左侧的项目



ΔX= c  X n + 1 -X n / l 
n = X n +ΔXΔY 

= c  Y n + 1 -Y n / l 

n = Y n + 


ΔYΔW= c  W n + 1 -W n / 1 
n = W n +ΔWΔH 

= c  H n + 1 -H n / 1 
n = H n +ΔH

动画右侧的物品


ΔX= c  X n + 1 -X n / I 
n = X n +ΔXΔY 

= c  Y n + 1 -Y n / 1 
n = Y n - 

ΔYΔW= c  W n-1 -W n / 1 
n = W n -ΔWΔH 

= c  H n-1 -H n / 1 
n = H n -ΔH

哪里

c =当前动画步骤

l =总动画步数计数



未来特点

计划添加视图切换按钮,以便用户可以切换到图标视图/列表视图/报告视图/相册视图


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值