MinGW – wxWidgets – SlideValue

LastUpdate 2005.09.04 Yoshiaki Ueda
[目次へ戻る]

 数値入力と連動したスライドバーを持つパネルをつくる。ついでにキャプションも表示できるようにする。

■数値入力と連動したスライドバーを持つパネルをつくる


●まずはコントロールを配置する


定義
class yfSlideValue : public wxPanel
{
    wxSlider* m_slider;
public:
    yfSlideValue(wxWindow* parent, wxWindowID id,
            const wxString& label,
            int value, int minValue, int maxValue,
            const wxPoint& point = wxDefaultPosition, const wxSize& size = wxDefaultSize,
            const wxString& name = "slideValue");
    wxSlider* GetSlider();
};
実装
yfSlideValue::yfSlideValue(wxWindow* parent, wxWindowID id,
            const wxString& label,
            int value, int minValue, int maxValue,
            const wxPoint& point /*= wxDefaultPosition*/, const wxSize& size /*= wxDefaultSize*/,
            const wxString& name /*= "slideValue"*/)
    : wxPanel(parent, id, point, size, 0, name)
{
    wxBoxSizer* szTop = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer* szLabel = new wxBoxSizer(wxHORIZONTAL);
    wxControl* control;
   
    control = new wxStaticText(this, -1, label);
    szLabel->Add(control,1,wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxALL,10);

    control = new wxTextCtrl(this, -1, wxString::Format(wxT("%d"),value),
            wxDefaultPosition, wxDefaultSize, wxTE_RIGHT);
    szLabel->Add(control,0,wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxADJUST_MINSIZE|wxALL,10);
   
    szTop->Add(szLabel,0,wxEXPAND);

    m_slider = new wxSlider(this, -1, value, minValue, maxValue);
    szTop->Add(m_slider,0,wxEXPAND,5);

    SetSizer(szTop);
    szTop->SetSizeHints(this);   
}

●スライダーの動きで数値表示を更新する


class yfSlideValue : public wxPanel
{
private:
    void OnSliderScroll(wxScrollEvent& event);
    DECLARE_EVENT_TABLE()
};
BEGIN_EVENT_TABLE(yfSlideValue, wxPanel)
    EVT_COMMAND_SCROLL(IDC_SLIDER, yfSlideValue::OnSliderScroll)
END_EVENT_TABLE()

void yfSlideValue::OnSliderScroll(wxScrollEvent& event)
{
    m_textCtrl->SetValue(wxString::Format(wxT("%d"),event.GetPosition()));
}

●テキストコントロールからフォーカスが離れるのを拾う


 数値入力でスライダを動かすのには多少厄介な問題がある。テキスト更新イベントで動かしたのでは、一桁入力するたびにスライダーが動いてしまう。そもそもテキスト更新イベントは、本当に必要とするとき以外にも、やたら沢山飛んでくる。
 そこでやはり、テキストコントロールからフォーカスが離れるのを拾いたい。

class yfExTextCtrl : public wxTextCtrl
{
protected:
    WXTYPE m_killFocusId;
public:
    yfExTextCtrl();
    void SetKillFocusEvent(WXTYPE id);
private:
    void OnKillFocus(wxFocusEvent& event);
    DECLARE_EVENT_TABLE()
};
yfExTextCtrl::yfExTextCtrl()
    : m_killFocusId(0)
{
}

void yfExTextCtrl::SetKillFocusEvent(WXTYPE id)
{
    m_killFocusId = id;
}

BEGIN_EVENT_TABLE(yfExTextCtrl, wxTextCtrl)
    EVT_KILL_FOCUS(yfExTextCtrl::OnKillFocus) 
END_EVENT_TABLE()

void yfExTextCtrl::OnKillFocus(wxFocusEvent& event)
{
    if( m_killFocusId && GetParent() ){
        wxCommandEvent newEvent(m_killFocusId, GetId());
        GetParent()->ProcessEvent(newEvent);
    }
    event.Skip();
}

●フォーカスが離れたイベントを拾いスライダーを動かす


class yfSlideValue : public wxPanel
{
private:
    void OnTextUpdatePossibility(wxCommandEvent& event);
    DECLARE_EVENT_TABLE()
};
DECLARE_EVENT_TYPE(EVT_TEXT_CTRL_KILL_FOCUS, -1)
DEFINE_EVENT_TYPE(EVT_TEXT_CTRL_KILL_FOCUS)
yfSlideValue::yfSlideValue( .... )
{
    m_textCtrl = new yfExTextCtrl();
    m_textCtrl->Create(this, IDC_TEXT_CTRL, wxString::Format(wxT("%d"),value),
            wxDefaultPosition, wxDefaultSize, wxTE_RIGHT);
    m_textCtrl->SetKillFocusEvent(EVT_TEXT_CTRL_KILL_FOCUS);
    szLabel->Add(m_textCtrl,0,wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxADJUST_MINSIZE|wxALL,10);
}
BEGIN_EVENT_TABLE(yfSlideValue, wxPanel)
    EVT_COMMAND(IDC_TEXT_CTRL,
            EVT_TEXT_CTRL_KILL_FOCUS, yfSlideValue::OnTextUpdatePossibility)
END_EVENT_TABLE()
void yfSlideValue::OnTextUpdatePossibility(wxCommandEvent& event)
{
    if(!(m_slider&&m_textCtrl))return;
    int newValue = atoi(m_textCtrl->GetValue());
    if(newValue>m_maxValue){
        m_textCtrl->SetValue( wxString::Format(wxT("%d"), m_maxValue) );
        newValue = m_maxValue;
    }
    if(newValue<m_minValue){
        m_textCtrl->SetValue( wxString::Format(wxT("%d"), m_minValue) );
        newValue = m_minValue;
    }
    if(m_value!=newValue){
        m_slider->SetValue( m_value = newValue );
    }
}


●Enterキーが押されたときにもスライダーを動かす


 スライダーが動くのが、フォーカスが離れたときだけでは物足りない感じがする。
 ユーザは数値の入力を済ませたつもりでも、いつまでたっても動かない。
 ユーザが数値の入力を済ませたことを伝える手段として、Enterキーの押下を使うことにする。Enterキーが押されたときにもスラーダーを動かすようにする。

BEGIN_EVENT_TABLE(yfSlideValue, wxPanel)
    EVT_TEXT_ENTER(IDC_TEXT_CTRL, yfSlideValue::OnTextUpdatePossibility)
END_EVENT_TABLE()

●wxTextValidatorを試してみる


 テキストコントロールに数字以外の文字が入力されても、われ関せず突っ走ってしまう。
 wxTextValidatorを使うと、そのあたり上手く処理してくれるのだろうか?
 ・・・アラート音を出して、数値入力に必要の無いキーを見事ロックアウトしてくれる。

class yfSlideValue : public wxPanel
{
    wxTextValidator m_textValidator;
};
yfSlideValue::yfSlideValue( .... )
{
    //バリデートのセット
    m_textValidator.SetStyle(wxFILTER_NUMERIC);
    m_textCtrl->SetValidator(m_textValidator);
}