combobox.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,047 行 · 第 1/2 页
CPP
1,047 行
/////////////////////////////////////////////////////////////////////////////
// Name: univ/combobox.cpp
// Purpose: wxComboControl and wxComboBox implementation
// Author: Vadim Zeitlin
// Modified by:
// Created: 15.12.00
// RCS-ID: $Id: combobox.cpp,v 1.42 2005/05/31 09:28:45 JS Exp $
// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "univcombobox.h"
#endif
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_COMBOBOX
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/button.h"
#include "wx/combobox.h"
#include "wx/listbox.h"
#include "wx/textctrl.h"
#include "wx/bmpbuttn.h"
#include "wx/validate.h"
#endif
#include "wx/tooltip.h"
#include "wx/popupwin.h"
#include "wx/univ/renderer.h"
#include "wx/univ/inphand.h"
#include "wx/univ/theme.h"
/*
The keyboard event flow:
1. they always come to the text ctrl
2. it forwards the ones it doesn't process to the wxComboControl
3. which passes them to the popup window if it is popped up
*/
// constants
// ----------------------------------------------------------------------------
// the margin between the text control and the combo button
static const wxCoord g_comboMargin = 2;
// ----------------------------------------------------------------------------
// wxComboButton is just a normal button except that it sends commands to the
// combobox and not its parent
// ----------------------------------------------------------------------------
class wxComboButton : public wxBitmapButton
{
public:
wxComboButton(wxComboControl *combo)
: wxBitmapButton(combo->GetParent(), wxID_ANY, wxNullBitmap,
wxDefaultPosition, wxDefaultSize,
wxBORDER_NONE | wxBU_EXACTFIT)
{
m_combo = combo;
wxBitmap bmpNormal, bmpFocus, bmpPressed, bmpDisabled;
GetRenderer()->GetComboBitmaps(&bmpNormal,
&bmpFocus,
&bmpPressed,
&bmpDisabled);
SetBitmapLabel(bmpNormal);
SetBitmapFocus(bmpFocus.Ok() ? bmpFocus : bmpNormal);
SetBitmapSelected(bmpPressed.Ok() ? bmpPressed : bmpNormal);
SetBitmapDisabled(bmpDisabled.Ok() ? bmpDisabled : bmpNormal);
SetBestSize(wxDefaultSize);
}
protected:
void OnButton(wxCommandEvent& WXUNUSED(event)) { m_combo->ShowPopup(); }
virtual wxSize DoGetBestClientSize() const
{
const wxBitmap& bmp = GetBitmapLabel();
return wxSize(bmp.GetWidth(), bmp.GetHeight());
}
private:
wxComboControl *m_combo;
DECLARE_EVENT_TABLE()
};
// ----------------------------------------------------------------------------
// wxComboListBox is a listbox modified to be used as a popup window in a
// combobox
// ----------------------------------------------------------------------------
class wxComboListBox : public wxListBox, public wxComboPopup
{
public:
// ctor and dtor
wxComboListBox(wxComboControl *combo, int style = 0);
virtual ~wxComboListBox();
// implement wxComboPopup methods
virtual bool SetSelection(const wxString& s);
virtual wxControl *GetControl() { return this; }
virtual void OnShow();
virtual wxCoord GetBestWidth() const;
// fix virtual function hiding
virtual void SetSelection(int n) { DoSetSelection(n, true); }
void SetSelection(int n, bool select) { DoSetSelection(n, select); }
protected:
// we shouldn't return height too big from here
virtual wxSize DoGetBestClientSize() const;
// filter mouse move events happening outside the list box
void OnMouseMove(wxMouseEvent& event);
// set m_clicked value from here
void OnLeftUp(wxMouseEvent& event);
// called whenever the user selects or activates a listbox item
void OnSelect(wxCommandEvent& event);
// used to process wxUniv actions
bool PerformAction(const wxControlAction& action,
long numArg,
const wxString& strArg);
private:
// has the mouse been released on this control?
bool m_clicked;
DECLARE_EVENT_TABLE()
};
// ----------------------------------------------------------------------------
// wxComboTextCtrl is a simple text ctrl which forwards
// wxEVT_COMMAND_TEXT_UPDATED events and all key events to the combobox
// ----------------------------------------------------------------------------
class wxComboTextCtrl : public wxTextCtrl
{
public:
wxComboTextCtrl(wxComboControl *combo,
const wxString& value,
long style,
const wxValidator& validator);
protected:
void OnKey(wxKeyEvent& event);
void OnText(wxCommandEvent& event);
private:
wxComboControl *m_combo;
DECLARE_EVENT_TABLE()
};
// ----------------------------------------------------------------------------
// event tables and such
// ----------------------------------------------------------------------------
BEGIN_EVENT_TABLE(wxComboButton, wxButton)
EVT_BUTTON(wxID_ANY, wxComboButton::OnButton)
END_EVENT_TABLE()
BEGIN_EVENT_TABLE(wxComboListBox, wxListBox)
EVT_LISTBOX(wxID_ANY, wxComboListBox::OnSelect)
EVT_LISTBOX_DCLICK(wxID_ANY, wxComboListBox::OnSelect)
EVT_MOTION(wxComboListBox::OnMouseMove)
EVT_LEFT_UP(wxComboListBox::OnLeftUp)
END_EVENT_TABLE()
BEGIN_EVENT_TABLE(wxComboControl, wxControl)
EVT_KEY_DOWN(wxComboControl::OnKey)
EVT_KEY_UP(wxComboControl::OnKey)
END_EVENT_TABLE()
BEGIN_EVENT_TABLE(wxComboTextCtrl, wxTextCtrl)
EVT_KEY_DOWN(wxComboTextCtrl::OnKey)
EVT_KEY_UP(wxComboTextCtrl::OnKey)
EVT_TEXT(wxID_ANY, wxComboTextCtrl::OnText)
END_EVENT_TABLE()
IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl)
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxComboControl creation
// ----------------------------------------------------------------------------
void wxComboControl::Init()
{
m_popup = (wxComboPopup *)NULL;
m_winPopup = (wxPopupComboWindow *)NULL;
m_isPopupShown = false;
m_btn = NULL;
m_text = NULL;
}
bool wxComboControl::Create(wxWindow *parent,
wxWindowID id,
const wxString& value,
const wxPoint& pos,
const wxSize& size,
long style,
const wxValidator& validator,
const wxString& name)
{
// first create our own window, i.e. the one which will contain all
// subcontrols
style &= ~wxBORDER_NONE;
style |= wxBORDER_SUNKEN;
if ( !wxControl::Create(parent, id, pos, size, style, validator, name) )
return false;
// create the text control and the button as our siblings (*not* children),
// don't care about size/position here - they will be set in DoMoveWindow()
m_btn = new wxComboButton(this);
m_text = new wxComboTextCtrl(this,
value,
style & wxCB_READONLY ? wxTE_READONLY : 0,
validator);
// for compatibility with the other ports, the height specified is the
// combined height of the combobox itself and the popup
if ( size.y == wxDefaultCoord )
{
// ok, use default height for popup too
m_heightPopup = wxDefaultCoord;
}
else
{
m_heightPopup = size.y - DoGetBestSize().y;
}
SetBestSize(size);
Move(pos);
// create the popup window immediately here to allow creating the controls
// with parent == GetPopupWindow() from the derived class ctor
m_winPopup = new wxPopupComboWindow(this);
// have to disable this window to avoid interfering it with message
// processing to the text and the button... but pretend it is enabled to
// make IsEnabled() return true
wxControl::Enable(false); // don't use non virtual Disable() here!
m_isEnabled = true;
CreateInputHandler(wxINP_HANDLER_COMBOBOX);
return true;
}
wxComboControl::~wxComboControl()
{
// as the button and the text control are the parent's children and not
// ours, we have to delete them manually - they are not deleted
// automatically by wxWidgets when we're deleted
delete m_btn;
delete m_text;
delete m_winPopup;
}
// ----------------------------------------------------------------------------
// geometry stuff
// ----------------------------------------------------------------------------
void wxComboControl::DoSetSize(int x, int y,
int width, int WXUNUSED(height),
int sizeFlags)
{
// combo height is always fixed
wxControl::DoSetSize(x, y, width, DoGetBestSize().y, sizeFlags);
}
wxSize wxComboControl::DoGetBestClientSize() const
{
wxSize sizeBtn = m_btn->GetBestSize(),
sizeText = m_text->GetBestSize();
wxCoord widthPopup = 0;
if (m_popup)
{
widthPopup = m_popup->GetBestWidth();
}
return wxSize(wxMax(sizeText.x + g_comboMargin + sizeBtn.x, widthPopup),
wxMax(sizeBtn.y, sizeText.y));
}
void wxComboControl::DoMoveWindow(int x, int y, int width, int height)
{
wxControl::DoMoveWindow(x, y, width, height);
// position the subcontrols inside the client area
wxRect rectBorders = GetRenderer()->GetBorderDimensions(GetBorder());
x += rectBorders.x;
y += rectBorders.y;
width -= rectBorders.x + rectBorders.width;
height -= rectBorders.y + rectBorders.height;
wxSize sizeBtn = m_btn->GetBestSize();
wxCoord wText = width - sizeBtn.x;
wxPoint p = GetParent() ? GetParent()->GetClientAreaOrigin() : wxPoint(0,0);
m_text->SetSize(x - p.x, y - p.y, wText, height);
m_btn->SetSize(x - p.x + wText, y - p.y, sizeBtn.x, height);
}
// ----------------------------------------------------------------------------
// operations
// ----------------------------------------------------------------------------
bool wxComboControl::Enable(bool enable)
{
if ( !wxControl::Enable(enable) )
return false;
m_btn->Enable(enable);
m_text->Enable(enable);
return true;
}
bool wxComboControl::Show(bool show)
{
if ( !wxControl::Show(show) )
return false;
if (m_btn)
m_btn->Show(show);
if (m_text)
m_text->Show(show);
return true;
}
#if wxUSE_TOOLTIPS
void wxComboControl::DoSetToolTip(wxToolTip *tooltip)
{
wxControl::DoSetToolTip(tooltip);
// Set tool tip for button and text box
if (m_text && m_btn)
{
if (tooltip)
{
const wxString &tip = tooltip->GetTip();
m_text->SetToolTip(tip);
m_btn->SetToolTip(tip);
}
else
{
m_text->SetToolTip(NULL);
m_btn->SetToolTip(NULL);
}
}
}
#endif // wxUSE_TOOLTIPS
// ----------------------------------------------------------------------------
// popup window handling
// ----------------------------------------------------------------------------
void wxComboControl::SetPopupControl(wxComboPopup *popup)
{
m_popup = popup;
}
void wxComboControl::ShowPopup()
{
wxCHECK_RET( m_popup, _T("no popup to show in wxComboControl") );
wxCHECK_RET( !IsPopupShown(), _T("popup window already shown") );
wxControl *control = m_popup->GetControl();
// size and position the popup window correctly
m_winPopup->SetSize(GetSize().x,
m_heightPopup == wxDefaultCoord ? control->GetBestSize().y
: m_heightPopup);
wxSize sizePopup = m_winPopup->GetClientSize();
control->SetSize(0, 0, sizePopup.x, sizePopup.y);
// some controls don't accept the size we give then: e.g. a listbox may
// require more space to show its last row
wxSize sizeReal = control->GetSize();
if ( sizeReal != sizePopup )
{
m_winPopup->SetClientSize(sizeReal);
}
m_winPopup->PositionNearCombo();
// show it
m_popup->OnShow();
m_winPopup->Popup(m_text);
m_text->SelectAll();
m_popup->SetSelection(m_text->GetValue());
m_isPopupShown = true;
}
void wxComboControl::HidePopup()
{
wxCHECK_RET( m_popup, _T("no popup to hide in wxComboControl") );
wxCHECK_RET( IsPopupShown(), _T("popup window not shown") );
m_winPopup->Dismiss();
m_isPopupShown = false;
}
void wxComboControl::OnSelect(const wxString& value)
{
m_text->SetValue(value);
m_text->SelectAll();
OnDismiss();
}
void wxComboControl::OnDismiss()
{
HidePopup();
m_text->SetFocus();
}
// ----------------------------------------------------------------------------
// wxComboTextCtrl
// ----------------------------------------------------------------------------
wxComboTextCtrl::wxComboTextCtrl(wxComboControl *combo,
const wxString& value,
long style,
const wxValidator& validator)
: wxTextCtrl(combo->GetParent(), wxID_ANY, value,
wxDefaultPosition, wxDefaultSize,
wxBORDER_NONE | style,
validator)
{
m_combo = combo;
}
void wxComboTextCtrl::OnText(wxCommandEvent& event)
{
if ( m_combo->IsPopupShown() )
{
m_combo->GetPopupControl()->SetSelection(GetValue());
}
// we need to make a copy of the event to have the correct originating
// object and id
wxCommandEvent event2 = event;
event2.SetEventObject(m_combo);
event2.SetId(m_combo->GetId());
// there is a small incompatibility with wxMSW here: the combobox gets the
// event before the text control in our case which corresponds to SMW
// CBN_EDITUPDATE notification and not CBN_EDITCHANGE one wxMSW currently
// uses
//
// if this is really a problem, we can play games with the event handlers
// to circumvent this
(void)m_combo->ProcessEvent(event2);
event.Skip();
}
// pass the keys we don't process to the combo first
void wxComboTextCtrl::OnKey(wxKeyEvent& event)
{
switch ( event.GetKeyCode() )
{
case WXK_RETURN:
// the popup control gets it first but only if it is shown
if ( !m_combo->IsPopupShown() )
break;
//else: fall through
case WXK_UP:
case WXK_DOWN:
case WXK_ESCAPE:
case WXK_PAGEDOWN:
case WXK_PAGEUP:
case WXK_PRIOR:
case WXK_NEXT:
(void)m_combo->ProcessEvent(event);
return;
}
event.Skip();
}
// ----------------------------------------------------------------------------
// wxComboListBox
// ----------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?