Scrolling

From WxWiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Scrolling widgets

#include "wx/wx.h"
#include <iostream>

class ScrolledWidgetsPane : public wxScrolledWindow
{
public:
    ScrolledWidgetsPane(wxWindow* parent, wxWindowID id) : wxScrolledWindow(parent, id)
    {
        // the sizer will take care of determining the needed scroll size
        // (if you don't use sizers you will need to manually set the viewport size)
        wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
        
        // add a series of widgets
        for (int w=1; w<=120; w++)
        {
            wxButton* b = new wxButton(this, wxID_ANY, wxString::Format(wxT("Button %i"), w));
            sizer->Add(b, 0, wxALL, 3);
        }
        
        this->SetSizer(sizer);

        // this part makes the scrollbars show up
        this->FitInside(); // ask the sizer about the needed size
        this->SetScrollRate(5, 5);
    }

};

// A sample app that adds the scrolled pane to a frame to make this code runnable
class MyApp: public wxApp
{
    wxFrame *frame;
public:
    
    bool OnInit()
    {
        wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
        frame = new wxFrame((wxFrame *)NULL, -1,  wxT("Scrolling Widgets"), wxPoint(50,50), wxSize(650,650));
        
        ScrolledWidgetsPane* my_image = new ScrolledWidgetsPane(frame, wxID_ANY);
        sizer->Add(my_image, 1, wxEXPAND);
        frame->SetSizer(sizer);
        
        frame->Show();
        return true;
    } 
};

IMPLEMENT_APP(MyApp)

Scrolling a render / an image

Scrolling a render (e.g. an image) can be done using a wxScrolledWindow, like in the following example :

#include "wx/wx.h"
#include <iostream>

class ScrolledImageComponent : public wxScrolledWindow
{
    wxBitmap* bitmap;
    int w,h;
public:
    ScrolledImageComponent(wxWindow* parent, wxWindowID id, wxString image_path) : wxScrolledWindow(parent, id)
    {
        wxImage image(image_path);
        if(!image.IsOk())
        {
            wxMessageBox(wxT("there was an error loading the image"));
            return;
        }
        
        w = image.GetWidth();
        h = image.GetHeight();

        /* init scrolled area size, scrolling speed, etc. */
        SetScrollbars(1,1, w, h, 0, 0);
        
        bitmap = new wxBitmap( image );
    }
    ~ScrolledImageComponent()
    {
        delete bitmap;
    }
    void OnDraw(wxDC& dc)
    {
        /* render the image - in a real app, if your scrolled area
           is somewhat big, you will want to draw only visible parts,
           not everything like below */
        dc.DrawBitmap(*bitmap, 0, 0, false);

        // also check wxScrolledWindow::PrepareDC
    }
};


class MyApp: public wxApp
{
    wxFrame *frame;
public:
    
    bool OnInit()
    {
        wxInitAllImageHandlers();
        wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
        frame = new wxFrame((wxFrame *)NULL, -1,  wxT("Scrolling an Image"), wxPoint(50,50), wxSize(650,650));
        
        ScrolledImageComponent* my_image = new ScrolledImageComponent(frame, wxID_ANY, wxT("my_image.jpg") );
        sizer->Add(my_image, 1, wxALL | wxEXPAND, 120);
        frame->SetSizer(sizer);
        
        frame->Show();
        return true;
    } 
};

IMPLEMENT_APP(MyApp)

If you render lots of stuff, you will want to use wxScrolledWindow::GetViewStart along with the size of the scrolled window to render only the parts which are visible, in order to maintain good performance.

Synchronizing 2 scrolled panes

The question is often asked, here is a way to do it

#include "wx/wx.h"
#include <iostream>

class ScrolledImageComponent : public wxScrolledWindow
{
    wxBitmap* bitmap;
    int w,h;
    ScrolledImageComponent* m_peer;
        
public:
    ScrolledImageComponent(wxWindow* parent, wxWindowID id, wxString image_path) : wxScrolledWindow(parent, id)
    {
        m_peer = NULL;
        
        wxImage image(image_path);
        if(!image.IsOk())
        {
            wxMessageBox(wxT("there was an error loading the image"));
            return;
        }
        
        w = image.GetWidth();
        h = image.GetHeight();
        
        /* init scrolled area size, scrolling speed, etc. */
        SetScrollbars(1,1, w, h, 0, 0);
        
        bitmap = new wxBitmap( image );
        
        Connect(wxID_ANY, wxEVT_SCROLLWIN_THUMBTRACK, wxScrollWinEventHandler(ScrolledImageComponent::onScroll), NULL, this);
        Connect(wxID_ANY, wxEVT_SCROLLWIN_THUMBRELEASE, wxScrollWinEventHandler(ScrolledImageComponent::onScroll), NULL, this);
        Connect(wxID_ANY, wxEVT_SCROLLWIN_LINEUP, wxScrollWinEventHandler(ScrolledImageComponent::onScroll), NULL, this);
        Connect(wxID_ANY, wxEVT_SCROLLWIN_LINEDOWN, wxScrollWinEventHandler(ScrolledImageComponent::onScroll), NULL, this);
    }
    ~ScrolledImageComponent()
    {
        delete bitmap;
    }
    
    void SetPeer(ScrolledImageComponent* other)
    {
        m_peer = other;
    }
    
    void onScroll(wxScrollWinEvent& evt)
    {
        if (m_peer != NULL)
        {
            m_peer->Scroll(GetScrollPos(wxHORIZONTAL), GetScrollPos(wxVERTICAL));
        }
        evt.Skip(); // let the event go
    }
    
    void OnDraw(wxDC& dc)
    {
        /* render the image - in a real app, if your scrolled area
         is somewhat big, you will want to draw only visible parts,
         not everything like below */
        dc.DrawBitmap(*bitmap, 0, 0, false);
        
        // also check wxScrolledWindow::PrepareDC
    }
};


class MyApp: public wxApp
{
    wxFrame *frame;
public:
    
    bool OnInit()
    {
        wxInitAllImageHandlers();
        wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
        frame = new wxFrame((wxFrame *)NULL, -1,  wxT("Scrolling an Image"), wxPoint(50,50), wxSize(650,650));
        
        ScrolledImageComponent* my_image = new ScrolledImageComponent(frame, wxID_ANY, wxT("my_image.jpg") );
        sizer->Add(my_image, 1, wxALL | wxEXPAND, 5);
        
        ScrolledImageComponent* my_image2 = new ScrolledImageComponent(frame, wxID_ANY, wxT("my_image.jpg") );
        sizer->Add(my_image2, 1, wxALL | wxEXPAND, 5);
        
        my_image->SetPeer(my_image2);
        my_image2->SetPeer(my_image);
        
        frame->SetSizer(sizer);
        
        frame->Show();
        return true;
    } 
};

IMPLEMENT_APP(MyApp)