微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在wxGrid的同一个单元格中添加wxTextCtrl和wxButton?

如何解决如何在wxGrid的同一个单元格中添加wxTextCtrl和wxButton?

我创建了一个 wxGrid,我有 3 行和 2 列。我想在同一个单元格中添加 wxTextCtrl 和 wxButton。

pGrid->SetCellValue(3,"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);

解决方法

您需要为此创建一个自定义编辑器,显示您自己的自定义复合窗口,其中包含一个文本控件和一个按钮。

,

这是一个从 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,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,wxGrid* grid) wxOVERRIDE;
    virtual bool EndEdit(int row,const wxGrid* grid,const wxString& oldval,wxString *newval) wxOVERRIDE;
    virtual void ApplyEdit(int row,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,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,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,long style)
{
    wxControl* control = new wxControl(parent,wxDefaultPosition,wxDefaultSize,wxNO_BORDER);
    m_handler = evtHandler;

    style |= wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB | wxNO_BORDER;
    m_text = new wxTextCtrl(control,wxID_ANY,wxEmptyString,style);
    m_text->SetMargins(0,0);

    m_button = new wxButton(control,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,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,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,wxGrid* grid)
{
    grid->GetTable()->SetValue(row,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 上,它看起来像这样:

enter image description here

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。