listbox.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,516 行 · 第 1/3 页
CPP
1,516 行
/////////////////////////////////////////////////////////////////////////////
// Name: univ/listbox.cpp
// Purpose: wxListBox implementation
// Author: Vadim Zeitlin
// Modified by:
// Created: 30.08.00
// RCS-ID: $Id: listbox.cpp,v 1.31 2005/02/13 17:08:27 VZ Exp $
// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "univlistbox.h"
#endif
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_LISTBOX
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/dcclient.h"
#include "wx/listbox.h"
#include "wx/validate.h"
#endif
#include "wx/univ/renderer.h"
#include "wx/univ/inphand.h"
#include "wx/univ/theme.h"
// ============================================================================
// implementation of wxListBox
// ============================================================================
IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl)
BEGIN_EVENT_TABLE(wxListBox, wxListBoxBase)
EVT_SIZE(wxListBox::OnSize)
END_EVENT_TABLE()
// ----------------------------------------------------------------------------
// construction
// ----------------------------------------------------------------------------
void wxListBox::Init()
{
// will be calculated later when needed
m_lineHeight = 0;
m_itemsPerPage = 0;
m_maxWidth = 0;
m_scrollRangeY = 0;
m_maxWidthItem = -1;
m_strings = NULL;
// no items hence no current item
m_current = -1;
m_selAnchor = -1;
m_currentChanged = false;
// no need to update anything initially
m_updateCount = 0;
// no scrollbars to show nor update
m_updateScrollbarX =
m_showScrollbarX =
m_updateScrollbarY =
m_showScrollbarY = false;
}
wxListBox::wxListBox(wxWindow *parent,
wxWindowID id,
const wxPoint &pos,
const wxSize &size,
const wxArrayString& choices,
long style,
const wxValidator& validator,
const wxString &name)
{
Init();
Create(parent, id, pos, size, choices, style, validator, name);
}
bool wxListBox::Create(wxWindow *parent,
wxWindowID id,
const wxPoint &pos,
const wxSize &size,
const wxArrayString& choices,
long style,
const wxValidator& validator,
const wxString &name)
{
wxCArrayString chs(choices);
return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
style, validator, name);
}
bool wxListBox::Create(wxWindow *parent,
wxWindowID id,
const wxPoint &pos,
const wxSize &size,
int n,
const wxString choices[],
long style,
const wxValidator& validator,
const wxString &name)
{
// for compatibility accept both the new and old styles - they mean the
// same thing for us
if ( style & wxLB_ALWAYS_SB )
style |= wxALWAYS_SHOW_SB;
// if we don't have neither multiple nor extended flag, we must have the
// single selection listbox
if ( !(style & (wxLB_MULTIPLE | wxLB_EXTENDED)) )
style |= wxLB_SINGLE;
#if wxUSE_TWO_WINDOWS
style |= wxVSCROLL|wxHSCROLL;
if ((style & wxBORDER_MASK) == 0)
style |= wxBORDER_SUNKEN;
#endif
if ( !wxControl::Create(parent, id, pos, size, style,
validator, name) )
return false;
SetWindow(this);
m_strings = new wxArrayString;
Set(n, choices);
SetBestSize(size);
CreateInputHandler(wxINP_HANDLER_LISTBOX);
return true;
}
wxListBox::~wxListBox()
{
// call this just to free the client data -- and avoid leaking memory
DoClear();
delete m_strings;
m_strings = NULL;
}
// ----------------------------------------------------------------------------
// adding/inserting strings
// ----------------------------------------------------------------------------
int wxCMPFUNC_CONV wxListBoxSortNoCase(wxString* s1, wxString* s2)
{
return s1->CmpNoCase(*s2);
}
int wxListBox::DoAppendOnly(const wxString& item)
{
size_t index;
if ( IsSorted() )
{
m_strings->Add(item);
m_strings->Sort(wxListBoxSortNoCase);
index = m_strings->Index(item);
}
else
{
index = m_strings->GetCount();
m_strings->Add(item);
}
return index;
}
int wxListBox::DoAppend(const wxString& item)
{
size_t index = DoAppendOnly( item );
m_itemsClientData.Insert(NULL, index);
m_updateScrollbarY = true;
if ( HasHorzScrollbar() )
{
// has the max width increased?
wxCoord width;
GetTextExtent(item, &width, NULL);
if ( width > m_maxWidth )
{
m_maxWidth = width;
m_maxWidthItem = index;
m_updateScrollbarX = true;
}
}
RefreshFromItemToEnd(index);
return index;
}
void wxListBox::DoInsertItems(const wxArrayString& items, int pos)
{
// the position of the item being added to a sorted listbox can't be
// specified
wxCHECK_RET( !IsSorted(), _T("can't insert items into sorted listbox") );
size_t count = items.GetCount();
for ( size_t n = 0; n < count; n++ )
{
m_strings->Insert(items[n], pos + n);
m_itemsClientData.Insert(NULL, pos + n);
}
// the number of items has changed so we might have to show the scrollbar
m_updateScrollbarY = true;
// the max width also might have changed - just recalculate it instead of
// keeping track of it here, this is probably more efficient for a typical
// use pattern
RefreshHorzScrollbar();
// note that we have to refresh all the items after the ones we inserted,
// not just these items
RefreshFromItemToEnd(pos);
}
void wxListBox::DoSetItems(const wxArrayString& items, void **clientData)
{
DoClear();
size_t count = items.GetCount();
if ( !count )
return;
m_strings->Alloc(count);
m_itemsClientData.Alloc(count);
for ( size_t n = 0; n < count; n++ )
{
size_t index = DoAppendOnly(items[n]);
m_itemsClientData.Insert(clientData ? clientData[n] : NULL, index);
}
m_updateScrollbarY = true;
RefreshAll();
}
void wxListBox::SetString(int n, const wxString& s)
{
wxCHECK_RET( !IsSorted(), _T("can't set string in sorted listbox") );
(*m_strings)[n] = s;
if ( HasHorzScrollbar() )
{
// we need to update m_maxWidth as changing the string may cause the
// horz scrollbar [dis]appear
wxCoord width;
GetTextExtent(s, &width, NULL);
// it might have increased if the new string is long
if ( width > m_maxWidth )
{
m_maxWidth = width;
m_maxWidthItem = n;
m_updateScrollbarX = true;
}
// or also decreased if the old string was the longest one
else if ( n == m_maxWidthItem )
{
RefreshHorzScrollbar();
}
}
RefreshItem(n);
}
// ----------------------------------------------------------------------------
// removing strings
// ----------------------------------------------------------------------------
void wxListBox::DoClear()
{
m_strings->Clear();
if ( HasClientObjectData() )
{
size_t count = m_itemsClientData.GetCount();
for ( size_t n = 0; n < count; n++ )
{
delete (wxClientData *) m_itemsClientData[n];
}
}
m_itemsClientData.Clear();
m_selections.Clear();
m_current = -1;
}
void wxListBox::Clear()
{
DoClear();
m_updateScrollbarY = true;
RefreshHorzScrollbar();
RefreshAll();
}
void wxListBox::Delete(int n)
{
wxCHECK_RET( n >= 0 && n < GetCount(),
_T("invalid index in wxListBox::Delete") );
// do it before removing the index as otherwise the last item will not be
// refreshed (as GetCount() will be decremented)
RefreshFromItemToEnd(n);
m_strings->RemoveAt(n);
if ( HasClientObjectData() )
{
delete (wxClientData *)m_itemsClientData[n];
}
m_itemsClientData.RemoveAt(n);
// when the item disappears we must not keep using its index
if ( n == m_current )
{
m_current = -1;
}
else if ( n < m_current )
{
m_current--;
}
//else: current item may stay
// update the selections array: the indices of all seletected items after
// the one being deleted must change and the item itselfm ust be removed
int index = wxNOT_FOUND;
size_t count = m_selections.GetCount();
for ( size_t item = 0; item < count; item++ )
{
if ( m_selections[item] == n )
{
// remember to delete it later
index = item;
}
else if ( m_selections[item] > n )
{
// to account for the index shift
m_selections[item]--;
}
//else: nothing changed for this one
}
if ( index != wxNOT_FOUND )
{
m_selections.RemoveAt(index);
}
// the number of items has changed, hence the scrollbar may disappear
m_updateScrollbarY = true;
// finally, if the longest item was deleted the scrollbar may disappear
if ( n == m_maxWidthItem )
{
RefreshHorzScrollbar();
}
}
// ----------------------------------------------------------------------------
// client data handling
// ----------------------------------------------------------------------------
void wxListBox::DoSetItemClientData(int n, void* clientData)
{
m_itemsClientData[n] = clientData;
}
void *wxListBox::DoGetItemClientData(int n) const
{
return m_itemsClientData[n];
}
void wxListBox::DoSetItemClientObject(int n, wxClientData* clientData)
{
m_itemsClientData[n] = clientData;
}
wxClientData* wxListBox::DoGetItemClientObject(int n) const
{
return (wxClientData *)m_itemsClientData[n];
}
// ----------------------------------------------------------------------------
// selection
// ----------------------------------------------------------------------------
void wxListBox::DoSetSelection(int n, bool select)
{
if ( select )
{
if ( m_selections.Index(n) == wxNOT_FOUND )
{
if ( !HasMultipleSelection() )
{
// selecting an item in a single selection listbox deselects
// all the others
DeselectAll();
}
m_selections.Add(n);
RefreshItem(n);
}
//else: already selected
}
else // unselect
{
int index = m_selections.Index(n);
if ( index != wxNOT_FOUND )
{
m_selections.RemoveAt(index);
RefreshItem(n);
}
//else: not selected
}
// sanity check: a single selection listbox can't have more than one item
// selected
wxASSERT_MSG( HasMultipleSelection() || (m_selections.GetCount() < 2),
_T("multiple selected items in single selection lbox?") );
if ( select )
{
// the newly selected item becomes the current one
SetCurrentItem(n);
}
}
int wxListBox::GetSelection() const
{
wxCHECK_MSG( !HasMultipleSelection(), -1,
_T("use wxListBox::GetSelections for ths listbox") );
return m_selections.IsEmpty() ? -1 : m_selections[0];
}
int wxCMPFUNC_CONV wxCompareInts(int *n, int *m)
{
return *n - *m;
}
int wxListBox::GetSelections(wxArrayInt& selections) const
{
// always return sorted array to the user
selections = m_selections;
size_t count = m_selections.GetCount();
// don't call sort on an empty array
if ( count )
{
selections.Sort(wxCompareInts);
}
return count;
}
// ----------------------------------------------------------------------------
// refresh logic: we use delayed refreshing which allows to avoid multiple
// refreshes (and hence flicker) in case when several listbox items are
// added/deleted/changed subsequently
// ----------------------------------------------------------------------------
void wxListBox::RefreshFromItemToEnd(int from)
{
RefreshItems(from, GetCount() - from);
}
void wxListBox::RefreshItems(int from, int count)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?