这是一个从 wxGridCellTextEditor 类中剪切和粘贴 95% 的示例。
static wxRect AdjustRectForPlatform(const wxRect& rectOrig)
{
wxRect rect(rectOrig);
// // Make the edit control large enough to allow for internal margins
// //
// // TODO: remove this if the text ctrl sizing is improved esp. for unix
// //
#if defined(__WXGTK__)
if (rect.x != 0)
{
rect.x += 1;
rect.y += 1;
rect.width -= 1;
rect.height -= 1;
}
#elif defined(__WXMSW__)
if ( rect.x == 0 )
rect.x += 2;
else
rect.x += 3;
if ( rect.y == 0 )
rect.y += 2;
else
rect.y += 3;
rect.width -= 2;
rect.height -= 2;
#elif defined(__WXOSX__)
rect.x += 1;
rect.y += 1;
rect.width -= 1;
rect.height -= 1;
#else
int extra_x = ( rect.x > 2 ) ? 2 : 1;
int extra_y = ( rect.y > 2 ) ? 2 : 1;
#if defined(__WXMOTIF__)
extra_x *= 2;
extra_y *= 2;
#endif
rect.SetLeft( wxMax(0, rect.x - extra_x) );
rect.SetTop( wxMax(0, rect.y - extra_y) );
rect.SetRight( rect.GetRight() + 2 * extra_x );
rect.SetBottom( rect.GetBottom() + 2 * extra_y );
#endif
return rect;
}
wxDEFINE_EVENT(gridEVT_BUTTON, wxCommandEvent);
class wxGridCellStringAndButtonRenderer: public wxGridCellStringRenderer
{
public:
wxGridCellStringAndButtonRenderer():wxGridCellStringRenderer(){}
virtual void Draw(wxGrid &grid, wxGridCellAttr &attr, wxDC &dc,
const wxRect &rect, int row, int col, bool isSelected)
{
dc.SetBackground(attr.GetBackgroundColour());
dc.Clear();
// Draw the text.
wxRect adjRect = AdjustRectForPlatform(rect);
int buttonHeight = adjRect.GetHeight();
wxRect textRect = rect;
textRect.SetWidth(rect.GetWidth() - buttonHeight);
wxGridCellStringRenderer::Draw(grid, attr, dc, textRect,
row, col, isSelected);
// Draw the button.
wxRendererNative& renderer = wxRendererNative::GetDefault();
const int buttonLeft = rect.GetLeft()+rect.GetWidth()-buttonHeight;
const int buttonTop = adjRect.GetTop()-1;
wxSize buttonSize = wxSize(buttonHeight,buttonHeight);
wxRect rect3 = wxRect(wxPoint(buttonLeft,buttonTop),buttonSize);
renderer.DrawPushButton(&grid,dc,rect3);
}
};
class wxGridCellTextAndButtonEditor : public wxGridCellEditor
{
public:
explicit wxGridCellTextAndButtonEditor(size_t maxChars = 0);
virtual void Create(wxWindow* parent,
wxWindowID id,
wxEvtHandler* evtHandler) wxOVERRIDE;
virtual void SetSize(const wxRect& rect) wxOVERRIDE;
virtual void PaintBackground(wxDC& dc,
const wxRect& rectCell,
const wxGridCellAttr& attr) wxOVERRIDE;
virtual bool IsAcceptedKey(wxKeyEvent& event) wxOVERRIDE;
virtual void BeginEdit(int row, int col, wxGrid* grid) wxOVERRIDE;
virtual bool EndEdit(int row, int col, const wxGrid* grid,
const wxString& oldval, wxString *newval) wxOVERRIDE;
virtual void ApplyEdit(int row, int col, wxGrid* grid) wxOVERRIDE;
virtual void Reset() wxOVERRIDE;
virtual void StartingKey(wxKeyEvent& event) wxOVERRIDE;
virtual void HandleReturn(wxKeyEvent& event) wxOVERRIDE;
// parameters string format is "max_width"
virtual void SetParameters(const wxString& params) wxOVERRIDE;
#if wxUSE_VALIDATORS
virtual void SetValidator(const wxValidator& validator);
#endif
virtual wxGridCellEditor *Clone() const wxOVERRIDE;
// added GetValue so we can get the value which is in the control
virtual wxString GetValue() const wxOVERRIDE;
protected:
// parts of our virtual functions reused by the derived classes
void DoCreate(wxWindow* parent, wxWindowID id, wxEvtHandler* evtHandler,
long style = 0);
void DoBeginEdit(const wxString& startValue);
void DoReset(const wxString& startValue);
void OnButton(wxCommandEvent&);
private:
size_t m_maxChars; // max number of chars allowed
#if wxUSE_VALIDATORS
wxScopedPtr<wxValidator> m_validator;
#endif
wxString m_value;
wxDECLARE_NO_COPY_CLASS(wxGridCellTextAndButtonEditor);
wxEvtHandler* m_handler;
wxTextCtrl* m_text;
wxButton* m_button;
};
wxGridCellTextAndButtonEditor::wxGridCellTextAndButtonEditor(size_t maxChars)
{
m_maxChars = maxChars;
}
void wxGridCellTextAndButtonEditor::Create(wxWindow* parent,
wxWindowID id,
wxEvtHandler* evtHandler)
{
DoCreate(parent, id, evtHandler);
}
void wxGridCellTextAndButtonEditor::OnButton(wxCommandEvent&)
{
wxCommandEvent event(gridEVT_BUTTON);
m_handler->ProcessEvent(event);
m_text->SetFocus();
}
void wxGridCellTextAndButtonEditor::DoCreate(wxWindow* parent,
wxWindowID id,
wxEvtHandler* evtHandler,
long style)
{
wxControl* control = new wxControl(parent, id, wxDefaultPosition,
wxDefaultSize, wxNO_BORDER);
m_handler = evtHandler;
style |= wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB | wxNO_BORDER;
m_text = new wxTextCtrl(control, wxID_ANY, wxEmptyString,
wxDefaultPosition, wxDefaultSize,
style);
m_text->SetMargins(0, 0);
m_button = new wxButton(control,wxID_ANY,wxString());
m_button->Bind(wxEVT_BUTTON,&wxGridCellTextAndButtonEditor::OnButton,this);
m_control = control;
wxBoxSizer* szr = new wxBoxSizer(wxHORIZONTAL);
szr->Add(m_text,wxSizerFlags(1));
szr->Add(m_button,wxSizerFlags());
control->SetSizer(szr);
#ifdef __WXOSX__
wxWidgetImpl* impl = m_text->GetPeer();
impl->SetNeedsFocusRect(false);
#endif
// set max length allowed in the textctrl, if the parameter was set
if ( m_maxChars != 0 )
{
m_text->SetMaxLength(m_maxChars);
}
#if wxUSE_VALIDATORS
// validate text in textctrl, if validator is set
if ( m_validator )
{
m_text->SetValidator(*m_validator);
}
#endif
wxGridCellEditor::Create(parent, id, evtHandler);
}
void wxGridCellTextAndButtonEditor::PaintBackground(wxDC& dc,
const wxRect& WXUNUSED(rectCell),
const wxGridCellAttr& WXUNUSED(attr))
{
// as we fill the entire client area,
// don't do anything here to minimize flicker
}
void wxGridCellTextAndButtonEditor::SetSize(const wxRect& rectOrig)
{
wxRect rect = AdjustRectForPlatform(rectOrig);
m_button->SetMinSize(wxSize(rect.GetHeight(),rect.GetHeight()));
m_button->SetMaxSize(wxSize(rect.GetHeight(),rect.GetHeight()));
wxGridCellEditor::SetSize(rect);
}
void wxGridCellTextAndButtonEditor::BeginEdit(int row, int col, wxGrid* grid)
{
wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
m_value = grid->GetTable()->GetValue(row, col);
DoBeginEdit(m_value);
}
void wxGridCellTextAndButtonEditor::DoBeginEdit(const wxString& startValue)
{
m_text->SetValue(startValue);
m_text->SetInsertionPointEnd();
m_text->SelectAll();
m_text->SetFocus();
m_control->Layout();
}
bool wxGridCellTextAndButtonEditor::EndEdit(int WXUNUSED(row),
int WXUNUSED(col),
const wxGrid* WXUNUSED(grid),
const wxString& WXUNUSED(oldval),
wxString *newval)
{
wxCHECK_MSG( m_control, false,
"wxGridCellTextAndButtonEditor must be created first!" );
const wxString value = m_text->GetValue();
if ( value == m_value )
return false;
m_value = value;
if ( newval )
*newval = m_value;
return true;
}
void wxGridCellTextAndButtonEditor::ApplyEdit(int row, int col, wxGrid* grid)
{
grid->GetTable()->SetValue(row, col, m_value);
m_value.clear();
}
void wxGridCellTextAndButtonEditor::Reset()
{
wxASSERT_MSG( m_control, "wxGridCellTextAndButtonEditor must be created first!" );
DoReset(m_value);
}
void wxGridCellTextAndButtonEditor::DoReset(const wxString& startValue)
{
m_text->SetValue(startValue);
m_text->SetInsertionPointEnd();
}
bool wxGridCellTextAndButtonEditor::IsAcceptedKey(wxKeyEvent& event)
{
switch ( event.GetKeyCode() )
{
case WXK_DELETE:
case WXK_BACK:
return true;
default:
return wxGridCellEditor::IsAcceptedKey(event);
}
}
void wxGridCellTextAndButtonEditor::StartingKey(wxKeyEvent& event)
{
// Since this is now happening in the EVT_CHAR event EmulateKeyPress is no
// longer an appropriate way to get the character into the text control.
// Do it ourselves instead. We know that if we get this far that we have
// a valid character, so not a whole lot of testing needs to be done.
int ch;
bool isPrintable;
#if wxUSE_UNICODE
ch = event.GetUnicodeKey();
if ( ch != WXK_NONE )
isPrintable = true;
else
#endif // wxUSE_UNICODE
{
ch = event.GetKeyCode();
isPrintable = ch >= WXK_SPACE && ch < WXK_START;
}
switch (ch)
{
case WXK_DELETE:
// Delete the initial character when starting to edit with DELETE.
m_text->Remove(0, 1);
break;
case WXK_BACK:
// Delete the last character when starting to edit with BACKSPACE.
{
const long pos = m_text->GetLastPosition();
m_text->Remove(pos - 1, pos);
}
break;
default:
if ( isPrintable )
m_text->WriteText(static_cast<wxChar>(ch));
break;
}
}
void wxGridCellTextAndButtonEditor::HandleReturn( wxKeyEvent& event )
{
#if defined(__WXMOTIF__) || defined(__WXGTK__)
// wxMotif needs a little extra help...
size_t pos = (size_t)( Text()->GetInsertionPoint() );
wxString s( Text()->GetValue() );
s = s.Left(pos) + wxT("\n") + s.Mid(pos);
Text()->SetValue(s);
Text()->SetInsertionPoint( pos );
#else
// the other ports can handle a Return key press
//
event.Skip();
#endif
}
void wxGridCellTextAndButtonEditor::SetParameters(const wxString& params)
{
if ( !params )
{
// reset to default
m_maxChars = 0;
}
else
{
long tmp;
if ( params.ToLong(&tmp) )
{
m_maxChars = (size_t)tmp;
}
else
{
wxLogDebug( wxT("Invalid wxGridCellTextAndButtonEditor parameter string '%s' ignored"), params.c_str() );
}
}
}
#if wxUSE_VALIDATORS
void wxGridCellTextAndButtonEditor::SetValidator(const wxValidator& validator)
{
m_validator.reset(static_cast<wxValidator*>(validator.Clone()));
}
#endif
wxGridCellEditor *wxGridCellTextAndButtonEditor::Clone() const
{
wxGridCellTextAndButtonEditor* editor = new wxGridCellTextAndButtonEditor(m_maxChars);
#if wxUSE_VALIDATORS
if ( m_validator )
{
editor->SetValidator(*m_validator);
}
#endif
return editor;
}
// return the value in the text control
wxString wxGridCellTextAndButtonEditor::GetValue() const
{
return m_text->GetValue();
}
在 Windows 上,它看起来像这样:

此代码在单击时引发一个从 wxCommandEvent 派生的事件,类型为 gridEVT_BUTTON。它不包含任何其他信息,但如果需要,可以调整代码以包含行和列(例如在事件的 Int 和 ExtraLong 字段中)。