wxWidgets 中的动画滑动面板/窗口

Posted

技术标签:

【中文标题】wxWidgets 中的动画滑动面板/窗口【英文标题】:Animating Sliding Panel/Window in wxWidgets 【发布时间】:2021-10-03 12:23:54 【问题描述】:

嗨,我有一个 wxWindow,它有两个箭头(左和右),中间有一个 wxPanel(附有屏幕截图)。现在,当用户单击右箭头按钮时,屏幕上显示的当前面板应该向左滑动,并且新的 wxPanel 应该从右侧出现并向左移动,以取代第一个 wxPanel .我附上了 4 个屏幕截图,显示了用户单击右箭头按钮后的中间阶段。类似地,当用户单击左箭头按钮但这次是相反的方向时。我知道如何创建箭头并赋予它点击功能,但我不知道如何在 wxWidgets 中为它设置动画,或者这种动画在 wxWidgets 中是否可行。

这是屏幕上最初显示的内容:

接下来当用户点击右箭头按钮时:

接下来 page1 仍在向左移动并离开屏幕,而 page2 从右侧进入屏幕但仍未占用完整空间。这是一个中间阶段:

最后 page2 取代了 page1。这是结束阶段。

请注意,当用户单击右箭头时,滑动动画应该需要一些时间,比如 0.5 秒或 1 秒,以便用户可以看到下一个面板滑动到屏幕中。

【问题讨论】:

那么你的问题是什么?如何做到这一点?另外,您是否考虑过用户可以单击滑动离开按钮这一事实。在这种情况下应该怎么办?我认为面板中有控件。如果用户单击箭头然后单击面板内应该滑开的控件会发生什么?这就是这种动画不受欢迎的原因。请重新考虑这样的设计并使用普通的向导/笔记本控件。或者只是按需隐藏/显示面板。 @Igor 用户不能点击 wxPanel 内正在移动(滑动)的任何东西。在我们的例子中,当显示 page1 并且假设用户尚未单击箭头按钮时,此时用户“可以”单击 page1 内的任何控件。但是当用户点击让我们说向右箭头的那一刻,我们首先禁用这个(page1)面板,然后动画才开始。这样,我们就不必担心用户是否点击了 wxPanel 内正在移动/滑开或进入屏幕的任何控件。 【参考方案1】:

我认为使用 wxWidgets,你能做的最好的就是用一个简单的书来模拟这个。这是一个例子:

#include "wx/wx.h"

#include <wx/simplebook.h>
#include <wx/spinctrl.h>

class MyFrame: public wxFrame

public:
    MyFrame();

private:
    void ChangePage(wxShowEffect);
    void SetLabel();

    wxSimplebook* m_simplebook;
    wxStaticText* m_pageIndicator;
;

MyFrame::MyFrame():wxFrame(NULL, wxID_ANY, "Sliding Demo", wxDefaultPosition,
             wxSize(400, 300))

    const int initialEffectTimout = 200;
    wxPanel* bg = new wxPanel(this,wxID_ANY);

    // Create the simple booka and add 3 dummy pages.
    m_simplebook = new wxSimplebook(bg,wxID_ANY);
    m_simplebook->SetEffectTimeout(initialEffectTimout);
    wxPanel* page1 = new wxPanel(m_simplebook,wxID_ANY);
    wxPanel* page2 = new wxPanel(m_simplebook,wxID_ANY);
    wxPanel* page3 = new wxPanel(m_simplebook,wxID_ANY);
    page1->SetBackgroundColour(*wxRED);
    page2->SetBackgroundColour(*wxGREEN);
    page3->SetBackgroundColour(*wxBLUE);
    m_simplebook->AddPage(page1,wxString());
    m_simplebook->AddPage(page2,wxString());
    m_simplebook->AddPage(page3,wxString());

    // create left and right arrows.
    wxButton* leftArrow = new wxButton(bg, wxID_ANY, wxUniChar(0x276E),
                               wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
    wxButton* rightArrow = new wxButton(bg, wxID_ANY, wxUniChar(0x276F),
                               wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);

    // create the label for the page indicator.
    m_pageIndicator = new wxStaticText(bg,wxID_ANY,wxString());
    SetLabel();

    // add a spin control to change the duration of the slide animation.
    wxStaticText* spinLabel = new wxStaticText(bg,wxID_ANY,"Transition time:");
    wxSpinCtrl* spin = new wxSpinCtrl(bg,wxID_ANY);
    spin->SetRange(0,1000);
    spin->SetValue(initialEffectTimout);

    // Layout the controls
    wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer* bookSizer = new wxBoxSizer(wxHORIZONTAL);
    bookSizer->Add(leftArrow,wxSizerFlags(0).Border(wxALL).CenterVertical());
    bookSizer->Add(m_simplebook,wxSizerFlags(1).Expand().Border(wxTOP|wxBOTTOM));
    bookSizer->Add(rightArrow,wxSizerFlags(0).Border(wxALL).Center());
    mainSizer->Add(bookSizer,wxSizerFlags(1).Expand());
    mainSizer->Add(m_pageIndicator,wxSizerFlags().Border(wxBOTTOM).Center());

    wxSizer* spinSizer = new wxBoxSizer(wxHORIZONTAL);
    spinSizer->Add(spinLabel,wxSizerFlags().Center());
    spinSizer->Add(spin,wxSizerFlags());
    mainSizer->Add(spinSizer, wxSizerFlags().Center().Border(wxBOTTOM));

    bg->SetSizer(mainSizer);
    Layout();

    // Event handlers for the left arrow, right arrow, and spin control.
    leftArrow->Bind(wxEVT_BUTTON,
            [this](wxCommandEvent&)ChangePage(wxSHOW_EFFECT_SLIDE_TO_RIGHT););
    rightArrow->Bind(wxEVT_BUTTON,
             [this](wxCommandEvent&)ChangePage(wxSHOW_EFFECT_SLIDE_TO_LEFT););
    spin->Bind(wxEVT_SPINCTRL,
             [this](wxSpinEvent& event)
             m_simplebook->SetEffectTimeout(event.GetPosition()););


void MyFrame::SetLabel()

    int curPage = m_simplebook->GetSelection();
    int totalPages = m_simplebook->GetPageCount();
    wxString label;

    for ( int i = 0 ; i < totalPages ; ++i )
    
        // U+2B24 = "Black Large Circle"
        // U+2B58 = "Heavy Circle"
        label << ((i == curPage) ? wxUniChar(0x2B24) : wxUniChar(0x2B58));
    

    m_pageIndicator->SetLabel(label);


void MyFrame::ChangePage(wxShowEffect effect)

    m_simplebook->SetEffect(effect);
    m_simplebook->AdvanceSelection(effect == wxSHOW_EFFECT_SLIDE_TO_LEFT);

    SetLabel();



class MyApp : public wxApp

    public:
        virtual bool OnInit()
        
            MyFrame* frame = new MyFrame();
            frame->Show();
            return true;
        
;

wxIMPLEMENT_APP(MyApp);

在 Windows 上看起来像这样:

我意识到这并不是您想要的,因为它会在滑动下一个页面之前完全滑出一页,而不是在幻灯片发生时将页面彼此相邻。但我认为这是使用可用控件可以做到的最好的方法。

【讨论】:

以上是关于wxWidgets 中的动画滑动面板/窗口的主要内容,如果未能解决你的问题,请参考以下文章

角度动画滑动面板 - 加载视图时显示第二个

jQuery - 显示滑动面板时动画绝对定位的 div 的“左”位置

滑动动画切换窗口或容器组件

wxwidgets 窗口信息怎么传递给上层窗口

wxWidgets源码分析 - 窗口尺寸

wxWidgets源码分析 - 窗口管理