wxScrolledWindow is slow when scrolling through long text

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
MJaoune
Earned a small fee
Earned a small fee
Posts: 24
Joined: Tue Aug 20, 2019 7:37 pm

wxScrolledWindow is slow when scrolling through long text

Post by MJaoune » Tue Oct 15, 2019 1:37 am

Hi,

I have a wxScrolledWindow widget that has a number of wxStaticText widgets with long texts. On Windows (GTK doesn't have this problem), the scrolling would become slow when going through texts that have a somehow big number of lines. How can I make it faster? Is there a way to enable hardware acceleration when scrolling?

Ronald
I live to help wx-kind
I live to help wx-kind
Posts: 162
Joined: Mon Mar 05, 2018 4:17 am

Re: wxScrolledWindow is slow when scrolling through long text

Post by Ronald » Tue Oct 15, 2019 2:07 am

MJaoune wrote:
Tue Oct 15, 2019 1:37 am
Hi,

I have a wxScrolledWindow widget that has a number of wxStaticText widgets with long texts. On Windows (GTK doesn't have this problem), the scrolling would become slow when going through texts that have a somehow big number of lines. How can I make it faster? Is there a way to enable hardware acceleration when scrolling?
One case, wxStaticText calc its size to fit the text by default, try wxST_NO_AUTORESIZE.

MJaoune
Earned a small fee
Earned a small fee
Posts: 24
Joined: Tue Aug 20, 2019 7:37 pm

Re: wxScrolledWindow is slow when scrolling through long text

Post by MJaoune » Tue Oct 15, 2019 2:17 am

Ronald wrote:
Tue Oct 15, 2019 2:07 am
One case, wxStaticText calc its size to fit the text by default, try wxST_NO_AUTORESIZE.
But that only happens once, am I right? Or does it keep happening as long as wxScrolledWindow scrolls through text?

So wxStaticText keeps thinking it is being redrawn when it is scrolled through?

Ronald
I live to help wx-kind
I live to help wx-kind
Posts: 162
Joined: Mon Mar 05, 2018 4:17 am

Re: wxScrolledWindow is slow when scrolling through long text

Post by Ronald » Tue Oct 15, 2019 3:00 am

MJaoune wrote:
Tue Oct 15, 2019 2:17 am
Ronald wrote:
Tue Oct 15, 2019 2:07 am
One case, wxStaticText calc its size to fit the text by default, try wxST_NO_AUTORESIZE.
But that only happens once, am I right? Or does it keep happening as long as wxScrolledWindow scrolls through text?
So wxStaticText keeps thinking it is being redrawn when it is scrolled through?
Boundbox size should be calculated only once, because, when scrolling though the bound rect of the displaying part of wxStaticText changes,
the bound rect of wxStaticText should not change.
It's easy to test.

For the case that the whole wxStaticText is being re-rendered, better to debug with the wx source code.

User avatar
doublemax
Moderator
Moderator
Posts: 15278
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxScrolledWindow is slow when scrolling through long text

Post by doublemax » Tue Oct 15, 2019 6:08 am

How many wxStaticText are there?

It could be this unresolved problem: http://trac.wxwidgets.org/ticket/15766
Use the source, Luke!

MJaoune
Earned a small fee
Earned a small fee
Posts: 24
Joined: Tue Aug 20, 2019 7:37 pm

Re: wxScrolledWindow is slow when scrolling through long text

Post by MJaoune » Tue Oct 15, 2019 9:06 am

doublemax wrote:
Tue Oct 15, 2019 6:08 am
How many wxStaticText are there?

It could be this unresolved problem: http://trac.wxwidgets.org/ticket/15766
About 10-20, some of them are short texts, some are long... It is also slow on Windows 7, so that ticket might not be related I guess.
Ronald wrote:
Tue Oct 15, 2019 2:07 am
One case, wxStaticText calc its size to fit the text by default, try wxST_NO_AUTORESIZE.
Tried it, doesn't fix the problem.

User avatar
doublemax
Moderator
Moderator
Posts: 15278
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxScrolledWindow is slow when scrolling through long text

Post by doublemax » Tue Oct 15, 2019 12:10 pm

MJaoune wrote:
Tue Oct 15, 2019 9:06 am
doublemax wrote:
Tue Oct 15, 2019 6:08 am
How many wxStaticText are there?

It could be this unresolved problem: http://trac.wxwidgets.org/ticket/15766
About 10-20, some of them are short texts, some are long... It is also slow on Windows 7, so that ticket might not be related I guess.
I agree.

Can you show the code?
Use the source, Luke!

MJaoune
Earned a small fee
Earned a small fee
Posts: 24
Joined: Tue Aug 20, 2019 7:37 pm

Re: wxScrolledWindow is slow when scrolling through long text

Post by MJaoune » Tue Oct 15, 2019 2:57 pm

doublemax wrote:
Tue Oct 15, 2019 12:10 pm
I agree.

Can you show the code?
Sorry, the code is long and somehow private.

What I want to know is, does everything inside wxScrolledWindow keep getting redrawn even while scrolling? Can I set the "refresh rate" of a wxWindow component?

The redrawing is done according to the monitor's refresh rate? For example if I am working on a 60Hz monitor, the components will get redrawn 60 times per second?

My final question, is "painting" just another term for "redraw"?

User avatar
doublemax
Moderator
Moderator
Posts: 15278
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxScrolledWindow is slow when scrolling through long text

Post by doublemax » Tue Oct 15, 2019 3:58 pm

Sorry, the code is long and somehow private.
Can you extract just the code that fills the scrolledwindow with wxStaticTexts and fill them with dummy strings? It should be possible to reproduce the issue in a minimal sample. If not, maybe there are other parts in your application that are responsible.
What I want to know is, does everything inside wxScrolledWindow keep getting redrawn even while scrolling? Can I set the "refresh rate" of a wxWindow component?
Whenever a new part of the window is scrolled into view, the OS will generate a paint event and the control must redraw itself. But normally no layout should happen, so this should all be fast. You can not limit the refresh rate, especially since you're using standard controls and no custom paint event handler.
Use the source, Luke!

Ronald
I live to help wx-kind
I live to help wx-kind
Posts: 162
Joined: Mon Mar 05, 2018 4:17 am

Re: wxScrolledWindow is slow when scrolling through long text

Post by Ronald » Wed Oct 16, 2019 12:04 am

Another solution, draw the texts in EVT_PAINT handler directly.
It's not hard,faster than wxStaticText that works properly.

However, the probem should be investigated, it may be a bug of efficiency, even related to other controls that is not obvious in common use.
I'll dig it.

Ronald
I live to help wx-kind
I live to help wx-kind
Posts: 162
Joined: Mon Mar 05, 2018 4:17 am

Re: wxScrolledWindow is slow when scrolling through long text

Post by Ronald » Wed Oct 16, 2019 1:36 am

doublemax wrote:
Tue Oct 15, 2019 12:10 pm
MJaoune wrote:
Tue Oct 15, 2019 9:06 am
doublemax wrote:
Tue Oct 15, 2019 6:08 am
How many wxStaticText are there?

It could be this unresolved problem: http://trac.wxwidgets.org/ticket/15766
About 10-20, some of them are short texts, some are long... It is also slow on Windows 7, so that ticket might not be related I guess.
I agree.

Can you show the code?
modifed samples/minimal, not slow
param:
  • wxStaticText count: 20
  • rows per wxStaticText: 100
  • cols per wxStaticText: 10
Env
  • Windows 10
  • wxWidget dev almost latest
Test result: works properly, not slow

BTW, found a bug, if set cols per wxStaticText to 100 with other params unchanged, nothing displays.

Code: Select all

/////////////////////////////////////////////////////////////////////////////
// Name:        minimal.cpp
// Purpose:     Minimal wxWidgets sample
// Author:      Julian Smart
// Modified by:
// Created:     04/01/98
// Copyright:   (c) Julian Smart
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// ============================================================================
// declarations
// ============================================================================

// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

// ----------------------------------------------------------------------------
// resources
// ----------------------------------------------------------------------------

// the application icon (under Windows it is in resources and even
// though we could still include the XPM here it would be unused)
#ifndef wxHAS_IMAGES_IN_RESOURCES
    #include "../sample.xpm"
#endif

#include <sstream>

// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------

// Define a new application type, each program should derive a class from wxApp
class MyApp : public wxApp
{
public:
    // override base class virtuals
    // ----------------------------

    // this one is called on application startup and is a good place for the app
    // initialization (doing it here and not in the ctor allows to have an error
    // return: if OnInit() returns false, the application terminates)
    virtual bool OnInit() wxOVERRIDE;
};

class MyPanel : public wxScrolledWindow
{
public:
    MyPanel(wxWindow * parent,
            wxWindowID winid = wxID_ANY,
            const wxPoint & pos = wxDefaultPosition,
            const wxSize & size = wxDefaultSize,
            long style = wxScrolledWindowStyle,
            const wxString & name = wxPanelNameStr) :
        wxScrolledWindow(parent, winid, pos, size, style, name)
    {
        SetScrollRate(10, 10);

        wxFlexGridSizer * pSizer_0 = new wxFlexGridSizer(2, 5, 5);
        constexpr int nStaticTextCount = 20;
        constexpr int nRowsInStaticText = 100;
        constexpr int nColsInStaticText = 10;

        for (int i = 0; i < nStaticTextCount; ++i)
        {
            wxStaticText * pST = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER);
            { // fill it
                std::ostringstream oss;                
                for (int row = 0; row < nRowsInStaticText; ++row)
                {
                    for (int col = 0; col < nColsInStaticText; ++col)
                    {
                        oss << "TestStaticText" << i << ' ';
                    }
                    oss << "\n";
                }
                pST->SetLabel(oss.str());
            }
            pSizer_0->Add(pST);
        }

        SetSizer(pSizer_0);
    }
};

// Define a new frame type: this is going to be our main frame
class MyFrame : public wxFrame
{
public:
    // ctor(s)
    MyFrame(const wxString& title);

    // event handlers (these functions should _not_ be virtual)
    void OnQuit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);

private:
    // any class wishing to process wxWidgets events must use this macro
    wxDECLARE_EVENT_TABLE();
};

// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------

// IDs for the controls and the menu commands
enum
{
    // menu items
    Minimal_Quit = wxID_EXIT,

    // it is important for the id corresponding to the "About" command to have
    // this standard value as otherwise it won't be handled properly under Mac
    // (where it is special and put into the "Apple" menu)
    Minimal_About = wxID_ABOUT
};

// ----------------------------------------------------------------------------
// event tables and other macros for wxWidgets
// ----------------------------------------------------------------------------

// the event tables connect the wxWidgets events with the functions (event
// handlers) which process them. It can be also done at run-time, but for the
// simple menu events like this the static method is much simpler.
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(Minimal_Quit,  MyFrame::OnQuit)
    EVT_MENU(Minimal_About, MyFrame::OnAbout)
wxEND_EVENT_TABLE()

// Create a new application object: this macro will allow wxWidgets to create
// the application object during program execution (it's better than using a
// static object for many reasons) and also implements the accessor function
// wxGetApp() which will return the reference of the right type (i.e. MyApp and
// not wxApp)
wxIMPLEMENT_APP(MyApp);

// ============================================================================
// implementation
// ============================================================================

// ----------------------------------------------------------------------------
// the application class
// ----------------------------------------------------------------------------

// 'Main program' equivalent: the program execution "starts" here
bool MyApp::OnInit()
{
    // call the base class initialization method, currently it only parses a
    // few common command-line options but it could be do more in the future
    if ( !wxApp::OnInit() )
        return false;

    // create the main application window
    MyFrame *frame = new MyFrame("Minimal wxWidgets App");

    // and show it (the frames, unlike simple controls, are not shown when
    // created initially)

    frame->Maximize();
    frame->Show(true);

    // success: wxApp::OnRun() will be called which will enter the main message
    // loop and the application will run. If we returned false here, the
    // application would exit immediately.
    return true;
}

// ----------------------------------------------------------------------------
// main frame
// ----------------------------------------------------------------------------

// frame constructor
MyFrame::MyFrame(const wxString & title)
    : wxFrame(NULL, wxID_ANY, title)
{
    // set the frame icon
    SetIcon(wxICON(sample));

    #if wxUSE_MENUS
    // create a menu bar
    wxMenu * fileMenu = new wxMenu;

    // the "About" item should be in the help menu
    wxMenu * helpMenu = new wxMenu;
    helpMenu->Append(Minimal_About, "&About\tF1", "Show about dialog");

    fileMenu->Append(Minimal_Quit, "E&xit\tAlt-X", "Quit this program");

    // now append the freshly created menu to the menu bar...
    wxMenuBar * menuBar = new wxMenuBar();
    menuBar->Append(fileMenu, "&File");
    menuBar->Append(helpMenu, "&Help");

    // ... and attach this menu bar to the frame
    SetMenuBar(menuBar);
    #else // !wxUSE_MENUS
    // If menus are not available add a button to access the about box
    wxSizer * sizer = new wxBoxSizer(wxHORIZONTAL);
    wxButton * aboutBtn = new wxButton(this, wxID_ANY, "About...");
    aboutBtn->Bind(wxEVT_BUTTON, &MyFrame::OnAbout, this);
    sizer->Add(aboutBtn, wxSizerFlags().Center());
    SetSizer(sizer);
    #endif // wxUSE_MENUS/!wxUSE_MENUS

    #if wxUSE_STATUSBAR
    // create a status bar just for fun (by default with 1 pane only)
    CreateStatusBar(2);
    SetStatusText("Welcome to wxWidgets!");
    #endif // wxUSE_STATUSBAR

    wxBoxSizer * pSizer_0 = new wxBoxSizer(wxVERTICAL);

    MyPanel * pPanel = new MyPanel(this, wxID_ANY);
    pSizer_0->Add(pPanel, 1, wxEXPAND);

    SetSizer(pSizer_0);
}


// event handlers

void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    // true is to force the frame to close
    Close(true);
}

void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
    wxMessageBox(wxString::Format
                 (
                    "Welcome to %s!\n"
                    "\n"
                    "This is the minimal wxWidgets sample\n"
                    "running under %s.",
                    wxVERSION_STRING,
                    wxGetOsDescription()
                 ),
                 "About wxWidgets minimal sample",
                 wxOK | wxICON_INFORMATION,
                 this);
}

User avatar
doublemax
Moderator
Moderator
Posts: 15278
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxScrolledWindow is slow when scrolling through long text

Post by doublemax » Wed Oct 16, 2019 5:26 am

Thanks Ronald for the demo code. I was too lazy to write it myself :)
I don't see any slowdown either.

@MJaoune:
How do you place the controls, do you also use sizers?
Do you have a scroll- or mouse event handler that could be responsible for the slow down?
Use the source, Luke!

MJaoune
Earned a small fee
Earned a small fee
Posts: 24
Joined: Tue Aug 20, 2019 7:37 pm

Re: wxScrolledWindow is slow when scrolling through long text

Post by MJaoune » Wed Oct 16, 2019 9:27 am

doublemax wrote:
Wed Oct 16, 2019 5:26 am
@MJaoune:
How do you place the controls, do you also use sizers?
Do you have a scroll- or mouse event handler that could be responsible for the slow down?
There is the wxScrolledWindow which has a vertical wxBoxSizer, this sizer holds a random number of custom wxWindow widgets. Those custom wxWindow widgets each has a vertical wxBoxSizer which includes the texts ordered vertically. Due to wxWidgets' wxStaticText wrapping bugs for RTL languages, I need to add the wxStaticText in a custom wxWindow which has a wxBoxSizer inside to align it properly.

Does having many wxBoxSizers cause such an issue?
Ronald wrote:
Wed Oct 16, 2019 12:04 am
Another solution, draw the texts in EVT_PAINT handler directly.
It's not hard,faster than wxStaticText that works properly.
Why if I use event.Skip(false) in an EVT_PAINT, the wxWindow would still get painted normally? Why can't I stop the wxWindow from getting painted in an EVT_PAINT?

Ronald
I live to help wx-kind
I live to help wx-kind
Posts: 162
Joined: Mon Mar 05, 2018 4:17 am

Re: wxScrolledWindow is slow when scrolling through long text

Post by Ronald » Wed Oct 16, 2019 9:52 am

MJaoune wrote:
Wed Oct 16, 2019 9:27 am
Why if I use event.Skip(false) in an EVT_PAINT, the wxWindow would still get painted normally? Why can't I stop the wxWindow from getting painted in an EVT_PAINT?
If the parent window paints on the child window, add style wxCLIP_CHILDREN to the parent.
But generally wxCLIP_CHILDREN is used to avoid flicker, so it has little chance to help.

User avatar
doublemax
Moderator
Moderator
Posts: 15278
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxScrolledWindow is slow when scrolling through long text

Post by doublemax » Wed Oct 16, 2019 12:29 pm

There is the wxScrolledWindow which has a vertical wxBoxSizer, this sizer holds a random number of custom wxWindow widgets. Those custom wxWindow widgets each has a vertical wxBoxSizer which includes the texts ordered vertically. Due to wxWidgets' wxStaticText wrapping bugs for RTL languages, I need to add the wxStaticText in a custom wxWindow which has a wxBoxSizer inside to align it properly.
Please create a minimal sample that mimics the same setup. These "custom wxWindow widgets" definitely sound suspicious.
Use the source, Luke!

Post Reply