您的位置:首页 > 其它

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

2017-06-20 18:43 549 查看
翻译来源: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






介绍

灵感来自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)));
}
}


幕后涉及数学

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


将项目置于控件中


计算任何项目的宽度

W n =
W ( r / 100 )n


计算任何物品的高度

H n =
H ( r / 100 )n


计算任何项目的Y位置

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


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

X n =
X -
的n + 1 
Σ
我 = 2
W ( r / 100 )


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

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


哪里
H =所选项目的高度
W =所选项目的宽度
X =所选项目的X位置
Y =所选项目的Y位置
r =当前缩放级别,以%
e = Y的当前高程




动画控件中的项目


动画向左的项目


动画左侧的项目

ΔX= c ( X n
+ 1 -X n) /

X n =
X n +ΔXΔY 

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


Y n =
Y n + 

ΔYΔW= c ( W n
+ 1 -W n) /

W n =
W n +ΔWΔH 

= c ( H n
+ 1 -H n) /

H n =
H n +ΔH


动画右侧的物品

ΔX= c ( X n
+ 1 -X n) /

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

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

Y n-1 =
Y n -ΔY 

ΔW= c ( W n
+ 1 -W n) /

W n =
W n -ΔWΔH 

= c ( H n
+ 1 -H n) /

H n =
H n -ΔH


动画物品向右移动


动画左侧的项目

ΔX= c ( X n
+ 1 -X n) /

X n =
X n +ΔXΔY 

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


Y n =
Y n + 

ΔYΔW= c ( W n
+ 1 -W n) /

W n =
W n +ΔWΔH 

= c ( H n
+ 1 -H n) /

H n =
H n +ΔH


动画右侧的物品

ΔX= c ( X n
+ 1 -X n) /

X n =
X n +ΔXΔY 

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

Y n =
Y n - 

ΔYΔW= c ( W n-1 -W n) /

W n =
W n -ΔWΔH 

= c ( H n-1 -H n) /

H n =
H n -ΔH
哪里
c =当前动画步骤
l =总动画步数计数



未来特点

计划添加视图切换按钮,以便用户可以切换到图标视图/列表视图/报告视图/相册视图
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: