wxTextCtrl

From WxWiki
Jump to navigation Jump to search
Official Classes SmallBlocks.png Archive Containers Controls Data Structures Database Date & Time Debug Device Contexts Dialogs Document & Views Drag & Drop Events Filesystem Frames Graphics Grid Cell Help HTML Logging Miscellaneous Networking Printing Sizers Streams Threading Windows

A text control allows text to be displayed and edited.

It may be single line or multi-line. Notice that a lot of methods of the text controls are found in the base wxTextEntry class which is a common base class for wxTextCtrl and other controls using a single line text entry field (e.g. wxComboBox).

Allowing Only Certain Kinds of Input

To create a textctrl that only allows a certain kind of input, use wxMaskedEditCtrl or wxFormatValidator. wxMaskedEditCtrl works with a mask, that is, each char in its place. wxFormatValidator is useful for writing localized numbers (to deal with a decimal separator for example). You can find them at contributed classes.

In-place Input Capitalization

Until there is no other solution available, do it like this:

BEGIN_EVENT_TABLE(MyDialog, wxDialog)
    EVT_TEXT(MyDialog::IdOfTxtCtrl, MyDialog::OnText)
END_EVENT_TABLE()

void MyDialog::OnText(wxCommandEvent& event)
{
    if(!m_ctrlPtr->IsModified())
        return;
    long insertionPoint = m_ctrlPtr->GetInsertionPoint();
    m_ctrlPtr->ChangeValue(m_ctrlPtr->GetValue().Upper());
    m_ctrlPtr->SetInsertionPoint(insertionPoint);
}

Different Characters with Different Colours

  • use wxTextCtrl::SetStyle(). Note that to do some of this, you'll need to have created the wxTextCtrl with the wxTE_RICH2 style for your wxMSW port.

or:

  • you need to use wxTextAttr. See the manual and the text sample.

Scrolling

Is there a way to reliably scroll so that the bottom line of text is at the bottom of the wxTextCtrl?

If you always use AppendText() it will scroll automatically (if it doesn't, it's a bug). You can always ensure that the last line is visible using ShowPosition(GetLastPosition()) too, of course.

Note: If you rely on this mechanism, the text will scroll a whole page down at a time. If you want the control to show the last line of text at the bottom, you can add "ScrollLines(1)" right after the AppendText call. AppendText will ensure the new line is visible, and ScrollLines will ensure the scroll bar is at the real end of the range, not further.

Under (at least) wxWidgets 2.6.3 under Windows the above seems to work as long as the string you pass to AppendText() only contains a single '\n'. If there are several lines it seems you have to modify the argument to ScrollLines accordingly. Example MSW code:

void AddSomeText( wxTextCtrl *aChatWindow, wxString s )
{
    // HACK: Under Windows (using wxTE_RICH2) we have trouble ensuring that the last
    // entered line is really at the bottom of the screen. We jump through some
    // hoops to get this working.

    // Count number of newlines (i.e lines)
    int lines = 0;
    const char* cstr = s.c_str();
    for( ; *cstr ; ++cstr )
        if( *cstr == '\n' )
            ++lines;

    // Dance...
    aChatWindow->Freeze();                 // Freeze the window to prevent scrollbar jumping
    aChatWindow->AppendText( s );          // Add the text
    aChatWindow->ScrollLines( lines + 1 ); // Scroll down correct number of lines + one (the extra line is important for some cases!)
    aChatWindow->ShowPosition( aChatWindow->GetLastPosition() ); // Ensure the last line is shown at the very bottom of the window
    aChatWindow->Thaw();                   // Allow the window to redraw
}

The Freeze() / Thaw() calls might not be necessary, but I added them for good measure.

Setting Scroll Position (2.8.9)

Under the GTK builds, the following (note that display is a wxTextCtrl derived class):

int size = display->GetSize().GetHeight();
int pos = display->GetScrollPos(wxVERTICAL);
display->SetScrollPos(wxVERTICAL, pos - size);

Will trivially scroll the window up one page (one screen height specifically.) However, this is unportable and does not work (without calling GetHandle and using the Win32 API directly) in Win32 builds. Adding a Refresh() call has no effect, and does not appear to be required in GTK.

For cross platform operation, ShowPosition() seems to work reliably. This takes a character index and makes the line containing it visible on screen. For smooth partial-page scrolling, this requires that you manually take care of hysteresis, and further requires that you calculate or cache a character position for any line you wish to display.

Disabling Auto-scroll

You cannot disable auto-scroll with AppendText() in a cross-platform manner. Under Windows:

long pos = ::SendMessage( ctrl->GetHwnd(), EM_GETFIRSTVISIBLELINE, 0, 0 );
ctrl->AppendText(text);
int newpos = ::SendMessage( ctrl->GetHwnd(), EM_GETFIRSTVISIBLELINE, 0, 0 );
::SendMessage( ctrl->GetHwnd(), EM_LINESCROLL, 0, pos-newpos );

Background Color

You can change the background color of the entire wxTextCtrl by using the SetBackgroundColour (note the British spelling) method of wxWindow.

TextOutput->SetBackgroundColour(wxColour("#000000"));

wxTE_PROCESS_ENTER and Multiline wxTextCtrls

Multiline wxTextCtrls do not support wxTE_PROCESS_ENTER, and should never get EVT_TEXT_ENTER events. The fact that this sometimes works on MSW is actually a (minor) bug.

Right Justifying Text in a wxTextCtrl Textbox

With wxTE_RIGHT. (Didn't work in some pre-2.6 versions).

SetDefaultStyle

It seems that SetDefaultStyle() does not work if you have the wxTE_RICH2 flag set.

It works with 2.8.9 in some degree! With wxTE_RICH2, SetDefaultStyle(someencoding) has to be called before SetDefaultStyle(somecolor). In fact, to me, the only way to change/set color is to have wxTE_RICH2 with wxTextCtrl. There may be something else need to be adjusted. The endcoding seems does not work properly to show Big5 and similar.

Pitfalls

PositionToXY() always returns FALSE on wxMac at least in 2.4.2. This function is not implemented on that platform.

  • PositionToXY()/XYToPosition() also is not implemented on wxMac 2.6.3 and 2.8.0

See Also