Search code examples
c++dialogwxwidgetsword-wrap

wxWidgets C++ - dynamically wrapping wxStaticText in dialog


I am having trouble with getting a wxStaticText label to wrap dynamically in a dialog, using wxWidgets 3.0.2. I followed ideas for other questions like this one, bit I still have strange effects.

I am using the Wrap(int) function on the text, in a callback on the wxEVT_SIZE event, but it seems to have an unexpected effect on the text, and also seems to only "ratchet" down the size, and won't wrap again as the window expands.

The main part of the binding is:

CTOR(...) {
    ....
    m_text->Bind(wxEVT_SIZE, &DIALOG_WRAPTEXT::onResize, this);
}

void CLASS::onResize( wxSizeEvent& event )
{
    m_text->Wrap( event.GetSize().GetWidth() );
    event.Skip();
}

The result looks OK when the dialog is first shown, but when you resize narrower and back up, you get this result:

After making narrower After making wide again

A minimum reproducible example is:

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
    #include <wx/wx.h>
#endif
class DIALOG_WRAPTEXT: public wxDialog
{
public:

    DIALOG_WRAPTEXT( wxWindow* parent,
            const wxString& aTitle, const wxSize aSize );

private:

    void onResize( wxSizeEvent& evt );

    wxBoxSizer* m_itemBoxSizer;
    wxStaticText* m_text;
};

DIALOG_WRAPTEXT::DIALOG_WRAPTEXT(
        wxWindow* parent, const wxString& aTitle, const wxSize aSize ):
                    wxDialog( parent, wxID_ANY, aTitle,
                                 wxPoint( -1, -1 ), aSize,
                                 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
    m_itemBoxSizer = new wxBoxSizer( wxVERTICAL );
    SetSizer( m_itemBoxSizer );

    wxString msg("Lots and lots of text to wrap hopefully. "
                "Lots and lots of text to wrap hopefully. "
                "Lots and lots of text to wrap hopefully. "
                "Lots and lots of text to wrap hopefully. "
                "Lots and lots of text to wrap hopefully. "
                "Lots and lots of text to wrap hopefully. "
                );

    m_text = new wxStaticText( this, wxID_ANY, msg );
    // wxEXPAND makes no difference
    m_itemBoxSizer->Add( m_text, 1, wxALIGN_TOP | wxALL | wxEXPAND, 5 );

    // Bind to m_text or this, same effect
    m_text->Bind(wxEVT_SIZE, &DIALOG_WRAPTEXT::onResize, this);

}

void DIALOG_WRAPTEXT::onResize( wxSizeEvent& event )
{
    //m_text->Freeze(); // makes no difference
    const auto w = event.GetSize().GetWidth();
    wxLogDebug( "Wrap to width: %d",w ); // produces sensible values
    m_text->Wrap( w );
    //m_text->Thaw();
    event.Skip();
}


class MyApp: public wxApp
{
public:

    bool OnInit() override
    {
        auto d = new DIALOG_WRAPTEXT(NULL, "Dialog title", wxSize(200, 200));

        d->ShowModal();
        d->Destroy();
    }
};

wxIMPLEMENT_APP(MyApp);

What is the right way to dynamically wrap static text in a dialog?


Solution

  • Without any wrap(), the wxStaticText displays the text correctly (wrapping at word boundaries) using the follwing minimal code on windows with wx 3.0.2. I can resize the dialog (shrink, grow) and the wxStaticText will update itself correctly. This is not enough for your use case? Are you sure you need to use the wrap function?

    #include <wx/wxprec.h>
    #ifndef WX_PRECOMP
    #include <wx/wx.h>
    #endif
    class DIALOG_WRAPTEXT : public wxDialog
    {
    public:
    
        DIALOG_WRAPTEXT(wxWindow* parent,
            const wxString& aTitle, const wxSize aSize);
    
    private:
    
        void onResize(wxSizeEvent& evt);
    
        wxBoxSizer* m_itemBoxSizer;
        wxStaticText* m_text;
    };
    
    DIALOG_WRAPTEXT::DIALOG_WRAPTEXT(
        wxWindow* parent, const wxString& aTitle, const wxSize aSize) :
        wxDialog(parent, wxID_ANY, aTitle,
            wxPoint(-1, -1), aSize,
            wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
    {
        m_itemBoxSizer = new wxBoxSizer(wxVERTICAL);
        SetSizer(m_itemBoxSizer);
    
        wxString msg("Lots and lots of text to wrap hopefully. "
            "Lots and lots of text to wrap hopefully. "
            "Lots and lots of text to wrap hopefully. "
            "Lots and lots of text to wrap hopefully. "
            "Lots and lots of text to wrap hopefully. "
            "Lots and lots of text to wrap hopefully. "
        );
    
        m_text = new wxStaticText(this, wxID_ANY, msg);
        // wxEXPAND makes no difference
        m_itemBoxSizer->Add(m_text, 1, wxALIGN_TOP | wxALL | wxEXPAND, 5);
    
        // Act on dialog resize
        Bind(wxEVT_SIZE, &DIALOG_WRAPTEXT::onResize, this);
    
    }
    
    void DIALOG_WRAPTEXT::onResize(wxSizeEvent& event)
    {
        // layout everything in the dialog
        Layout();
        event.Skip();
    }
    
    
    class MyApp : public wxApp
    {
    public:
    
        bool OnInit() override
        {
            auto d = new DIALOG_WRAPTEXT(NULL, "Dialog title", wxSize(200, 200));
    
            d->ShowModal();
            d->Destroy();
    
            return true;
        }
    };
    
    wxIMPLEMENT_APP(MyApp);