zoukankan      html  css  js  c++  java
  • 风火轮 – 飞入动画效果

    在动画基类的基础上,再实现各种动画效果,只需专注于各种逻辑实现,倒也不是太难的事。

    今天实现第二个动画效果-飞入。

    1. 飞入效果

    代码很少,因为只需要确定不同时间的位置,故只重载BuildDisplayRect:

    头文件

    /**

    * @class TCbwAnimationEffect_ FlyIn

    * @brief 动画基类

    *

    * 处理飞入动画效果

    * @author 陈斌文

    * @version 1.0

    * @date 2015-03-04

    * @QQ: 282397369

    */

    class TCbwAnimationEffect_FlyIn : public TCbwAnimationEffect { // 飞入

        typedef TCbwAnimationEffect inherited;

        virtual TRect __fastcall BuildDisplayRect(OBJECTMAT * m);

    public:

        __fastcall TCbwAnimationEffect_FlyIn();

        static TCbwAnimationEffect * Build();

    };

    然后实现:

    // ***************************** 飞入效果 **************************************

    __fastcall TCbwAnimationEffect_FlyIn::TCbwAnimationEffect_FlyIn()

        : TCbwAnimationEffect() {

        EffectType = cetFlyIn;

    }

    TCbwAnimationEffect * TCbwAnimationEffect_FlyIn::Build() {

        return new TCbwAnimationEffect_FlyIn;

    }

    // BuildDisplayRect是根据索引确定相应位置

    TRect __fastcall TCbwAnimationEffect_FlyIn::BuildDisplayRect(OBJECTMAT * m) {

        TPoint startPos(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;

        int x = startPos.x + (endPos.x - startPos.x) * (FCurrentIndex + 1)

            / FPeriodLength;

        int y = startPos.y + (endPos.y - startPos.y) * (FCurrentIndex + 1)

            / FPeriodLength;

        TRect result(x, y, x + m->Mat.cols, y + m->Mat.rows);

        return result;

    }

    // ***************************** 飞入效果 **************************************

    1. 界面处理

    现在到了处理界面的时候,因为在飞入效果中,还需要再设定效果选项。

    在选择对象的时候,可以再顺带判断是否有动画项,简化处理,当只有一个动画项的时候再进行编辑处理。

        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];

        return selectedEffectItems;

    }

    再通过SelectAnimationEffect(FCurrentEffectItem)完成界面按钮的控制。

    再深入研究下PPT中的动画项效果选项,发现其有两部分:固定的序列项,即作为一个对象、整批发送、按段落三个选项,其余为各动画项相应的属性项。

    因此,在基类中加入效果选项属性,100以内为相应选项,100: 作为一个对象,101:整批发送,102:按段落

        int EffectOptionType; // 效果选项,

    这样可以兼容所有效果选项(应该不会超过100项的吧)

    而各个类型的效果选项,可以硬编码实现,也可以配置实现。从灵活角度,当然是配置实现了,后续也有利于国际化语言包。

    void __fastcall TForm::SelectAnimationEffect(TCbwAnimationEffect * effectItem) {

        int index = -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];

                bool shouldBeSelected = (item->ImageIndex == index);

                if(item->Selected != shouldBeSelected)

                     item->Selected = shouldBeSelected;

            }

        }

        bool hasItemFlag = (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;

        UnicodeString basePath = THelper::File::GetApplicationPath() + effectNode->AttributeValueByName("path");

        UnicodeString cn = effectItem->ClassName();

        UnicodeString prefix = "TCbwAnimationEffect_";

        cn.Delete(1, prefix.Length());

        CbwXmlNode * destNode = effectNode->NodeByAttribute("name", cn);

        if(destNode) {

            for(int optionIndex = 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(int i = 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(int i = 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"));

            }

        }

    }

    配置文件大体如下,实现到哪个效果,再相应添加配置项:

    从网上再找相应的图标,放到reseffect目录下

    再加上相应的按钮处理

    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(int type) {

        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;

        RECT displayRect = 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;

        TRestore ApplicationCurrentStatus(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);

        }

        delete backData;

        delete FPreviewBitmap;

        delete bitmap;

    }

    这下可以看到效果:

    发现一个小小问题,点击各效果选项,效果选项的按钮图标没有相应改变。再花2分钟应该能解决。

    以后每天没事的时候,实现一两个PPT动画效果,貌似一个月能实现完成。

    在这之后,再实现潮流、跑马灯等效果,可以控制LED屏了,值得搞下。

  • 相关阅读:
    NodeJS3-1基础API----Path(路径)
    NodeJS2-6环境&调试----debug
    NodeJS2-5环境&调试----process(进程)
    NodeJS2-4环境&调试----global变量
    NodeJS2-3环境&调试----module.exports与exports的区别
    短视频秒播优化实践(二)
    短视频秒播优化实践(一)
    仿抖音上下滑动播放视频
    带着问题,再读ijkplayer源码
    上班一个月,后悔当初着急入职的选择了
  • 原文地址:https://www.cnblogs.com/drgraph/p/4313682.html
Copyright © 2011-2022 走看看