wxLogTextCtrl send too many logs to the wxTextCtrl, does wxTextCtrl have a row number limit

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.
ollydbg23
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 224
Joined: Fri Dec 12, 2008 10:31 am

wxLogTextCtrl send too many logs to the wxTextCtrl, does wxTextCtrl have a row number limit

Post by ollydbg23 » Sat Jan 02, 2021 7:37 am

Hi, I have an application which use wxLogTextCtrl, and the application will runs for a long time, and there are many log messages send to the wxTextCtrl.

The question is: will the wxTextCtrl get a row number limit? What happens if it reaches the limit, will the old lines get automatically removed? Will the wxTextCtrl get slower if it has too many messages?

Any one has suggestions?
Thanks.

Kvaz1r
Super wx Problem Solver
Super wx Problem Solver
Posts: 298
Joined: Tue Jun 07, 2016 1:07 pm

Re: wxLogTextCtrl send too many logs to the wxTextCtrl, does wxTextCtrl have a row number limit

Post by Kvaz1r » Sat Jan 02, 2021 7:47 am

1. That's really depend on your OS because wxWidgets is try to use native controls mostly.

Default value for wxTectCtrl under Windows is 64KB of text. So it would be better to use wxStyledTextCtrl instead. Another option - use virtual list control for each row where row is string that storage in std::vector<>.

2. I'm not totally sure, but I think after overflow new lines just won't be shown.

3. Yes.

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2955
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxLogTextCtrl send too many logs to the wxTextCtrl, does wxTextCtrl have a row number limit

Post by PB » Sat Jan 02, 2021 7:48 am

I think the answer my be platform specific.

AFAIK, on MSW, regular wxTextCtrl (without wxTE_RICH2) has a limit of 64 kB of text after which it probably crashes. With wxTE_RICH2, the theoretical limit is probably the RAM available. It will never remove any lines by itself.

However, I think in practice the user should limit the number of lines he adds to the control to some reasonable number. Either way, how the control behaves with very large amounts of text should be easy to test.

ollydbg23
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 224
Joined: Fri Dec 12, 2008 10:31 am

Re: wxLogTextCtrl send too many logs to the wxTextCtrl, does wxTextCtrl have a row number limit

Post by ollydbg23 » Sat Jan 02, 2021 8:04 am

Thanks.
Kvaz1r wrote:
Sat Jan 02, 2021 7:47 am
1. That's really depend on your OS because wxWidgets is try to use native controls mostly.
It is the Windows OS.
Default value for wxTectCtrl under Windows is 64KB of text. So it would be better to use wxStyledTextCtrl instead.
wxStyledTextCtrl may also have a content limit?
Another option - use virtual list control for each row where row is string that storage in std::vector<>.
OK, will try it.
2. I'm not totally sure, but I think after overflow new lines just won't be shown.
This is not the expected behavior, I think the very old messages should be deleted.
3. Yes.
OK, I see.

ollydbg23
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 224
Joined: Fri Dec 12, 2008 10:31 am

Re: wxLogTextCtrl send too many logs to the wxTextCtrl, does wxTextCtrl have a row number limit

Post by ollydbg23 » Sat Jan 02, 2021 8:06 am

PB wrote:
Sat Jan 02, 2021 7:48 am
I think the answer my be platform specific.

AFAIK, on MSW, regular wxTextCtrl (without wxTE_RICH2) has a limit of 64 kB of text after which it probably crashes. With wxTE_RICH2, the theoretical limit is probably the RAM available. It will never remove any lines by itself.

However, I think in practice the user should limit the number of lines he adds to the control to some reasonable number. Either way, how the control behaves with very large amounts of text should be easy to test.
Thanks, so when a wxLogMessage() like function get called, the wxTextCtrl should check the contents, if it exceed the limit, the old messages will be removed.

Is this way correct?

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2955
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxLogTextCtrl send too many logs to the wxTextCtrl, does wxTextCtrl have a row number limit

Post by PB » Sat Jan 02, 2021 8:16 am

All wxLogTextCtrl does is appending log messages to a wxTextCtrl. This is its full code

Code: Select all

class WXDLLIMPEXP_CORE wxLogTextCtrl : public wxLog
{
public:
    wxLogTextCtrl(wxTextCtrl *pTextCtrl);

protected:
    // implement sink function
    virtual void DoLogText(const wxString& msg) wxOVERRIDE;

private:
    // the control we use
    wxTextCtrl *m_pTextCtrl;

    wxDECLARE_NO_COPY_CLASS(wxLogTextCtrl);
}; 

wxLogTextCtrl::wxLogTextCtrl(wxTextCtrl *pTextCtrl)
{
    m_pTextCtrl = pTextCtrl;
}

void wxLogTextCtrl::DoLogText(const wxString& msg)
{
    m_pTextCtrl->AppendText(msg + wxS('\n'));
} 

If you need something more, you need to implement it yourself.

Kvaz1r
Super wx Problem Solver
Super wx Problem Solver
Posts: 298
Joined: Tue Jun 07, 2016 1:07 pm

Re: wxLogTextCtrl send too many logs to the wxTextCtrl, does wxTextCtrl have a row number limit

Post by Kvaz1r » Sat Jan 02, 2021 8:57 am

ollydbg23 wrote:
Sat Jan 02, 2021 8:04 am
wxStyledTextCtrl may also have a content limit?
I think if you are going to reach such limits it would be better split log and put it in several files ;-)
wxStyledTextCtrl worked for me even when wxTectCtrl with rich flag wasn't. I found fixed bug for Scintilla (wxStyledTextCtrl is using Scintilla lib)Problems drawing very long lines where author tested ability on large SQL dumps.

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2955
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxLogTextCtrl send too many logs to the wxTextCtrl, does wxTextCtrl have a row number limit

Post by PB » Sat Jan 02, 2021 9:29 am

FWIW, wxTextCtrl with wxTE_RICH2 flag on Win10 seems to handle 1,000,000 lines mostly fine. The only issue seems to be manual resizing by mouse, probably caused by the long time the control takes to redraw?

Code: Select all

#include <wx/wx.h>

class MyFrame: public wxFrame
{
public:
    MyFrame() : wxFrame (nullptr, wxID_ANY, "Test")
    {
        const size_t lineCount = 1000 * 1000;

        wxTextCtrl* logCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
                                    wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2);
        wxString    logText;

        for ( size_t i = 0; i < lineCount; ++i )
            logText.Append(wxString::Format("This is a log line no %zu (and this is just a random filler text to make the line longer.\n", i));

        logCtrl->AppendText(logText);
    }
};

class MyApp : public wxApp
{
public:
    bool OnInit() override
    {
        (new MyFrame())->Show();
        return true;
    }
}; wxIMPLEMENT_APP(MyApp);
However, I would generally not recommend having a million lines in a text control.

ollydbg23
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 224
Joined: Fri Dec 12, 2008 10:31 am

Re: wxLogTextCtrl send too many logs to the wxTextCtrl, does wxTextCtrl have a row number limit

Post by ollydbg23 » Mon Jan 04, 2021 12:21 pm

Thanks guys for the help, this is what I implemented:

Code: Select all

/** a log control has content limit */
class LogTextCtrlLimit : public wxLogTextCtrl
{
public:
    LogTextCtrlLimit(wxTextCtrl *pTextCtrl);

protected:
    // implement sink function
    virtual void DoLogText(const wxString& msg);

private:
    // the control we use
    wxTextCtrl *m_pTextCtrl;
    int m_Counter;

    wxDECLARE_NO_COPY_CLASS(LogTextCtrlLimit);
};

LogTextCtrlLimit::LogTextCtrlLimit(wxTextCtrl *pTextCtrl)
    : wxLogTextCtrl(pTextCtrl), // we don't use the wxLogTextCtrl::pTextCtrl
      m_pTextCtrl(pTextCtrl),   // instead, we save the pointer here
      m_Counter(0)
{
}

void LogTextCtrlLimit::DoLogText(const wxString& msg)
{
    m_Counter++;

    m_pTextCtrl->AppendText(msg + wxS('\n'));

    if (m_Counter > 10000)
    {
        m_Counter = 0;

        wxTextPos  length = m_pTextCtrl->GetLastPosition();
        if (length > 5000)
            m_pTextCtrl->Remove(0, length - 5000);
    }
}
Hope it can help others.

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2955
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxLogTextCtrl send too many logs to the wxTextCtrl, does wxTextCtrl have a row number limit

Post by PB » Mon Jan 04, 2021 1:52 pm

Why deriving from wxLogTextCtrl when you are not using any of its functionality? Would it not be better to derive directly from wxLog?

I personally would probably also remove the content based on the number of lines, not characters but...

Kvaz1r
Super wx Problem Solver
Super wx Problem Solver
Posts: 298
Joined: Tue Jun 07, 2016 1:07 pm

Re: wxLogTextCtrl send too many logs to the wxTextCtrl, does wxTextCtrl have a row number limit

Post by Kvaz1r » Mon Jan 04, 2021 2:21 pm

PB wrote:
Sat Jan 02, 2021 9:29 am
FWIW, wxTextCtrl with wxTE_RICH2 flag on Win10 seems to handle 1,000,000 lines mostly fine. The only issue seems to be manual resizing by mouse, probably caused by the long time the control takes to redraw?
Cool, glad to know - on Win10 works for me too(tested on 500,000), I had issue only under old version of Win7.
ollydbg23 wrote:
Mon Jan 04, 2021 12:21 pm
this is what I implemented:
Nice, though I think it would be better to match between total amount of characters(value that passed into Remove method) and amount of messages in log (counter variable).

If you want to keep only N messages where N not very long and messages also not very big, I would use std::queue like this:

Code: Select all

void LogTextCtrlLimit::DoLogText(const wxString& msg)
{
    m_queue.push(msg); //m_queue is member
    m_pTextCtrl->AppendText(msg + '\n');
    if (m_queue.size() > 100)
    {
        wxString old = m_queue.front();
        m_pTextCtrl->Remove(0, old.size()+1); //+1 because '\n'
        m_queue.pop();
    }
}
if you want count only characters - replace in your code m_Counter++;
to

Code: Select all

m_Counter += (msg.size()+1);

ollydbg23
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 224
Joined: Fri Dec 12, 2008 10:31 am

Re: wxLogTextCtrl send too many logs to the wxTextCtrl, does wxTextCtrl have a row number limit

Post by ollydbg23 » Mon Jan 04, 2021 2:38 pm

PB wrote:
Mon Jan 04, 2021 1:52 pm
Why deriving from wxLogTextCtrl when you are not using any of its functionality? Would it not be better to derive directly from wxLog?
Thanks, I also found this issue. First LogTextCtrlLimit was derive from wxLogTextCtrl, and I would like to access wxLogTextCtrl::m_pTextCtrl from my derived class LogTextCtrlLimit, unluckily, it is private (I have no way to access a base class's private member from derived class). Finally I add a same member variable LogTextCtrlLimit::m_pTextCtrl ...

Yes, you are correct, LogTextCtrlLimit should be derived from wxLog.
I personally would probably also remove the content based on the number of lines, not characters but...
Yes, I agree, I prefer limit the number of lines, I just don't know how to do this. :(

ollydbg23
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 224
Joined: Fri Dec 12, 2008 10:31 am

Re: wxLogTextCtrl send too many logs to the wxTextCtrl, does wxTextCtrl have a row number limit

Post by ollydbg23 » Mon Jan 04, 2021 2:48 pm

Kvaz1r wrote:
Mon Jan 04, 2021 2:21 pm
ollydbg23 wrote:
Mon Jan 04, 2021 12:21 pm
this is what I implemented:
Nice, though I think it would be better to match between total amount of characters(value that passed into Remove method) and amount of messages in log (counter variable).

If you want to keep only N messages where N not very long and messages also not very big, I would use std::queue like this:

Code: Select all

void LogTextCtrlLimit::DoLogText(const wxString& msg)
{
    m_queue.push(msg); //m_queue is member
    m_pTextCtrl->AppendText(msg + '\n');
    if (m_queue.size() > 100)
    {
        wxString old = m_queue.front();
        m_pTextCtrl->Remove(0, old.size()+1); //+1 because '\n'
        m_queue.pop();
    }
}
Thanks!

Do you mean that "m_queue" only store the lengths of each msg?
If that is true, can we just use something like:

Code: Select all

m_queue.push(msg.size()); //m_queue is member
I mean, m_queue could be something like

Code: Select all

std::queue<int>
?

if you want count only characters - replace in your code m_Counter++;
to

Code: Select all

m_Counter += (msg.size()+1);
OK, I see this method, so basically limit the total characters are simple than limit lines.

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2955
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxLogTextCtrl send too many logs to the wxTextCtrl, does wxTextCtrl have a row number limit

Post by PB » Mon Jan 04, 2021 3:22 pm

Kvaz1r wrote:
Mon Jan 04, 2021 2:21 pm

If you want to keep only N messages where N not very long and messages also not very big, I would use std::queue like this:
In this case, Flush() should probably be implemented as well?

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2955
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxLogTextCtrl send too many logs to the wxTextCtrl, does wxTextCtrl have a row number limit

Post by PB » Mon Jan 04, 2021 3:26 pm

ollydbg23 wrote:
Mon Jan 04, 2021 2:38 pm
Yes, I agree, I prefer limit the number of lines, I just don't know how to do this. :(
wxTextCtrl has GetNumberOfLines(), GetLineLength(), and Remove() so it theory it should be possible to implement. However, I do not know how fast it would be when the log is really long.

Post Reply