在动画基类的基础上,再实现各种动画效果,只需专注于各种逻辑实现,倒也不是太难的事。
今天实现第二个动画效果-飞入。
1. 飞入效果
代码很少,因为只需要确定不同时间的位置,故只重载BuildDisplayRect:
头文件
/**
*@class TCbwAnimationEffect_ FlyIn
*@brief 动画基类
*
* 处理飞入动画效果
*@author 陈斌文
*@version 1.0
*@date 2015-03-04
*@QQ: 282397369
*/
class TCbwAnimationEffect_FlyIn : publicTCbwAnimationEffect { // 飞入
typedefTCbwAnimationEffect inherited;
virtualTRect __fastcall BuildDisplayRect(OBJECTMAT * m);
public:
__fastcallTCbwAnimationEffect_FlyIn();
staticTCbwAnimationEffect * Build();
};
然后实现:
// ***************************** 飞入效果**************************************
__fastcallTCbwAnimationEffect_FlyIn::TCbwAnimationEffect_FlyIn()
:TCbwAnimationEffect() {
EffectType= cetFlyIn;
}
TCbwAnimationEffect *TCbwAnimationEffect_FlyIn::Build() {
returnnew TCbwAnimationEffect_FlyIn;
}
// BuildDisplayRect是根据索引确定相应位置
TRect __fastcallTCbwAnimationEffect_FlyIn::BuildDisplayRect(OBJECTMAT * m) {
TPointstartPos(m->LeftTopPosition.x, m->LeftTopPosition.y),
endPos(m->LeftTopPosition.x,m->LeftTopPosition.y);
if(cedFromBottom == EffectOptionType || cedFromLeftBottom == EffectOptionType ||
cedFromRightBottom== EffectOptionType) // 自底部
startPos.y= FHeight;
if(cedFromTop == EffectOptionType || cedFromLeftTop == EffectOptionType ||
cedFromRightTop== EffectOptionType) // 自顶部
startPos.y= -m->Mat.rows;
if(cedFromLeft == EffectOptionType || cedFromLeftBottom == EffectOptionType ||
cedFromLeftTop== EffectOptionType) // 自左侧
startPos.x= -m->Mat.cols;
if(cedFromRight == EffectOptionType || cedFromRightBottom == EffectOptionType ||
cedFromRightTop== EffectOptionType) // 自右侧
startPos.x= FWidth;
intx = startPos.x + (endPos.x - startPos.x) * (FCurrentIndex + 1)
/FPeriodLength;
inty = startPos.y + (endPos.y - startPos.y) * (FCurrentIndex + 1)
/FPeriodLength;
TRectresult(x, y, x + m->Mat.cols, y + m->Mat.rows);
returnresult;
}
// ***************************** 飞入效果**************************************
2. 界面处理
现在到了处理界面的时候,因为在飞入效果中,还需要再设定效果选项。
在选择对象的时候,可以再顺带判断是否有动画项,简化处理,当只有一个动画项的时候再进行编辑处理。
TCbwAnimationEffect* FCurrentEffectItem;
vector<TCbwAnimationEffect*> FAllAnimationEffects;
vector<TCbwAnimationEffect*> __fastcall GetSelectEffectItems();
////////////////////////////////////////////////////////////////////////////////////////
vector<TCbwAnimationEffect *>__fastcall TForm::GetSelectEffectItems() {
vector<TCbwAnimationEffect*> selectedEffectItems;
FCurrentEffectItem= NULL;
for(int i = 0; i < cSelectedObjects->MetaNumber; ++i) {
TCbwObject* object = cSelectedObjects->Meta(i);
CBW_ITERATOR(vector<TCbwAnimationEffect*>, FAllAnimationEffects)
if((*it)->ContainsObject(object)){
selectedEffectItems.push_back(*it);
break;
}
}
if(selectedEffectItems.size()== 1)
FCurrentEffectItem= selectedEffectItems[0];
returnselectedEffectItems;
}
再通过SelectAnimationEffect(FCurrentEffectItem)完成界面按钮的控制。
再深入研究下PPT中的动画项效果选项,发现其有两部分:固定的序列项,即作为一个对象、整批发送、按段落三个选项,其余为各动画项相应的属性项。
因此,在基类中加入效果选项属性,100以内为相应选项,100: 作为一个对象,101:整批发送,102:按段落
intEffectOptionType; // 效果选项,
这样可以兼容所有效果选项(应该不会超过100项的吧)
而各个类型的效果选项,可以硬编码实现,也可以配置实现。从灵活角度,当然是配置实现了,后续也有利于国际化语言包。
void __fastcall TForm::SelectAnimationEffect(TCbwAnimationEffect* effectItem) {
intindex = -1;
if(effectItem)
index= effectItem->EffectType - 1;
for(int i = 0; i < Gallery_FlashEffect->GalleryGroups->Count; ++i) { // 确保只添加一次
TdxRibbonGalleryGroup* group = Gallery_FlashEffect->GalleryGroups->Items[i];
for(int j = group->Items->Count - 1; j >= 0; --j) {
TdxRibbonGalleryGroupItem* item = group->Items->Items[j];
boolshouldBeSelected = (item->ImageIndex == index);
if(item->Selected!= shouldBeSelected)
item->Selected= shouldBeSelected;
}
}
boolhasItemFlag = (effectItem != NULL);
Button_Flash_Preview->Enabled= hasItemFlag;
Button_Flash_Effect->Enabled= hasItemFlag;
Button_Flash_Effect->ItemLinks->Clear();
if(!TGlobalVariables::XmlForStringResource|| !effectItem)
return;
CbwXmlNode* effectNode =TGlobalVariables::XmlForStringResource->RootNode->NodeByName("Effect",true);
if(!effectNode)
return;
UnicodeStringbasePath = THelper::File::GetApplicationPath() +effectNode->AttributeValueByName("path");
UnicodeStringcn = effectItem->ClassName();
UnicodeStringprefix = "TCbwAnimationEffect_";
cn.Delete(1,prefix.Length());
CbwXmlNode* destNode = effectNode->NodeByAttribute("name", cn);
if(destNode){
for(intoptionIndex = 0; optionIndex < destNode->ElementNumber; ++optionIndex) {
CbwXmlNode* optionNode = destNode->Elements(optionIndex);
TdxBarSeparator* sep = new TdxBarSeparator(Application->MainForm);
Button_Flash_Effect->ItemLinks->Add()->Item= sep;
sep->Caption= optionNode->AttributeValueByName("caption");
for(inti = 0; i < optionNode->ElementNumber; ++i) {
CbwXmlNode* itemNode = optionNode->Elements(i);
TdxBarButton* button = TCbwDevExp::CreateMenuItem(Button_Flash_Effect,
actEffect,itemNode->AttributeValueByName("caption"), i, true, false,
basePath+ itemNode->AttributeValueByName("glyph"));
}
}
}
CbwXmlNode* baseNode = effectNode->NodeByName("optionItem");
if(baseNode){
TdxBarSeparator* sep = new TdxBarSeparator(Application->MainForm);
Button_Flash_Effect->ItemLinks->Add()->Item= sep;
sep->Caption= baseNode->AttributeValueByName("caption");
for(inti = 0; i < baseNode->ElementNumber; ++i) {
if(i&& effectItem->RelativeObjectNumber() == 1) // 单个对象,只有一项
break;
CbwXmlNode* itemNode = baseNode->Elements(i);
TdxBarButton* button = TCbwDevExp::CreateMenuItem(Button_Flash_Effect,
actEffect,itemNode->AttributeValueByName("caption"), 100 + i, true, false,
basePath+ itemNode->AttributeValueByName("glyph"));
}
}
}
配置文件大体如下,实现到哪个效果,再相应添加配置项:
从网上再找相应的图标,放到res\effect目录下
再加上相应的按钮处理
void __fastcall TForm::Button_Flash_PreviewClick(TObject*Sender)
{
PreviewCurrentEffect();
}
//---------------------------------------------------------------------------
void __fastcall TForm::actEffectExecute(TObject*Sender)
{
int tag =THelper::Util::GetActionTag(Sender);
ChangeCurrentEffect(tag);
}
//---------------------------------------------------------------------------
void __fastcall TForm::ChangeCurrentEffect(inttype) {
if(!FCurrentEffectItem)
return;
FCurrentEffectItem->EffectOptionType= type;
PreviewCurrentEffect();
}
void __fastcall TForm::PreviewCurrentEffect(){
if(!FCurrentEffectItem)
return;
FCurrentEffectItem->RefreshAllObjects();
FCurrentEffectItem->SetBounds(ScrollBox->Width,ScrollBox->Height);
Graphics::TBitmap* bitmap = new Graphics::TBitmap; // bitmap将用于显示
bitmap->PixelFormat= pf24bit;
bitmap->Width= ScrollBox->Width;
bitmap->Height= ScrollBox->Height;
RECTdisplayRect = Rect(ScrollBox->HorzScrollBar->Position,
ScrollBox->VertScrollBar->Position,ScrollBox->HorzScrollBar->Position +
ScrollBox->Width,ScrollBox->VertScrollBar->Position +
ScrollBox->Height);
Graphics::TBitmap* FPreviewBitmap = new Graphics::TBitmap;
FPreviewBitmap->PixelFormat= pf24bit;
FPreviewBitmap->Width= PaintBox->Width;
FPreviewBitmap->Height= PaintBox->Height;
TCanvas* canvas = FPreviewBitmap->Canvas;
canvas->Rectangle(0,0, 10000, 10000);
CBW_ITERATOR(CbwObjects,Objects)(*it)->Canvas = canvas;
CBW_ITERATOR(CbwObjects,Objects) {
TCbwObject* object = *it;
if(!CanObjectBeVisible(object) || !object->CanContinueWithRect
(displayRect,CBW_CONTINUE_DRAW) || object->Selected)
continue;
object->Draw();
}
PostPaint(canvas);
bitmap->Canvas->CopyRect(Rect(0,0, bitmap->Width, bitmap->Height), canvas,
displayRect);
CBW_ITERATOR(CbwObjects,Objects)(*it)->Canvas = PaintBox->Canvas;
TRestoreApplicationCurrentStatus(TGraphApp::CurrentStatus, cfsAnimation);
BYTE* backData = THelper::Graphics::GetBitmapData(bitmap);
FCurrentEffectItem->First();
while(!FCurrentEffectItem->Eof){
FCurrentEffectItem->Draw(ScrollBox->Handle,backData, bitmap->Width, bitmap->Height);
FCurrentEffectItem->Next();
// THelper::Util::Delay(40);
Sleep(10);
}
deletebackData;
deleteFPreviewBitmap;
deletebitmap;
}
这下可以看到效果:
发现一个小小问题,点击各效果选项,效果选项的按钮图标没有相应改变。再花2分钟应该能解决。
以后每天没事的时候,实现一两个PPT动画效果,貌似一个月能实现完成。
在这之后,再实现潮流、跑马灯等效果,可以控制LED屏了,值得搞下。