Reputation: 47
I have created a wxGrid, I have 3 rows and 2 columns. I want to add wxTextCtrl and wxButton in the same cell.
pGrid->SetCellValue(3,0,"Label");
wxBoxSizer *hSizer = new wxBoxSizer(wxHORIZONTAL);
wxTextCtrl *txt = new wxTextCtrl(this, ID, "");
wxButton *btn = new wxButton(this, ID2, "OK");
hSizer->Add(txt);
hSizer->Add(btn);
pGrid->SetCellRenderer(3,1, hSizer);
Upvotes: 0
Views: 521
Reputation: 3554
Here's an example that's 95% cut and paste from the wxGridCellTextEditor class.
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();
}
On windows it looks like this:
This code throws an event derived from wxCommandEvent with type gridEVT_BUTTON when it is clicked. It doesn't include any other information, but the code could be adjusted to include the row and column (for example in the Int and ExtraLong fields of the event) if desired.
Upvotes: 1
Reputation: 22678
You will need to create a custom editor for this, showing your own custom compound window with a text control and a button in it.
Upvotes: 2