RichTextCtrl formatting issue (bold sticking on).

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
AustinBachurski
In need of some credit
In need of some credit
Posts: 3
Joined: Tue May 30, 2023 2:12 pm

RichTextCtrl formatting issue (bold sticking on).

Post by AustinBachurski »

Hoping I could get some help troubleshooting an issue I'm having with a wxRichTextCtrl that I'm trying to use for a status display showing server items and their current state. I have three methods which filter what is displayed (show all, show started, and show stopped). Most of the time it works as expected with some text being bold, a certain color, center aligned, etc., but sometimes when I change filters, it acts like the BeginBold() method sticks on - all the text in the control will be bold. This seems to happen consistently if I select some text near the top of the control, or at times simply place the caret near the top of the control. I tried using SetInsertionPointEnd() at the top of my display methods, but this causes the problem to occur every time. The next issue is rare, but every now and then, all the text in the control will be center aligned. Switching to a different display filter corrects the center align issue, but once the "everything is bold" issue occurs, it seems to stick until the application is restarted.

I was having similar issues where my text color would bleed over where it wasn't supposed to, changing the order of the BeginBold/BeginTextColour/BeginAlignment methods seemed to correct that with some trial and error, so I suspect that I may still be doing that incorrectly, but the current order has produced the most consistent results thus far.

Here's one of my filtering methods, the other two are very similar - m_statusText is my wxRichTextCtrl which is constructed with the wxRE_READONLY style. My apologies if my code is incorrect/poorly written - I'm about 8 months into learning to code so I still have a lot to learn...
Thanks a bunch.

Code: Select all

void Frame::displayStatusAll()
{
	m_statusText->Clear();
	m_statusText->SetBackgroundColour(wxColour(*wxLIGHT_GREY));
	m_statusText->BeginBold();
	m_statusText->BeginTextColour(wxColour{ 0, 0, 255 });
	m_statusText->WriteText("Enterprise Portal: " + m_credentials.getPortal());
	m_statusText->EndTextColour();
	m_statusText->Newline();
	m_statusText->BeginTextColour(wxColour{ 21, 67, 96 });
	m_statusText->WriteText(m_mapServices.getTimeStamp());
	m_statusText->Newline();
	m_statusText->WriteText("Total Services: " + m_mapServices.getCountTotalAsString());
	m_statusText->Newline();
	m_statusText->WriteText(m_mapServices.getCountStartedAsString() + " - Started.");
	m_statusText->Newline();
	m_statusText->WriteText(m_mapServices.getCountStoppedAsString() + " - Stopped.");
	m_statusText->EndTextColour();
	m_statusText->EndBold();
	m_statusText->Newline();
	m_statusText->Newline();
	m_statusText->BeginAlignment(wxTEXT_ALIGNMENT_CENTER);
	m_statusText->BeginBold();
	m_statusText->BeginTextColour(wxColour{ 23, 32, 42, });
	m_statusText->WriteText("*** Displaying All Services ***");
	m_statusText->Newline();
	m_statusText->EndTextColour();
	m_statusText->EndBold();
	m_statusText->EndAlignment();
	m_statusText->Newline();

	for (const auto& [folder, services] : m_mapServices.m_serviceInformation)
	{
		m_statusText->BeginBold();
		m_statusText->BeginTextColour(wxColour{ 23, 32, 42 });
		m_statusText->WriteText(folder + ":");
		m_statusText->Newline();
		m_statusText->EndTextColour();
		m_statusText->EndBold();
		for (const auto& [service, status] : services)
		{
			if (status == "STARTED") // Green Text if STARTED.
			{
				m_statusText->BeginTextColour(wxColour{ 0, 139, 0 });
				m_statusText->WriteText("\t" + service + " - " + status);
				m_statusText->EndTextColour();
			}
			else // Red Text if STOPPED or unexpected.
			{
				m_statusText->BeginTextColour(wxColour{ 255, 0, 0 });
				m_statusText->WriteText("\t" + service + " - " + status);
				m_statusText->EndTextColour();
			}
			m_statusText->Newline();
		}
		m_statusText->Newline();
	}
}
User avatar
doublemax
Moderator
Moderator
Posts: 19163
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: RichTextCtrl formatting issue (bold sticking on).

Post by doublemax »

The nesting of the calls looks ok, i can't spot any obvious mistake. Can you reproduce this with a minimal patch to the "richtext" sample that comes with wxWidgets?
Use the source, Luke!
AustinBachurski
In need of some credit
In need of some credit
Posts: 3
Joined: Tue May 30, 2023 2:12 pm

Re: RichTextCtrl formatting issue (bold sticking on).

Post by AustinBachurski »

Sorry for the slow response, it took me a while to figure out how to use the samples... I'm not sure if this is as minimal as you were suggesting, but I changed the OnInsertSymbol() method on line 1879, (made a copy and commented out the old). Video example if curious (sorry for low quality...) - with the sample having the "Bold" button you can click to toggle bold, I did notice that if bold is toggled on, the text is unexpectedly bold, and appears normally when toggled off. Button toggles on when the cursor is placed in/on bold text. I suspect this is why it only happens when my cursor is at the top, as the text there is bold. Not sure if this is expected behavior or not.

Code: Select all

void MyFrame::OnInsertSymbol(wxCommandEvent& WXUNUSED(event)) // TESTING
{
#include <unordered_map>
#include <string>

    std::unordered_map<std::string, std::unordered_map<std::string, std::string>> serverStatus =
    {
        {"Testing", {
            {"Map Service One", "STARTED"},
            {"Map Service Two", "STARTED"},
            {"Map Service Three", "STOPPED"},
            {"Map Service Four", "STARTED"}
            }},
        {"One", {
            {"Map Service One", "STOPPED"},
            {"Map Service Two", "STARTED"},
            {"Map Service Three", "STARTED"},
            {"Map Service Four", "STARTED"}
            }},
        {"Two",{
            {"Map Service One", "STOPPED"},
            {"Map Service Two", "STOPPED"},
            {"Map Service Three", "STARTED"},
            {"Map Service Four", "STOPPED"}
            }}
    };

    m_richTextCtrl->Clear();
    m_richTextCtrl->SetBackgroundColour(wxColour(*wxLIGHT_GREY));
    m_richTextCtrl->BeginBold();
    m_richTextCtrl->BeginTextColour(wxColour{ 0, 0, 255 });
    m_richTextCtrl->WriteText("Enterprise Portal: m_credentials.getPortal()");
    m_richTextCtrl->EndTextColour();
    m_richTextCtrl->Newline();
    m_richTextCtrl->BeginTextColour(wxColour{ 21, 67, 96 });
    m_richTextCtrl->WriteText("m_mapServices.getTimeStamp()");
    m_richTextCtrl->Newline();
    m_richTextCtrl->WriteText("Total Services: m_mapServices.getCountTotalAsString()");
    m_richTextCtrl->Newline();
    m_richTextCtrl->WriteText("m_mapServices.getCountStartedAsString() - Started.");
    m_richTextCtrl->Newline();
    m_richTextCtrl->WriteText("m_mapServices.getCountStoppedAsString() - Stopped.");
    m_richTextCtrl->EndTextColour();
    m_richTextCtrl->EndBold();
    m_richTextCtrl->Newline();
    m_richTextCtrl->Newline();
    m_richTextCtrl->BeginAlignment(wxTEXT_ALIGNMENT_CENTER);
    m_richTextCtrl->BeginBold();
    m_richTextCtrl->BeginTextColour(wxColour{ 23, 32, 42, });
    m_richTextCtrl->WriteText("*** Displaying All Services ***");
    m_richTextCtrl->Newline();
    m_richTextCtrl->EndTextColour();
    m_richTextCtrl->EndBold();
    m_richTextCtrl->EndAlignment();
    m_richTextCtrl->Newline();

    for (const auto& [folder, services] : serverStatus)
    {
        m_richTextCtrl->BeginBold();
        m_richTextCtrl->BeginTextColour(wxColour{ 23, 32, 42 });
        m_richTextCtrl->WriteText(folder + ":");
        m_richTextCtrl->Newline();
        m_richTextCtrl->EndTextColour();
        m_richTextCtrl->EndBold();

        for (const auto& [service, status] : services)
        {
            if (status == "STARTED") // Green Text if STARTED.
            {
                m_richTextCtrl->BeginTextColour(wxColour{ 0, 139, 0 });
                m_richTextCtrl->WriteText("\t" + service + " - " + status);
                m_richTextCtrl->EndTextColour();
            }
            else // Red Text if STOPPED or unexpected.
            {
                m_richTextCtrl->BeginTextColour(wxColour{ 255, 0, 0 });
                m_richTextCtrl->WriteText("\t" + service + " - " + status);
                m_richTextCtrl->EndTextColour();
            }
            m_richTextCtrl->Newline();
        }
        m_richTextCtrl->Newline();
    }
}
AustinBachurski
In need of some credit
In need of some credit
Posts: 3
Joined: Tue May 30, 2023 2:12 pm

Re: RichTextCtrl formatting issue (bold sticking on).

Post by AustinBachurski »

Quick follow up, simple fix for my use case at least. After the clear command, an IsSelectionBold() check and ApplyBoldToSelection() if so seems to have solved the issue I was having, added a similar check for the alignment to prevent that intermittent issue as well. So the first few lines of each of my filtering methods becomes:

Code: Select all

m_statusText->Clear();

if (m_statusText->IsSelectionBold())
{
	m_statusText->ApplyBoldToSelection();
}
if (m_statusText->IsSelectionAligned(wxTEXT_ALIGNMENT_CENTER))
{
	m_statusText->ApplyAlignmentToSelection(wxTEXT_ALIGNMENT_LEFT);
}

m_statusText->SetBackgroundColour(wxColour(*wxLIGHT_GREY));
Thanks very much for your help!
Post Reply