Writing text in upper case in a wxTextCtrl Topic is solved

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.
Muetdhiver
Super wx Problem Solver
Super wx Problem Solver
Posts: 323
Joined: Sun Jun 08, 2008 11:59 am
Location: Bordeaux, France

Writing text in upper case in a wxTextCtrl

Post by Muetdhiver »

Hello !

I've got a frame with some controls : wxTextCtrl.

I just wonder if it is possible to write a text in the wxTextCtrl directly in upper case. User don't have to enable upper case on his keyboard, he types letter in lower case but these letter appear in upper case in the text control.

Thanks for your help.
Bye
Alexandre.
Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria »

I have not tried, but maybe you could try intercepting keyboard events and changing the pressed key in it, then letting it continue.
framepointer
Super wx Problem Solver
Super wx Problem Solver
Posts: 264
Joined: Mon Aug 07, 2006 3:25 pm
Location: Baia Mare, Romania
Contact:

Post by framepointer »

Hi.

You could do this:

Code: Select all

m_pTextCtrl->Connect(wxID_ANY, wxEVT_KEY, wxKeyEventHandler(MyClass::OnKey), 0L, this); 

/* ... */

void MyClass::OnKey(wxKeyEvent & event)
{
   if(event.GetKeyCode() >= 'a' &&  event.GetKeyCode() <= 'z')
   {    
       // add the upper value here at the current insert position
   }
   else
       event.Skip();
} 

Software is like sex,
It's better when it's free.
~Linus Torvalds
Muetdhiver
Super wx Problem Solver
Super wx Problem Solver
Posts: 323
Joined: Sun Jun 08, 2008 11:59 am
Location: Bordeaux, France

Post by Muetdhiver »

Thanks for your answer.
Unfortunally I don't succeed to enter into the OnKey function. I do not understand anything because I'm sure I've well connected my TxtCtrl to the event....

Here what i done, stop me if i'm wrong:

Code: Select all

enum
{
	wxID_ON_KEY = 140
};

CTrainingGameWord::Init()
{
...
m_po_tc_word	= new wxTextCtrl( this, wxID_ON_KEY, _T(""), wxDefaultPosition, wxSize(100, 25 ), wxTE_MULTILINE | wxTE_RICH );
	m_po_tc_word->Connect(wxID_ANY, wxID_ON_KEY, wxKeyEventHandler(CTrainingGameWord::OnKey), 0L, this );
....
}

void
CTrainingGameWord::OnKey(wxKeyEvent & event)
{
   if(event.GetKeyCode() >= 'a' &&  event.GetKeyCode() <= 'z')
   {
       // Add the upper value here at the current insert position
	   *m_po_tc_word << event.GetKeyCode()-32 ;
   }
   else
   {
       event.Skip();
   }
}
It's not the fact *m_po_tc_word << event.GetKeyCode()-32 ; should be wrong, it is just that, in debug, I never go into the OnKey function....

What's wrong ?

Thanks a lot.
Bye.
dbonnecaze
In need of some credit
In need of some credit
Posts: 2
Joined: Fri Sep 19, 2008 6:54 pm

Post by dbonnecaze »

I believe that the second param of your connect should be the event type not the ctrl id.

m_po_tc_word->Connect(wxID_ANY, wxEVT_KEY, wxKeyEventHandler
Muetdhiver
Super wx Problem Solver
Super wx Problem Solver
Posts: 323
Joined: Sun Jun 08, 2008 11:59 am
Location: Bordeaux, France

Post by Muetdhiver »

Finally I succeeded to enter into the function by putting wxEVT_KEY_DOWN instead of wxID_ON_KEY.

But I got this problem now:
i can't access to my text ctrl (m_po_tc_word).

Everything I do leads to a segmentation fault. I simply cannot take the current string from this widget:
wxString loc_o_string = m_po_tc_word->GetValue();

I think i cannot access in the OnKey function to an event that is getting updated in the same time by the wxWidget core. There is a critical access forbiden.

So do you have an idea ? Could I interact on the event ?
Thanks a lot, bye.
Alexandre.
Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria »

This sounds like you passed the wrong event sink argument in your Connect() call
Muetdhiver
Super wx Problem Solver
Super wx Problem Solver
Posts: 323
Joined: Sun Jun 08, 2008 11:59 am
Location: Bordeaux, France

Post by Muetdhiver »

To sum up, the CTrainingGameWord class contains 2 graphical elements:
- a static text (ignore it)
- a text control (which interests us) : m_po_tc_word

The CTrainingGameWord class inherits from wxPanel.

I attach, with the Connect function, a key event to this m_po_tc_word and wants to interact with.
This connection is done in the constructor of CTrainingGameWord class.

I use "this" (so, CTrainingGameWord class) as event sink.
I'm not a home to test but should I use "m_po_tc_word" instead of "this" ?

Thanks a lot.
Bye.
Alexandre.
Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria »

Muetdhiver wrote: I use "this" (so, CTrainingGameWord class) as event sink.
I'm not a home to test but should I use "m_po_tc_word" instead of "this" ?
.
I didn't read your whole post - as a general rule, pass a pointer to the class that contains the callback method and that should rspond to the event
Muetdhiver
Super wx Problem Solver
Super wx Problem Solver
Posts: 323
Joined: Sun Jun 08, 2008 11:59 am
Location: Bordeaux, France

Post by Muetdhiver »

Hi !

It does not solve the problem at all.
I tried:

Code: Select all

m_po_tc_word->Connect(wxID_ANY, wxEVT_KEY_UP, wxKeyEventHandler(CTrainingGameWord::OnKey), 0L, m_po_tc_word );
instead of

Code: Select all

m_po_tc_word->Connect(wxID_ANY, wxEVT_KEY_UP, wxKeyEventHandler(CTrainingGameWord::OnKey), 0L, this );
but the segmentation fault is always here when I try to access the m_po_tc_word component.

Any idea ?
Thanks.
Grrr
Earned some good credits
Earned some good credits
Posts: 126
Joined: Fri Apr 11, 2008 8:48 am
Location: Netherlands

Post by Grrr »

Instead of using Connect(), you can also create a subclass from wxTextCtrl and use event tables. Event trables work for most people, whereas Connect() seems to cause much confusion.
Muetdhiver
Super wx Problem Solver
Super wx Problem Solver
Posts: 323
Joined: Sun Jun 08, 2008 11:59 am
Location: Bordeaux, France

Post by Muetdhiver »

You're right, it works better by using table event instead of the Connect function that is a big shhh... !!! Hours passed due to this function.... It drived me crazy !!
Feneck91
Knows some wx things
Knows some wx things
Posts: 32
Joined: Tue Feb 28, 2006 7:47 am

Re: Writing text in upper case in a wxTextCtrl

Post by Feneck91 »

Other way very simple :

Code: Select all

void MyClass::BuildContent(wxWindow* _pParent)
{
...
.. init code (for me it is with xrc) ..
...

    m_pTextCtrl->Connect(XRCID("idMyCtrlEdit"), wxEVT_COMMAND_TEXT_UPDATED, (wxObjectEventFunction) &MyClass::OnCommandUpdate);
}

void MyClass::OnKeyDownToUpper(wxCommandEvent &_rCommandEvent)
{
    wxTextCtrl *pTextCtrl = dynamic_cast<wxTextCtrl *>(_rCommandEvent.GetEventObject());
    if (pTextCtrl != NULL)
    {
        if (!pTextCtrl->IsModified())
            return;
        long insertionPoint = pTextCtrl->GetInsertionPoint();
        pTextCtrl->ChangeValue(pTextCtrl->GetValue().Upper());
        pTextCtrl->SetInsertionPoint(insertionPoint);
    }
    _rCommandEvent.Skip();
}
Feneck91
Knows some wx things
Knows some wx things
Posts: 32
Joined: Tue Feb 28, 2006 7:47 am

Re: Writing text in upper case in a wxTextCtrl

Post by Feneck91 »

I think it can be used by wxWidgets users.
Compatible with wxWidgets 2.8.x and 2.9.x. Can give min & max string length, set to uppercase, force not to be empty (field mandatory), set colors for mandatory and error control.
Header

Code: Select all

/////////////////////////////////////////////////////////////////////////////
// Name:        wxETKIntegerValidator.h
// Library:     wxETK
// Purpose:     Header of validators.
// Author:      Stéphane Château
// Modified by:
// Created:     03/06/2011
// Licence:     LGPL
/////////////////////////////////////////////////////////////////////////////
#ifndef WXETK_VALIDATORS_H
#define WXETK_VALIDATORS_H

#include "wxETKTypes.h"
#include <wx/valtext.h>

///////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                       //
//                                        wxETKBaseValidator                                             //
//                                                                                                       //
///////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Base class for all wxETK validator classes.
 *
 * This class records colors for all validators: error color and mandatory color.
 *
 * All control who have wxFILTER_EMPTY as filter are set to specific background color (if set only).
 * When validate, if error occurs, the background of the control change to specific error color (if set too).
 * When a control is in error, modifying it (by past or TransferToWindow) changing the background back to
 * default color even the control is not yet valid.
 *
 * @author Stéphane Château
 * @version Name : wxETK<br>
 *          Revision : <b>1.0</b>
 */
class EXPORT_IMPORT wxETKBaseValidator
{
private:
    /**
     * Color for mandatory controls.
     *
     * Is used to display color controls that the value is mandatory (wxFILTER_EMPTY enabled).
     */
    static wxColour                     m_clMandatory;

    /**
     * Color for error controls.
     *
     * Modify controls who are validate failed to this color when validate failed.
     * Changing content of these controls make original color back, even the control is not yet valid.
     */
    static wxColour                     m_clError;

    /**
     * Indicate the control error color before changing the color.
     */
    wxColour                            m_clOldBkColor;

    /**
     * Indicate if the control is on error or not.
     *
     * When the user change the control, this flag is reset.
     */
    bool                                m_bIsOnError;

    /**
     * Text control pointer.
     *
     * Used only for wxTextCtrl type for uppercase filter.
     */
    wxTextCtrl *                        m_pTextCtrl;

public:
    /// @name Constructor / Destructor.
    //@{
    /**
     * Standard constructor.
     */
    wxETKBaseValidator(wxWindowBase *_pValidatorWindow);

    /**
     * Copy constructor.
     *
     * @param _rValidator Instance to copy into this.
     */
    wxETKBaseValidator(const wxETKBaseValidator &_rValidator);

    /**
     * Destructor.
     */
    virtual ~wxETKBaseValidator();
    //@}

    /**
     * Copy into this.
     *
     * @param _rValidator Element to copy into this.
     * @return Always true.
     */
    bool                                Copy(const wxETKBaseValidator& _rValidator);

    /**
     * Get color for mandatory controls.
     *
     * @return The color of the background mandatory control.
     */
    static wxColour                     GetColorForMandatory();

    /**
     * Set color for mandatory controls.
     *
     * @param _rclMandatory Color set for mandator controls, if not set the color of the control don't change.
     */
    static void                         SetColorForMandatory(const wxColour &_rclMandatory);

    /**
     * Indicate if the color for mandatory is set or not.
     *
     * @return true if the color has been set, false else.
     */
    static bool                         IsColorForMandatory();

    /**
     * Get color for errors controls.
     *
     * @return The color of the background error control.
     */
    static wxColour                     GetColorForError();

    /**
     * Set color for errors controls.
     *
     * @param _rclError Color set for error, if not set the color of the control don't change if error
     *                  occurs when validate.
     */
    static void                         SetColorForError(const wxColour &_rclError);

    /**
     * Indicate if the color for error is set or not.
     *
     * @return true if the color has been set, false else.
     */
    static bool                         IsColorForError();

    /**
     * Set the text control only if not already set.
     *
     * @param _pValidatorWindow Validator window to record.
     */
    void                                SetTextCtrlIfNeeded(wxWindowBase *_pValidatorWindow);

protected:
    /**
     * Clear the error if exists.
     *
     * Put the control back to normal color.
     */
    void                                ClearError();

    /**
     * Set the error if not already set.
     *
     * Put the control to error color only if set, record the original one before changing it.
     */
    void                                SetError();

    /**
     * Is mandatory to be able to know the validator.
     *
     * Used to set and clear error, etc.
     *
     * @return The Validator.
     */
    wxTextCtrl *                        GetTextCtrl() const;

private:
    DECLARE_ABSTRACT_CLASS(wxETKBaseValidator);
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                       //
//                                        wxETKTextValidator                                             //
//                                                                                                       //
///////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////

#if wxCHECK_VERSION(2,9,0) // version 2.9.0
    // Not defined in wxWidgets : set ctrl to uppercase
    #define wxFILTER_UPPERCASE              ((wxTextValidatorStyle) 0x8000)
    // Not defined in wxWidgets : set min lenght
    #define wxFILTER_MIN_LENGTH             ((wxTextValidatorStyle) 0x4000)
    // Not defined in wxWidgets : set max lenght
    #define wxFILTER_MAX_LENGTH             ((wxTextValidatorStyle) 0x2000)
    // Not defined in wxWidgets : set only A-Z and a-z char allowed
    #define wxFILTER_ALPHA_STRICT           ((wxTextValidatorStyle) 0x1000)
    // Not defined in wxWidgets : set only A-Z and a-z and 0-9 char allowed
    #define wxFILTER_ALPHANUMERIC_STRICT    ((wxTextValidatorStyle) 0x0800)
#else
    // Not defined in 2.8.x : different values as 2.9.0
    #define wxFILTER_EMPTY                  0x8000
    // Not defined in wxWidgets : set ctrl to uppercase
    #define wxFILTER_UPPERCASE              0x4000
    // Not defined in wxWidgets : set min lenght
    #define wxFILTER_MIN_LENGTH             0x2000
    // Not defined in wxWidgets : set max lenght
    #define wxFILTER_MAX_LENGTH             0x1000
    // Not defined in wxWidgets : set only A-Z and a-z char allowed
    #define wxFILTER_ALPHA_STRICT           0x0800
    // Not defined in wxWidgets : set only A-Z and a-z and 0-9 char allowed
    #define wxFILTER_ALPHANUMERIC_STRICT    0x0400
#endif

/**
 * Text validator.
 *
 * Based on wxETKBaseValidator this class add new kind of filters like:
 * <ul>
 *  <li>wxFILTER_EMPTY: if the control is empty, the validate failed. It is already implements into
 *                      wxWidgets 2.9.x but this class implements it for previous versions.</li>
 *  <li>wxFILTER_UPPERCASE: all typing into the control is put automatically in uppercase. This not use
 *                          a specific Windows style but catch all event when modifying the control content,
 *                          so it is multi-plateform.</li>
 *  <li>wxFILTER_MIN_LENGTH: let specify a min length of the control content, else the validate failed.</li>
 *  <li>wxFILTER_MAX_LENGTH: let specify a min length of the control content, else the validate failed.
 *                           Call SetMaxLength on the wxTextCtrl (cannot write more than this length), or could
 *                           only verify this length at validation (else do both controls).</li>
 *  <li>wxFILTER_ALPHA_STRICT: accept only a-z + A-Z chars.</li>
 *  <li>wxFILTER_ALPHANUMERIC_STRICT: accept only a-z + A-Z + 0-9 chars.</li>
 * </ul>
 *
 * @author Stéphane Château
 * @version Name : wxETK<br>
 *          Revision : <b>1.0</b>
 */
class EXPORT_IMPORT wxETKTextValidator : public wxTextValidator
                                       , public wxETKBaseValidator
{
private:
    /**
     * Min text length.
     */
    size_t                              m_stMinLength;

    /**
     * Min text length.
     */
    size_t                              m_stMaxLength;

public:
    /// @name Constructor / Destructor.
    //@{
    /**
     * Constructor.
     *
     * Construct the text validator.
     *
     * @param _lStyle Text validator style.
     * @param _pStringVal Pointer on string.
     * @param _pValidatorWindow Pointer on window. It is used ONLY on wxTextCtrl
     *                          for wxFILTER_UPPERCASE only.
     */
    wxETKTextValidator(long _lStyle = wxFILTER_NONE, wxString *_pStringVal = NULL,wxWindowBase *_pValidatorWindow = NULL);

    /**
     * Copy constructor.
     *
     * @param _rValidator Element to copy into this.
     */
    wxETKTextValidator(const wxETKTextValidator& _rValidator);

    /**
     * Destructor.
     */
    virtual ~wxETKTextValidator();
    //@}

    /**
     * Set the min length of this element.
     *
     * Only valid when _pValidatorWindow is pass into constructor. Only wxTextCtrl base class are allowed.
     *
     * @param _stMinLength Min length.
     */
    void                                SetMinLength(size_t _stMinLength);

    /**
     * Set the max length of this element.
     *
     * Only valid when _pValidatorWindow is pass into constructor.
     * Only wxTextCtrl base class are allowed.
     * The check is done when validate and the SetMaxLength function is called on
     * wxTextCtrl to limit string length by wxWidgets.
     *
     * @param _stMaxLength Max length.
     * @param _bSetMaxLenOnTextCtrl If true, call SetMaxLength on the wxTextCtrl, else only verify
     *                              on validation, else do both controls.
     */
    void                                SetMaxLength(int _stMaxLength,bool _bSetMaxLenOnTextCtrl=true);
protected:
#if !wxCHECK_VERSION(2,9,0) // version < 2.9.0
    /**
     * Test if style exist in style bit field of this component.
     *
     * @param iStyleToTest Style field to test.
     * @return true if this field is set, false else.
     */
    bool                                HasFlag(int iStyleToTest) const   { return (GetStyle() & iStyleToTest) != 0; }
#endif

    /**
     * Check is the string is valid, depending of filter value.
     *
     * Called only in wxWidget 2.9.x.
     *
     * @return The error message if the contents of '_strVal' are invalid.
     *         NB: this format string should always contain exactly one '%s'.
     */
    virtual wxString                    IsValid(const wxString& _strVal) const;

    /** Called when the value in the window must be validated.
     *
     * This function can pop up an error message.
     *
     * @param _pParent Control to validate.
     * @return true is the validate is ok, false else.
     */
    virtual bool                        Validate(wxWindow *_pParent);

    /**
     * Called to transfer data to the window.
     *
     * Clear error if validator is in error.
     */
    virtual bool                        TransferToWindow();

    /**
     * Used to change control color when it is "on error".
     *
     * When char is pressed, if m_bIsOnError is true, set background back
     * to m_clOldBkColor and reset m_bIsOnError.
     *
     * @param _rEvent Char event.
     */
    void                                OnChar(wxKeyEvent& _rEvent);

    /**
     * Called when the user press key on number text ctrl.
     *
     * If key is 'a' to 'z', transform to 'A' to 'Z'.
     *
     * @param _rCommandEvent Command event.
     */
    void                                OnCommandUpdateChangeToUppercase(wxCommandEvent &_rCommandEvent);

    /**
     * Make a clone of this validator (or return NULL).
     *
     * Currently necessary if you're passing a reference to a validator.
     * Another possibility is to always pass a pointer to a new validator
     * (so the calling code can use a copy constructor of the relevant class).
     *
     * @return a copy of this.
     */
    virtual wxObject *                  Clone() const;

    /**
     * Copy into this.
     *
     * @param _rValidator Element to copy into this.
     * @return Always true.
     */
    bool                                Copy(const wxETKTextValidator& _rValidator);
private:
#if wxCHECK_VERSION(2,9,0) // version 2.9.0
    // Defines only in version < 2.9.0
    wxDECLARE_NO_ASSIGN_CLASS(wxETKTextValidator);
#endif
    DECLARE_DYNAMIC_CLASS(wxETKTextValidator)
    DECLARE_EVENT_TABLE()
};

#endif // WXETK_VALIDATORS_H
Implementation:

Code: Select all

/////////////////////////////////////////////////////////////////////////////
// Name:        wxETKIntegerValidator.cpp
// Library:     wxETK
// Purpose:     Implementation of validators.
// Author:      Stéphane Château
// Modified by:
// Created:     03/06/2011
// Licence:     LGPL
/////////////////////////////////////////////////////////////////////////////

#include "wxETKValidators.h"

bool wxETKIsAlphaStrict(const wxChar& _rChar)
{
    return (    (_rChar>=_T('A') && _rChar<=_T('Z'))
             || (_rChar>=_T('a') && _rChar<=_T('z'))
           );
}

bool wxETKIsAlphaNumrericStrict(const wxChar& _rChar)
{
    return (    (_rChar>=_T('A') && _rChar<=_T('Z'))
             || (_rChar>=_T('a') && _rChar<=_T('z'))
             || (_rChar>=_T('0') && _rChar<=_T('9'))
           );
}

// IRIX mipsPro refuses to compile wxStringCheck<func>() if func is inline so
// let's work around this by using this non-template function instead of
// wxStringCheck(). And while this might be fractionally less efficient because
// the function call won't be inlined like this, we don't care enough about
// this to add extra #ifs for non-IRIX case.
namespace
{

bool wxETKCheckString(bool (*func)(const wxChar&), const wxString& str)
{
    for ( wxString::const_iterator i = str.begin(); i != str.end(); ++i )
    {
        if ( !func(*i) )
            return false;
    }

    return true;
}

} // anonymous namespace

///////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                       //
//                                        wxETKBaseValidator                                             //
//                                                                                                       //
///////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
wxColour wxETKBaseValidator::m_clMandatory;
wxColour wxETKBaseValidator::m_clError;

wxClassInfo wxETKBaseValidator::ms_classInfo(wxT("wxETKBaseValidator"),
                                             NULL,
                                             NULL,
                                             (int) sizeof(wxETKBaseValidator),
                                             NULL);

wxClassInfo *wxETKBaseValidator::GetClassInfo() const
    { return &wxETKBaseValidator::ms_classInfo; }

wxETKBaseValidator::wxETKBaseValidator(wxWindowBase *_pValidatorWindow)
    : m_bIsOnError(false)
    , m_pTextCtrl(NULL)
{
    SetTextCtrlIfNeeded(_pValidatorWindow);
}

wxETKBaseValidator::wxETKBaseValidator(const wxETKBaseValidator &_rValidator)
{
    Copy(_rValidator);
}

wxETKBaseValidator::~wxETKBaseValidator()
{
}

bool wxETKBaseValidator::Copy(const wxETKBaseValidator& _rValidator)
{
    m_bIsOnError   = _rValidator.m_bIsOnError;
    m_clOldBkColor = _rValidator.m_clOldBkColor;
    m_pTextCtrl    = _rValidator.m_pTextCtrl;

    return true;
}

wxColour wxETKBaseValidator::GetColorForMandatory()
{
    wxASSERT(IsColorForMandatory());
    return m_clMandatory;
}

void wxETKBaseValidator::SetColorForMandatory(const wxColour &_rclMandatory)
{
    m_clMandatory = _rclMandatory;
}

bool wxETKBaseValidator::IsColorForMandatory()
{
    return m_clMandatory.IsOk();
}

wxColour wxETKBaseValidator::GetColorForError()
{
    wxASSERT(IsColorForError());
    return m_clError;
}

void wxETKBaseValidator::SetColorForError(const wxColour &_rclError)
{
    m_clError = _rclError;
}

bool wxETKBaseValidator::IsColorForError()
{
    return m_clError.IsOk();
}

void wxETKBaseValidator::SetTextCtrlIfNeeded(wxWindowBase *_pValidatorWindow)
{
    if (_pValidatorWindow != NULL)
    {   // Only if pointer is valid
        if (m_pTextCtrl == NULL)
        {   // Only if not already set
            if (_pValidatorWindow!=NULL && _pValidatorWindow->IsKindOf(CLASSINFO(wxTextCtrl)))
            {
                m_pTextCtrl = dynamic_cast<wxTextCtrl *>(_pValidatorWindow);
                wxASSERT(m_pTextCtrl != NULL); // Must not be NULL
            }
        }
        else
        {   // Must be the same pointer else there is a problem
            wxASSERT(m_pTextCtrl == _pValidatorWindow); // Must be the same
        }
    }
}

void wxETKBaseValidator::ClearError()
{
    if (m_bIsOnError)
    {
        if (GetTextCtrl() != NULL && IsColorForError())
        {   // Put background color back
            GetTextCtrl()->SetBackgroundColour(m_clOldBkColor);
            GetTextCtrl()->Refresh();
        }
        m_bIsOnError = false;
    }
}

void wxETKBaseValidator::SetError()
{
    wxASSERT(GetTextCtrl() != NULL);

    if (GetTextCtrl() != NULL)
    {
        if (IsColorForError())
        {
            if (!m_bIsOnError)
            {
                m_clOldBkColor = GetTextCtrl()->GetBackgroundColour();
                m_bIsOnError   = true;
            }
            GetTextCtrl()->SetBackgroundColour(GetColorForError());
            GetTextCtrl()->Refresh();
        }
        GetTextCtrl()->SetFocus();
    }
}

wxTextCtrl * wxETKBaseValidator::GetTextCtrl() const
{
    return m_pTextCtrl;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                       //
//                                        wxETKTextValidator                                             //
//                                                                                                       //
///////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////

IMPLEMENT_DYNAMIC_CLASS2(wxETKTextValidator,wxTextValidator,wxETKBaseValidator)

BEGIN_EVENT_TABLE(wxETKTextValidator,wxTextValidator)
    EVT_CHAR(wxETKTextValidator::OnChar)
END_EVENT_TABLE()

wxETKTextValidator::wxETKTextValidator(long _lStyle, wxString *_pStringVal,wxWindowBase *_pValidatorWindow)
    : wxTextValidator(_lStyle & ~(wxFILTER_MAX_LENGTH | wxFILTER_MIN_LENGTH),_pStringVal)
    , wxETKBaseValidator(_pValidatorWindow)
    , m_stMinLength(0)
    , m_stMaxLength(0)
{
    if (HasFlag(wxFILTER_EMPTY) && IsColorForMandatory())
    {
        wxASSERT(GetTextCtrl() != NULL); // Must never be null, MUST BE wxTextCtrl window

        if (GetTextCtrl() != NULL)
        {   // Set the specific color for mandatory
            GetTextCtrl()->SetBackgroundColour(GetColorForMandatory());
        }
    }
    if (HasFlag(wxFILTER_UPPERCASE))
    {
        wxASSERT(GetTextCtrl() != NULL); // Must never be null, MUST BE wxTextCtrl window

        if (GetTextCtrl() != NULL)
        {
            GetTextCtrl()->Connect(GetTextCtrl()->GetId(), wxEVT_COMMAND_TEXT_UPDATED, (wxObjectEventFunction) &wxETKTextValidator::OnCommandUpdateChangeToUppercase);
        }
        else
        {   // Remove filter
            wxLogWarning(wxT("Only wxTextCtrl control could have wxFILTER_UPPERCASE style, removing it!"));
            SetStyle(GetStyle() & ~wxFILTER_UPPERCASE); // Remove uppercase style on window that is not a wxTextCtrl
        }
    }
}

wxETKTextValidator::wxETKTextValidator(const wxETKTextValidator& _rValidator)
    : wxTextValidator()
    , wxETKBaseValidator(_rValidator.GetTextCtrl())
{
    wxTextValidator::Copy(_rValidator);
    wxETKBaseValidator::Copy(_rValidator);
    Copy(_rValidator);
}

wxETKTextValidator::~wxETKTextValidator()
{
}

void wxETKTextValidator::SetMinLength(size_t _stMinLength)
{
    wxASSERT(GetTextCtrl() != NULL);
    if (GetTextCtrl() != NULL)
    {
        m_stMinLength = _stMinLength;
        SetStyle(GetStyle() | wxFILTER_MIN_LENGTH); // Add style
    }
}

void wxETKTextValidator::SetMaxLength(int _stMaxLength,bool _bSetMaxLenOnTextCtrl)
{
    wxASSERT(GetTextCtrl() != NULL);
    if (GetTextCtrl() != NULL)
    {
        if (_bSetMaxLenOnTextCtrl)
        {   // Call directly on control
            GetTextCtrl()->SetMaxLength(_stMaxLength);
        }
        m_stMaxLength = _stMaxLength;
        SetStyle(GetStyle() | wxFILTER_MAX_LENGTH); // Add style
    }
}

wxString wxETKTextValidator::IsValid(const wxString& _strVal) const
{
    if ( HasFlag(wxFILTER_ALPHANUMERIC_STRICT) && !wxETKCheckString(wxETKIsAlphaNumrericStrict, _strVal) )
        return _("'%s' should only contain alphabetic characters without accent or numeric characters.");
    if ( HasFlag(wxFILTER_ALPHA_STRICT)        && !wxETKCheckString(wxETKIsAlphaStrict, _strVal) )
        return _("'%s' should only contain alphabetic characters without accent.");

#if wxCHECK_VERSION(2,9,0) // version >= 2.9.0
    return wxTextValidator::IsValid(_strVal);
#else
    return wxEmptyString;
#endif
}

void wxETKTextValidator::OnChar(wxKeyEvent& event)
{
    ClearError();
    bool bError = false;

    // we don't filter special keys and delete
    int iKeyCode = event.GetKeyCode();
    if (iKeyCode < WXK_SPACE || iKeyCode == WXK_DELETE || iKeyCode >= WXK_START)
    {
        event.Skip();
        return;
    }

    if (HasFlag(wxFILTER_UPPERCASE))
    {   // Transform downcase to uppercase. If only some char are allowed like A,B,C, typing
        // 'b' will be refused by base class because here the 'b' is in minus. Transform it to
        // uppercase before this event if filtered by base class

        if (iKeyCode>=_T('a') && iKeyCode<=_T('z'))
        {
            event.m_uniChar = toupper(event.m_uniChar);
            iKeyCode = event.m_keyCode = toupper(iKeyCode);
        }
    }

    wxString str((wxChar) iKeyCode, 1);
    if (!IsValid(str).IsEmpty())
    {
        bError = true;
    }

    if (!bError)
    {   // Char is accepted, throw this event to other class who want this event
        event.Skip();
    }
    else
    {   // Char is refused, ignore it: eat message
        if (!wxTextValidator::IsSilent())
        {
            wxBell();
        }
    }
}

bool wxETKTextValidator::Validate(wxWindow *_pParent)
{
    bool bRet = wxTextValidator::Validate(_pParent);
    SetTextCtrlIfNeeded(GetWindow());
    if (bRet && GetTextCtrl()!=NULL)
    {   // Bloc that will display error message box, already done if error when validate base class
        wxString strError;
#if !wxCHECK_VERSION(2,9,0) // version < 2.9.0
        // wxFILTER_EMPTY is not implemented in wxWidgets 2.8.x or lesser
        if (HasFlag(wxFILTER_EMPTY) && GetTextCtrl()->GetValue().IsEmpty())
        {
            strError = _("Required information entry is empty.");
            bRet = false;
        }
        // IsValid is not called in wxWidgets 2.8.x or lesser (doesn't exists)
        // else error already displayed to the user
        if (bRet && !(strError=IsValid(GetTextCtrl()->GetValue())).IsEmpty())
        {
            strError = wxString::Format(strError,GetTextCtrl()->GetValue().wx_str());
            bRet = false;
        }
#endif
        if (bRet && HasFlag(wxFILTER_MIN_LENGTH) && GetTextCtrl()->GetValue().Len()<m_stMinLength)
        {
            strError = wxString::Format(wxPLURAL("Information entry must be at least %d char length.",
                                                 "Information entry must be at least %d chars length.",
                                                 m_stMinLength
                                                ),
                                        m_stMinLength
                                       );
            bRet = false;
        }
        if (bRet && HasFlag(wxFILTER_MAX_LENGTH) && GetTextCtrl()->GetValue().Len()>m_stMaxLength)
        {
            strError = wxString::Format(wxPLURAL("Information entry must max %d char length.",
                                                 "Information entry must max %d chars length.",
                                                 m_stMaxLength
                                                ),
                                        m_stMaxLength
                                       );
            bRet = false;
        }
        if (!bRet)
        {
            wxMessageBox(strError,wxGetTranslation(_T("Validation conflict")),wxOK | wxICON_EXCLAMATION, _pParent);
            //                                                   ^
            // Already translated by wxWidgets ------------------|
        }
    }
    if (!bRet)
    {
        SetError();
    }
    else
    {   // Put background color back (if needed)
        ClearError();
    }

    return bRet;
}

bool wxETKTextValidator::TransferToWindow()
{
    bool bRet = wxTextValidator::TransferToWindow();
    if (bRet)
    {
        ClearError();
    }
    return bRet;
}

bool wxETKTextValidator::Copy(const wxETKTextValidator& _rValidator)
{
    if (!wxTextValidator::Copy(_rValidator) || !wxETKBaseValidator::Copy(_rValidator))
    {
        return false;
    }
    m_stMinLength = _rValidator.m_stMinLength;
    m_stMaxLength = _rValidator.m_stMaxLength;

    return true;
}

wxObject *wxETKTextValidator::Clone() const
{
    return new wxETKTextValidator(*this);
}

void wxETKTextValidator::OnCommandUpdateChangeToUppercase(wxCommandEvent &_rCommandEvent)
{
    wxTextCtrl *pTextCtrl = dynamic_cast<wxTextCtrl *>(_rCommandEvent.GetEventObject());
    if (pTextCtrl != NULL)
    {
        if (!pTextCtrl->IsModified())
            return;
        long insertionPoint = pTextCtrl->GetInsertionPoint();
        pTextCtrl->ChangeValue(pTextCtrl->GetValue().Upper());
        pTextCtrl->SetInsertionPoint(insertionPoint);
    }
    _rCommandEvent.Skip();
}
bertolino
Experienced Solver
Experienced Solver
Posts: 77
Joined: Wed Aug 14, 2013 8:07 am
Location: France
Contact:

Re: Writing text in upper case in a wxTextCtrl

Post by bertolino »

Feneck91 wrote: Fri Jul 29, 2011 7:46 am Other way very simple :

Code: Select all

void MyClass::BuildContent(wxWindow* _pParent)
{
...
.. init code (for me it is with xrc) ..
...

    m_pTextCtrl->Connect(XRCID("idMyCtrlEdit"), wxEVT_COMMAND_TEXT_UPDATED, (wxObjectEventFunction) &MyClass::OnCommandUpdate);
}

void MyClass::OnKeyDownToUpper(wxCommandEvent &_rCommandEvent)
{
    wxTextCtrl *pTextCtrl = dynamic_cast<wxTextCtrl *>(_rCommandEvent.GetEventObject());
    if (pTextCtrl != NULL)
    {
        if (!pTextCtrl->IsModified())
            return;
        long insertionPoint = pTextCtrl->GetInsertionPoint();
        pTextCtrl->ChangeValue(pTextCtrl->GetValue().Upper());
        pTextCtrl->SetInsertionPoint(insertionPoint);
    }
    _rCommandEvent.Skip();
}
Ten years later, your sharp piece of code still works great. Many thanks for saving me time!
Post Reply