1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/choice.cpp 
   4 // Author:      Julian Smart 
   5 // Modified by: Vadim Zeitlin to derive from wxChoiceBase 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  27 #if wxUSE_CHOICE && !(defined(__SMARTPHONE__) && defined(__WXWINCE__)) 
  29 #include "wx/choice.h" 
  35     #include "wx/settings.h" 
  38 #include "wx/msw/private.h" 
  40 #if wxUSE_EXTENDED_RTTI 
  41 WX_DEFINE_FLAGS( wxChoiceStyle 
) 
  43 wxBEGIN_FLAGS( wxChoiceStyle 
) 
  44     // new style border flags, we put them first to 
  45     // use them for streaming out 
  46     wxFLAGS_MEMBER(wxBORDER_SIMPLE
) 
  47     wxFLAGS_MEMBER(wxBORDER_SUNKEN
) 
  48     wxFLAGS_MEMBER(wxBORDER_DOUBLE
) 
  49     wxFLAGS_MEMBER(wxBORDER_RAISED
) 
  50     wxFLAGS_MEMBER(wxBORDER_STATIC
) 
  51     wxFLAGS_MEMBER(wxBORDER_NONE
) 
  53     // old style border flags 
  54     wxFLAGS_MEMBER(wxSIMPLE_BORDER
) 
  55     wxFLAGS_MEMBER(wxSUNKEN_BORDER
) 
  56     wxFLAGS_MEMBER(wxDOUBLE_BORDER
) 
  57     wxFLAGS_MEMBER(wxRAISED_BORDER
) 
  58     wxFLAGS_MEMBER(wxSTATIC_BORDER
) 
  59     wxFLAGS_MEMBER(wxBORDER
) 
  61     // standard window styles 
  62     wxFLAGS_MEMBER(wxTAB_TRAVERSAL
) 
  63     wxFLAGS_MEMBER(wxCLIP_CHILDREN
) 
  64     wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
) 
  65     wxFLAGS_MEMBER(wxWANTS_CHARS
) 
  66     wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
) 
  67     wxFLAGS_MEMBER(wxALWAYS_SHOW_SB 
) 
  68     wxFLAGS_MEMBER(wxVSCROLL
) 
  69     wxFLAGS_MEMBER(wxHSCROLL
) 
  71 wxEND_FLAGS( wxChoiceStyle 
) 
  73 IMPLEMENT_DYNAMIC_CLASS_XTI(wxChoice
, wxControl
,"wx/choice.h") 
  75 wxBEGIN_PROPERTIES_TABLE(wxChoice
) 
  76     wxEVENT_PROPERTY( Select 
, wxEVT_COMMAND_CHOICE_SELECTED 
, wxCommandEvent 
) 
  78     wxPROPERTY( Font 
, wxFont 
, SetFont 
, GetFont  
, EMPTY_MACROVALUE 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
  79     wxPROPERTY_COLLECTION( Choices 
, wxArrayString 
, wxString 
, AppendString 
, GetStrings 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
  80     wxPROPERTY( Selection 
,int, SetSelection
, GetSelection
, EMPTY_MACROVALUE 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
  81     wxPROPERTY_FLAGS( WindowStyle 
, wxChoiceStyle 
, long , SetWindowStyleFlag 
, GetWindowStyleFlag 
, EMPTY_MACROVALUE 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style 
  82 wxEND_PROPERTIES_TABLE() 
  84 wxBEGIN_HANDLERS_TABLE(wxChoice
) 
  85 wxEND_HANDLERS_TABLE() 
  87 wxCONSTRUCTOR_4( wxChoice 
, wxWindow
* , Parent 
, wxWindowID 
, Id 
, wxPoint 
, Position 
, wxSize 
, Size 
) 
  89 IMPLEMENT_DYNAMIC_CLASS(wxChoice
, wxControl
) 
  98 // ============================================================================ 
 100 // ============================================================================ 
 102 // ---------------------------------------------------------------------------- 
 104 // ---------------------------------------------------------------------------- 
 106 bool wxChoice::Create(wxWindow 
*parent
, 
 110                       int n
, const wxString choices
[], 
 112                       const wxValidator
& validator
, 
 113                       const wxString
& name
) 
 115     // Experience shows that wxChoice vs. wxComboBox distinction confuses 
 116     // quite a few people - try to help them 
 117     wxASSERT_MSG( !(style 
& wxCB_DROPDOWN
) && 
 118                   !(style 
& wxCB_READONLY
) && 
 119                   !(style 
& wxCB_SIMPLE
), 
 120                   _T("this style flag is ignored by wxChoice, you ") 
 121                   _T("probably want to use a wxComboBox") ); 
 123     return CreateAndInit(parent
, id
, pos
, size
, n
, choices
, style
, 
 127 bool wxChoice::CreateAndInit(wxWindow 
*parent
, 
 131                              int n
, const wxString choices
[], 
 133                              const wxValidator
& validator
, 
 134                              const wxString
& name
) 
 136     // initialize wxControl 
 137     if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) ) 
 140     // now create the real HWND 
 141     if ( !MSWCreateControl(wxT("COMBOBOX"), wxEmptyString
, pos
, size
) ) 
 145     // choice/combobox normally has "white" (depends on colour scheme, of 
 146     // course) background rather than inheriting the parent's background 
 147     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
 149     // initialize the controls contents 
 150     for ( int i 
= 0; i 
< n
; i
++ ) 
 155     // and now we may finally size the control properly (if needed) 
 161 bool wxChoice::Create(wxWindow 
*parent
, 
 165                       const wxArrayString
& choices
, 
 167                       const wxValidator
& validator
, 
 168                       const wxString
& name
) 
 170     wxCArrayString 
chs(choices
); 
 171     return Create(parent
, id
, pos
, size
, chs
.GetCount(), chs
.GetStrings(), 
 172                   style
, validator
, name
); 
 175 bool wxChoice::MSWShouldPreProcessMessage(WXMSG 
*pMsg
) 
 177     MSG 
*msg 
= (MSG 
*) pMsg
; 
 179     // if the dropdown list is visible, don't preprocess certain keys 
 180     if ( msg
->message 
== WM_KEYDOWN
 
 181         && (msg
->wParam 
== VK_ESCAPE 
|| msg
->wParam 
== VK_RETURN
) ) 
 183         if (::SendMessage(GetHwndOf(this), CB_GETDROPPEDSTATE
, 0, 0)) 
 189     return wxControl::MSWShouldPreProcessMessage(pMsg
); 
 192 WXDWORD 
wxChoice::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 194     // we never have an external border 
 195     WXDWORD msStyle 
= wxControl::MSWGetStyle
 
 197                         (style 
& ~wxBORDER_MASK
) | wxBORDER_NONE
, exstyle
 
 200     // WS_CLIPSIBLINGS is useful with wxChoice and doesn't seem to result in 
 202     msStyle 
|= WS_CLIPSIBLINGS
; 
 204     // wxChoice-specific styles 
 205     msStyle 
|= CBS_DROPDOWNLIST 
| WS_HSCROLL 
| WS_VSCROLL
; 
 206     if ( style 
& wxCB_SORT 
) 
 212 wxChoice::~wxChoice() 
 217 // ---------------------------------------------------------------------------- 
 218 // adding/deleting items to/from the list 
 219 // ---------------------------------------------------------------------------- 
 221 int wxChoice::DoAppend(const wxString
& item
) 
 223     int n 
= (int)SendMessage(GetHwnd(), CB_ADDSTRING
, 0, (LPARAM
)item
.c_str()); 
 226         wxLogLastError(wxT("SendMessage(CB_ADDSTRING)")); 
 230         // we need to refresh our size in order to have enough space for the 
 233             UpdateVisibleHeight(); 
 236     InvalidateBestSize(); 
 240 int wxChoice::DoInsert(const wxString
& item
, unsigned int pos
) 
 242     wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT
), -1, wxT("can't insert into sorted list")); 
 243     wxCHECK_MSG(IsValidInsert(pos
), -1, wxT("invalid index")); 
 245     int n 
= (int)SendMessage(GetHwnd(), CB_INSERTSTRING
, pos
, (LPARAM
)item
.c_str()); 
 248         wxLogLastError(wxT("SendMessage(CB_INSERTSTRING)")); 
 253             UpdateVisibleHeight(); 
 256     InvalidateBestSize(); 
 260 void wxChoice::Delete(unsigned int n
) 
 262     wxCHECK_RET( IsValid(n
), wxT("invalid item index in wxChoice::Delete") ); 
 264     if ( HasClientObjectData() ) 
 266         delete GetClientObject(n
); 
 269     SendMessage(GetHwnd(), CB_DELETESTRING
, n
, 0); 
 272         UpdateVisibleHeight(); 
 274     InvalidateBestSize(); 
 277 void wxChoice::Clear() 
 281     SendMessage(GetHwnd(), CB_RESETCONTENT
, 0, 0); 
 284         UpdateVisibleHeight(); 
 286     InvalidateBestSize(); 
 289 void wxChoice::Free() 
 291     if ( HasClientObjectData() ) 
 293         unsigned int count 
= GetCount(); 
 294         for ( unsigned int n 
= 0; n 
< count
; n
++ ) 
 296             delete GetClientObject(n
); 
 301 // ---------------------------------------------------------------------------- 
 303 // ---------------------------------------------------------------------------- 
 305 int wxChoice::GetSelection() const 
 307     // if m_lastAcceptedSelection is set, it means that the dropdown is 
 308     // currently shown and that we want to use the last "permanent" selection 
 309     // instead of whatever is under the mouse pointer currently 
 311     // otherwise, get the selection from the control 
 312     return m_lastAcceptedSelection 
== wxID_NONE 
? GetCurrentSelection() 
 313                                                 : m_lastAcceptedSelection
; 
 316 int wxChoice::GetCurrentSelection() const 
 318     return (int)SendMessage(GetHwnd(), CB_GETCURSEL
, 0, 0); 
 321 void wxChoice::SetSelection(int n
) 
 323     SendMessage(GetHwnd(), CB_SETCURSEL
, n
, 0); 
 326 // ---------------------------------------------------------------------------- 
 327 // string list functions 
 328 // ---------------------------------------------------------------------------- 
 330 unsigned int wxChoice::GetCount() const 
 332     return (unsigned int)SendMessage(GetHwnd(), CB_GETCOUNT
, 0, 0); 
 335 int wxChoice::FindString(const wxString
& s
, bool bCase
) const 
 337 #if defined(__WATCOMC__) && defined(__WIN386__) 
 338     // For some reason, Watcom in WIN386 mode crashes in the CB_FINDSTRINGEXACT message. 
 339     // wxChoice::Do it the long way instead. 
 340     unsigned int count 
= GetCount(); 
 341     for ( unsigned int i 
= 0; i 
< count
; i
++ ) 
 343         // as CB_FINDSTRINGEXACT is case insensitive, be case insensitive too 
 344         if (GetString(i
).IsSameAs(s
, bCase
)) 
 350    //TODO:  Evidently some MSW versions (all?) don't like empty strings 
 351    //passed to SendMessage, so we have to do it ourselves in that case 
 354        unsigned int count 
= GetCount(); 
 355        for ( unsigned int i 
= 0; i 
< count
; i
++ ) 
 357          if (GetString(i
).empty()) 
 365        // back to base class search for not native search type 
 366        return wxItemContainerImmutable::FindString( s
, bCase 
); 
 370        int pos 
= (int)SendMessage(GetHwnd(), CB_FINDSTRINGEXACT
, 
 371                                   (WPARAM
)-1, (LPARAM
)s
.c_str()); 
 373        return pos 
== LB_ERR 
? wxNOT_FOUND 
: pos
; 
 375 #endif // Watcom/!Watcom 
 378 void wxChoice::SetString(unsigned int n
, const wxString
& s
) 
 380     wxCHECK_RET( IsValid(n
), wxT("invalid item index in wxChoice::SetString") ); 
 382     // we have to delete and add back the string as there is no way to change a 
 385     // we need to preserve the client data 
 387     if ( m_clientDataItemsType 
!= wxClientData_None 
) 
 389         data 
= DoGetItemClientData(n
); 
 391     else // no client data 
 396     ::SendMessage(GetHwnd(), CB_DELETESTRING
, n
, 0); 
 397     ::SendMessage(GetHwnd(), CB_INSERTSTRING
, n
, (LPARAM
)s
.c_str() ); 
 401         DoSetItemClientData(n
, data
); 
 403     //else: it's already NULL by default 
 405     InvalidateBestSize(); 
 408 wxString 
wxChoice::GetString(unsigned int n
) const 
 410     int len 
= (int)::SendMessage(GetHwnd(), CB_GETLBTEXTLEN
, n
, 0); 
 413     if ( len 
!= CB_ERR 
&& len 
> 0 ) 
 420                 (LPARAM
)(wxChar 
*)wxStringBuffer(str
, len
) 
 423             wxLogLastError(wxT("SendMessage(CB_GETLBTEXT)")); 
 430 // ---------------------------------------------------------------------------- 
 432 // ---------------------------------------------------------------------------- 
 434 void wxChoice::DoSetItemClientData(unsigned int n
, void* clientData
) 
 436     if ( ::SendMessage(GetHwnd(), CB_SETITEMDATA
, 
 437                        n
, (LPARAM
)clientData
) == CB_ERR 
) 
 439         wxLogLastError(wxT("CB_SETITEMDATA")); 
 443 void* wxChoice::DoGetItemClientData(unsigned int n
) const 
 445     LPARAM rc 
= SendMessage(GetHwnd(), CB_GETITEMDATA
, n
, 0); 
 448         wxLogLastError(wxT("CB_GETITEMDATA")); 
 450         // unfortunately, there is no way to return an error code to the user 
 457 void wxChoice::DoSetItemClientObject(unsigned int n
, wxClientData
* clientData
) 
 459     DoSetItemClientData(n
, clientData
); 
 462 wxClientData
* wxChoice::DoGetItemClientObject(unsigned int n
) const 
 464     return (wxClientData 
*)DoGetItemClientData(n
); 
 467 // ---------------------------------------------------------------------------- 
 468 // wxMSW specific helpers 
 469 // ---------------------------------------------------------------------------- 
 471 void wxChoice::UpdateVisibleHeight() 
 473     // be careful to not change the width here 
 474     DoSetSize(wxDefaultCoord
, wxDefaultCoord
, wxDefaultCoord
, GetSize().y
, wxSIZE_USE_EXISTING
); 
 477 void wxChoice::DoMoveWindow(int x
, int y
, int width
, int height
) 
 479     // here is why this is necessary: if the width is negative, the combobox 
 480     // window proc makes the window of the size width*height instead of 
 481     // interpreting height in the usual manner (meaning the height of the drop 
 482     // down list - usually the height specified in the call to MoveWindow() 
 483     // will not change the height of combo box per se) 
 485     // this behaviour is not documented anywhere, but this is just how it is 
 486     // here (NT 4.4) and, anyhow, the check shouldn't hurt - however without 
 487     // the check, constraints/sizers using combos may break the height 
 488     // constraint will have not at all the same value as expected 
 492     wxControl::DoMoveWindow(x
, y
, width
, height
); 
 495 void wxChoice::DoGetSize(int *w
, int *h
) const 
 497     // this is weird: sometimes, the height returned by Windows is clearly the 
 498     // total height of the control including the drop down list -- but only 
 499     // sometimes, and normally it isn't... I have no idea about what to do with 
 501     wxControl::DoGetSize(w
, h
); 
 504 void wxChoice::DoSetSize(int x
, int y
, 
 505                          int width
, int height
, 
 508     int heightOrig 
= height
; 
 510     // the height which we must pass to Windows should be the total height of 
 511     // the control including the drop down list while the height given to us 
 512     // is, of course, just the height of the permanently visible part of it 
 513     if ( height 
!= wxDefaultCoord 
) 
 515         // don't make the drop down list too tall, arbitrarily limit it to 40 
 516         // items max and also don't leave it empty 
 517         size_t nItems 
= GetCount(); 
 520         else if ( nItems 
> 24 ) 
 523         // add space for the drop down list 
 524         const int hItem 
= SendMessage(GetHwnd(), CB_GETITEMHEIGHT
, 0, 0); 
 525         height 
+= hItem
*(nItems 
+ 1); 
 529         // We cannot pass wxDefaultCoord as height to wxControl. wxControl uses 
 530         // wxGetWindowRect() to determine the current height of the combobox, 
 531         // and then again sets the combobox's height to that value. Unfortunately, 
 532         // wxGetWindowRect doesn't include the dropdown list's height (at least 
 533         // on Win2K), so this would result in a combobox with dropdown height of 
 534         // 1 pixel. We have to determine the default height ourselves and call 
 535         // wxControl with that value instead. 
 539         if (::SendMessage(GetHwnd(), CB_GETDROPPEDCONTROLRECT
, 0, (LPARAM
) &r
) != 0) 
 541             height 
= h 
+ r
.bottom 
- r
.top
; 
 545     wxControl::DoSetSize(x
, y
, width
, height
, sizeFlags
); 
 547     // If we're storing a pending size, make sure we store 
 548     // the original size for reporting back to the app. 
 549     if (m_pendingSize 
!= wxDefaultSize
) 
 550         m_pendingSize 
= wxSize(width
, heightOrig
); 
 552     // This solution works on XP, but causes choice/combobox lists to be 
 553     // too short on W2K and earlier. 
 555     int widthCurrent
, heightCurrent
; 
 556     DoGetSize(&widthCurrent
, &heightCurrent
); 
 558     // the height which we must pass to Windows should be the total height of 
 559     // the control including the drop down list while the height given to us 
 560     // is, of course, just the height of the permanently visible part of it 
 561     if ( height 
!= wxDefaultCoord 
&& height 
!= heightCurrent 
) 
 563         // don't make the drop down list too tall, arbitrarily limit it to 40 
 564         // items max and also don't leave it empty 
 565         unsigned int nItems 
= GetCount(); 
 568         else if ( nItems 
> 24 ) 
 571         // add space for the drop down list 
 572         const int hItem 
= SendMessage(GetHwnd(), CB_GETITEMHEIGHT
, 0, 0); 
 573         height 
+= hItem
*(nItems 
+ 1); 
 575     else // keep the same height as now 
 577         // normally wxWindow::DoSetSize() checks if we set the same size as the 
 578         // window already has and does nothing in this case, but for us the 
 579         // check fails as the size we pass to it includes the dropdown while 
 580         // the size returned by our GetSize() does not, so test if the size 
 581         // didn't really change ourselves here 
 582         if ( width 
== wxDefaultCoord 
|| width 
== widthCurrent 
) 
 584             // size doesn't change, what about position? 
 585             int xCurrent
, yCurrent
; 
 586             DoGetPosition(&xCurrent
, &yCurrent
); 
 587             const bool defMeansUnchanged 
= !(sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
); 
 588             if ( ((x 
== wxDefaultCoord 
&& defMeansUnchanged
) || x 
== xCurrent
) 
 590                  ((y 
== wxDefaultCoord 
&& defMeansUnchanged
) || y 
== yCurrent
) ) 
 592                 // nothing changes, nothing to do 
 597         // We cannot pass wxDefaultCoord as height to wxControl. wxControl uses 
 598         // wxGetWindowRect() to determine the current height of the combobox, 
 599         // and then again sets the combobox's height to that value. Unfortunately, 
 600         // wxGetWindowRect doesn't include the dropdown list's height (at least 
 601         // on Win2K), so this would result in a combobox with dropdown height of 
 602         // 1 pixel. We have to determine the default height ourselves and call 
 603         // wxControl with that value instead. 
 605         // Also notice that sometimes CB_GETDROPPEDCONTROLRECT seems to return 
 606         // wildly incorrect values (~32000) which looks like a bug in it, just 
 607         // ignore them in this case 
 609         if ( ::SendMessage(GetHwnd(), CB_GETDROPPEDCONTROLRECT
, 0, (LPARAM
) &r
) 
 610                     && r
.bottom 
< 30000 ) 
 612             height 
= heightCurrent 
+ r
.bottom 
- r
.top
; 
 616     wxControl::DoSetSize(x
, y
, width
, height
, sizeFlags
); 
 620 wxSize 
wxChoice::DoGetBestSize() const 
 622     // find the widest string 
 624     const unsigned int nItems 
= GetCount(); 
 625     for ( unsigned int i 
= 0; i 
< nItems
; i
++ ) 
 628         GetTextExtent(GetString(i
), &wLine
, NULL
); 
 629         if ( wLine 
> wChoice 
) 
 633     // give it some reasonable default value if there are no strings in the 
 638     // the combobox should be slightly larger than the widest string 
 639     wChoice 
+= 5*GetCharWidth(); 
 641     wxSize 
best(wChoice
, EDIT_HEIGHT_FROM_CHAR_HEIGHT(GetCharHeight())); 
 646 WXLRESULT 
wxChoice::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
 652                 int x 
= (int)LOWORD(lParam
); 
 653                 int y 
= (int)HIWORD(lParam
); 
 655                 // Ok, this is truly weird, but if a panel with a wxChoice 
 656                 // loses the focus, then you get a *fake* WM_LBUTTONUP message 
 657                 // with x = 65535 and y = 65535. Filter out this nonsense. 
 659                 // VZ: I'd like to know how to reproduce this please... 
 660                 if ( x 
== 65535 && y 
== 65535 ) 
 665             // we have to handle both: one for the normal case and the other 
 667         case WM_CTLCOLOREDIT
: 
 668         case WM_CTLCOLORLISTBOX
: 
 669         case WM_CTLCOLORSTATIC
: 
 673                 UnpackCtlColor(wParam
, lParam
, &hdc
, &hwnd
); 
 675                 WXHBRUSH hbr 
= MSWControlColor((WXHDC
)hdc
, hwnd
); 
 677                     return (WXLRESULT
)hbr
; 
 678                 //else: fall through to default window proc 
 682     return wxWindow::MSWWindowProc(nMsg
, wParam
, lParam
); 
 685 bool wxChoice::MSWCommand(WXUINT param
, WXWORD 
WXUNUSED(id
)) 
 688         The native control provides a great variety in the events it sends in 
 689         the different selection scenarios (undoubtedly for greater amusement of 
 690         the programmers using it). For the reference, here are the cases when 
 691         the final selection is accepted (things are quite interesting when it 
 694         A. Selecting with just the arrows without opening the dropdown: 
 698         B. Opening dropdown with F4 and selecting with arrows: 
 700             2. many CBN_SELCHANGE while changing selection in the list 
 704         C. Selecting with the mouse: 
 706             -- no intermediate CBN_SELCHANGEs -- 
 711         Admire the different order of messages in all of those cases, it must 
 712         surely have taken a lot of effort to Microsoft developers to achieve 
 718             // we use this value both because we don't want to track selection 
 719             // using CB_GETCURSEL while the dropdown is opened and because we 
 720             // need to reset the selection back to it if it's eventually 
 722             m_lastAcceptedSelection 
= GetCurrentSelection(); 
 726             // if the selection was accepted by the user, it should have been 
 727             // reset to wxID_NONE by CBN_SELENDOK, otherwise the selection was 
 728             // cancelled and we must restore the old one 
 729             if ( m_lastAcceptedSelection 
!= wxID_NONE 
) 
 731                 SetSelection(m_lastAcceptedSelection
); 
 732                 m_lastAcceptedSelection 
= wxID_NONE
; 
 737             // reset it to prevent CBN_CLOSEUP from undoing the selection (it's 
 738             // ok to reset it now as GetCurrentSelection() will now return the 
 739             // same thing anyhow) 
 740             m_lastAcceptedSelection 
= wxID_NONE
; 
 743                 const int n 
= GetSelection(); 
 745                 wxCommandEvent 
event(wxEVT_COMMAND_CHOICE_SELECTED
, m_windowId
); 
 747                 event
.SetEventObject(this); 
 751                     event
.SetString(GetStringSelection()); 
 752                     InitCommandEventWithItems(event
, n
); 
 755                 ProcessCommand(event
); 
 759         // don't handle CBN_SELENDCANCEL: just leave m_lastAcceptedSelection 
 760         // valid and the selection will be undone in CBN_CLOSEUP above 
 762         // don't handle CBN_SELCHANGE neither, we don't want to generate events 
 763         // while the dropdown is opened -- but do add it if we ever need this 
 772 WXHBRUSH 
wxChoice::MSWControlColor(WXHDC hDC
, WXHWND hWnd
) 
 775         return MSWControlColorDisabled(hDC
); 
 777     return wxChoiceBase::MSWControlColor(hDC
, hWnd
); 
 780 #endif // wxUSE_CHOICE && !(__SMARTPHONE__ && __WXWINCE__)