1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxListBox sample
4 // Author: Vadim Zeitlin
6 // Copyright: (c) 2000 Vadim Zeitlin
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
13 +1. horz scrollbar doesn't appear in listbox
14 +2. truncating text ctrl doesn't update display
15 +3. deleting last listbox item doesn't update display
16 4. text ctrl background corrupted after resize
19 // ============================================================================
21 // ============================================================================
23 // ----------------------------------------------------------------------------
25 // ----------------------------------------------------------------------------
27 // for compilers that support precompilation, includes "wx/wx.h".
28 #include "wx/wxprec.h"
34 // for all others, include the necessary headers
39 #include "wx/dcclient.h"
41 #include "wx/button.h"
42 #include "wx/checkbox.h"
43 #include "wx/checklst.h"
44 #include "wx/listbox.h"
45 #include "wx/radiobox.h"
46 #include "wx/radiobut.h"
47 #include "wx/statbox.h"
48 #include "wx/stattext.h"
49 #include "wx/textctrl.h"
54 #ifdef __WXUNIVERSAL__
55 #include "wx/univ/theme.h"
56 #endif // __WXUNIVERSAL__
58 // ----------------------------------------------------------------------------
60 // ----------------------------------------------------------------------------
85 // ----------------------------------------------------------------------------
87 // ----------------------------------------------------------------------------
89 // Define a new application type, each program should derive a class from wxApp
90 class LboxTestApp
: public wxApp
93 // override base class virtuals
94 // ----------------------------
96 // this one is called on application startup and is a good place for the app
97 // initialization (doing it here and not in the ctor allows to have an error
98 // return: if OnInit() returns false, the application terminates)
99 virtual bool OnInit();
102 // Define a new frame type: this is going to be our main frame
103 class LboxTestFrame
: public wxFrame
107 LboxTestFrame(const wxString
& title
);
108 virtual ~LboxTestFrame();
112 void OnButtonReset(wxCommandEvent
& event
);
113 void OnButtonCreate(wxCommandEvent
& event
);
114 void OnButtonChange(wxCommandEvent
& event
);
115 void OnButtonDelete(wxCommandEvent
& event
);
116 void OnButtonDeleteSel(wxCommandEvent
& event
);
117 void OnButtonDeselectAll(wxCommandEvent
& event
);
118 void OnButtonClear(wxCommandEvent
& event
);
121 void OnButtonClearLog(wxCommandEvent
& event
);
123 void OnButtonAdd(wxCommandEvent
& event
);
124 void OnButtonAddSeveral(wxCommandEvent
& event
);
125 void OnButtonAddMany(wxCommandEvent
& event
);
126 void OnButtonQuit(wxCommandEvent
& event
);
128 void OnListbox(wxCommandEvent
& event
);
129 void OnListboxDClick(wxCommandEvent
& event
);
130 void OnListboxRDown(wxMouseEvent
& event
);
132 void OnCheckOrRadioBox(wxCommandEvent
& event
);
134 void OnUpdateUIAddSeveral(wxUpdateUIEvent
& event
);
135 void OnUpdateUICreateButton(wxUpdateUIEvent
& event
);
136 void OnUpdateUIClearButton(wxUpdateUIEvent
& event
);
137 void OnUpdateUIDeleteButton(wxUpdateUIEvent
& event
);
138 void OnUpdateUIDeleteSelButton(wxUpdateUIEvent
& event
);
139 void OnUpdateUIDeselectAllButton(wxUpdateUIEvent
& event
);
141 // reset the listbox parameters
144 // (re)create the listbox
147 // listbox parameters
148 // ------------------
150 // the selection mode
158 // should it be sorted?
161 // should it have horz scroll/vert scrollbar permanently shown?
165 // should the recreate button be enabled?
171 // the sel mode radiobox
172 wxRadioBox
*m_radioSelMode
;
175 wxCheckBox
*m_chkSort
,
179 // the listbox itself and the sizer it is in
181 wxSizer
*m_sizerLbox
;
183 // panel the controls such as the listbox are in
187 // the listbox for logging messages
188 wxListBox
*m_lboxLog
;
191 // the text entries for "Add/change string" and "Delete" buttons
192 wxTextCtrl
*m_textAdd
,
198 // the log target we use to redirect messages to the listbox
202 // any class wishing to process wxWidgets events must use this macro
203 DECLARE_EVENT_TABLE()
207 // A log target which just redirects the messages to a listbox
208 class LboxLogger
: public wxLog
211 LboxLogger(wxListBox
*lbox
, wxLog
*logOld
)
214 //m_lbox->Disable(); -- looks ugly under MSW
218 virtual ~LboxLogger()
220 wxLog::SetActiveTarget(m_logOld
);
224 // implement sink functions
225 virtual void DoLog(wxLogLevel level
, const wxChar
*szString
, time_t t
)
227 // don't put trace messages into listbox or we can get into infinite
229 if ( level
== wxLOG_Trace
)
233 // cast is needed to call protected method
234 ((LboxLogger
*)m_logOld
)->DoLog(level
, szString
, t
);
239 wxLog::DoLog(level
, szString
, t
);
243 virtual void DoLogString(const wxChar
*szString
, time_t WXUNUSED(t
))
248 #ifdef __WXUNIVERSAL__
249 m_lbox
->AppendAndEnsureVisible(msg
);
250 #else // other ports don't have this method yet
253 // SetFirstItem() isn't implemented in wxGTK
255 m_lbox
->SetFirstItem(m_lbox
->GetCount() - 1);
260 // the control we use
263 // the old log target
268 // ----------------------------------------------------------------------------
270 // ----------------------------------------------------------------------------
272 IMPLEMENT_APP(LboxTestApp
)
274 // ----------------------------------------------------------------------------
276 // ----------------------------------------------------------------------------
278 BEGIN_EVENT_TABLE(LboxTestFrame
, wxFrame
)
279 EVT_BUTTON(LboxTest_Reset
, LboxTestFrame::OnButtonReset
)
280 EVT_BUTTON(LboxTest_Create
, LboxTestFrame::OnButtonCreate
)
281 EVT_BUTTON(LboxTest_Change
, LboxTestFrame::OnButtonChange
)
282 EVT_BUTTON(LboxTest_Delete
, LboxTestFrame::OnButtonDelete
)
283 EVT_BUTTON(LboxTest_DeleteSel
, LboxTestFrame::OnButtonDeleteSel
)
284 EVT_BUTTON(LboxTest_DeselectAll
, LboxTestFrame::OnButtonDeselectAll
)
285 EVT_BUTTON(LboxTest_Clear
, LboxTestFrame::OnButtonClear
)
287 EVT_BUTTON(LboxTest_ClearLog
, LboxTestFrame::OnButtonClearLog
)
289 EVT_BUTTON(LboxTest_Add
, LboxTestFrame::OnButtonAdd
)
290 EVT_BUTTON(LboxTest_AddSeveral
, LboxTestFrame::OnButtonAddSeveral
)
291 EVT_BUTTON(LboxTest_AddMany
, LboxTestFrame::OnButtonAddMany
)
292 EVT_BUTTON(LboxTest_Quit
, LboxTestFrame::OnButtonQuit
)
294 EVT_TEXT_ENTER(LboxTest_AddText
, LboxTestFrame::OnButtonAdd
)
295 EVT_TEXT_ENTER(LboxTest_DeleteText
, LboxTestFrame::OnButtonDelete
)
297 EVT_UPDATE_UI_RANGE(LboxTest_Reset
, LboxTest_Create
,
298 LboxTestFrame::OnUpdateUICreateButton
)
300 EVT_UPDATE_UI(LboxTest_AddSeveral
, LboxTestFrame::OnUpdateUIAddSeveral
)
301 EVT_UPDATE_UI(LboxTest_Clear
, LboxTestFrame::OnUpdateUIClearButton
)
302 EVT_UPDATE_UI(LboxTest_DeleteText
, LboxTestFrame::OnUpdateUIClearButton
)
303 EVT_UPDATE_UI(LboxTest_Delete
, LboxTestFrame::OnUpdateUIDeleteButton
)
304 EVT_UPDATE_UI(LboxTest_Change
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
305 EVT_UPDATE_UI(LboxTest_ChangeText
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
306 EVT_UPDATE_UI(LboxTest_DeleteSel
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
307 EVT_UPDATE_UI(LboxTest_DeselectAll
, LboxTestFrame::OnUpdateUIDeselectAllButton
)
309 EVT_LISTBOX(LboxTest_Listbox
, LboxTestFrame::OnListbox
)
310 EVT_LISTBOX_DCLICK(wxID_ANY
, LboxTestFrame::OnListboxDClick
)
311 EVT_CHECKBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
312 EVT_RADIOBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
315 // ============================================================================
317 // ============================================================================
319 // ----------------------------------------------------------------------------
321 // ----------------------------------------------------------------------------
323 bool LboxTestApp::OnInit()
325 if ( !wxApp::OnInit() )
328 wxFrame
*frame
= new LboxTestFrame(_T("wxListBox sample"));
332 //wxLog::AddTraceMask(_T("listbox"));
333 wxLog::AddTraceMask(_T("scrollbar"));
339 // ----------------------------------------------------------------------------
340 // top level frame class
341 // ----------------------------------------------------------------------------
343 LboxTestFrame::LboxTestFrame(const wxString
& title
)
344 : wxFrame(NULL
, wxID_ANY
, title
, wxPoint(100, 100))
348 m_radioSelMode
= (wxRadioBox
*)NULL
;
352 m_chkSort
= (wxCheckBox
*)NULL
;
354 m_lbox
= (wxListBox
*)NULL
;
356 m_lboxLog
= (wxListBox
*)NULL
;
358 m_sizerLbox
= (wxSizer
*)NULL
;
361 m_logTarget
= (wxLog
*)NULL
;
364 m_panel
= new wxPanel(this, wxID_ANY
);
367 What we create here is a frame having 3 panes: the explanatory pane to
368 the left allowing to set the listbox styles and recreate the control,
369 the pane containing the listbox itself and the lower pane containing
370 the buttons which allow to add/change/delete strings to/from it.
372 wxSizer
*sizerTop
= new wxBoxSizer(wxVERTICAL
),
373 *sizerUp
= new wxBoxSizer(wxHORIZONTAL
),
375 *sizerRight
= new wxBoxSizer(wxVERTICAL
);
378 static const wxString modes
[] =
385 wxStaticBox
*box
= new wxStaticBox(m_panel
, wxID_ANY
, _T("&Set listbox parameters"));
386 m_radioSelMode
= new wxRadioBox(m_panel
, wxID_ANY
, _T("Selection &mode:"),
387 wxDefaultPosition
, wxDefaultSize
,
388 WXSIZEOF(modes
), modes
,
389 1, wxRA_SPECIFY_COLS
);
391 m_chkVScroll
= new wxCheckBox(m_panel
, wxID_ANY
, _T("Always show &vertical scrollbar"));
392 m_chkHScroll
= new wxCheckBox(m_panel
, wxID_ANY
, _T("Show &horizontal scrollbar"));
393 m_chkSort
= new wxCheckBox(m_panel
, wxID_ANY
, _T("&Sort items"));
395 sizerLeft
= new wxStaticBoxSizer(box
, wxVERTICAL
);
397 sizerLeft
->Add(m_chkVScroll
, 0, wxLEFT
| wxRIGHT
, 5);
398 sizerLeft
->Add(m_chkHScroll
, 0, wxLEFT
| wxRIGHT
, 5);
399 sizerLeft
->Add(m_chkSort
, 0, wxLEFT
| wxRIGHT
, 5);
400 sizerLeft
->Add(5, 5, 0, wxGROW
| wxALL
, 5); // spacer
401 sizerLeft
->Add(m_radioSelMode
, 0, wxGROW
| wxALL
, 5);
403 wxSizer
*sizerBtn
= new wxBoxSizer(wxHORIZONTAL
);
404 wxButton
*btn
= new wxButton(m_panel
, LboxTest_Reset
, _T("&Reset"));
405 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
406 btn
= new wxButton(m_panel
, LboxTest_Create
, _T("&Create"));
407 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
408 sizerLeft
->Add(sizerBtn
, 0, wxALIGN_CENTRE_HORIZONTAL
| wxALL
, 15);
411 wxStaticBox
*box2
= new wxStaticBox(m_panel
, wxID_ANY
, _T("&Change listbox contents"));
412 wxSizer
*sizerMiddle
= new wxStaticBoxSizer(box2
, wxVERTICAL
);
414 wxSizer
*sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
415 btn
= new wxButton(m_panel
, LboxTest_Add
, _T("&Add this string"));
416 m_textAdd
= new wxTextCtrl(m_panel
, LboxTest_AddText
, _T("test item 0"));
417 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
418 sizerRow
->Add(m_textAdd
, 1, wxLEFT
, 5);
419 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
421 btn
= new wxButton(m_panel
, LboxTest_AddSeveral
, _T("&Insert a few strings"));
422 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
424 btn
= new wxButton(m_panel
, LboxTest_AddMany
, _T("Add &many strings"));
425 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
427 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
428 btn
= new wxButton(m_panel
, LboxTest_Change
, _T("C&hange current"));
429 m_textChange
= new wxTextCtrl(m_panel
, LboxTest_ChangeText
, wxEmptyString
);
430 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
431 sizerRow
->Add(m_textChange
, 1, wxLEFT
, 5);
432 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
434 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
435 btn
= new wxButton(m_panel
, LboxTest_Delete
, _T("&Delete this item"));
436 m_textDelete
= new wxTextCtrl(m_panel
, LboxTest_DeleteText
, wxEmptyString
);
437 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
438 sizerRow
->Add(m_textDelete
, 1, wxLEFT
, 5);
439 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
441 btn
= new wxButton(m_panel
, LboxTest_DeleteSel
, _T("Delete &selection"));
442 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
444 btn
= new wxButton(m_panel
, LboxTest_DeselectAll
, _T("Deselect All"));
445 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
447 btn
= new wxButton(m_panel
, LboxTest_Clear
, _T("&Clear"));
448 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
451 sizerRight
->SetMinSize(250, 0);
452 m_sizerLbox
= sizerRight
; // save it to modify it later
454 // the 3 panes panes compose the upper part of the window
455 sizerUp
->Add(sizerLeft
, 0, wxGROW
| (wxALL
& ~wxLEFT
), 10);
456 sizerUp
->Add(sizerMiddle
, 1, wxGROW
| wxALL
, 10);
457 sizerUp
->Add(sizerRight
, 1, wxGROW
| (wxALL
& ~wxRIGHT
), 10);
459 // the lower one only has the log listbox and a button to clear it
461 wxSizer
*sizerDown
= new wxStaticBoxSizer
463 new wxStaticBox(m_panel
, wxID_ANY
, _T("&Log window")),
466 m_lboxLog
= new wxListBox(m_panel
, wxID_ANY
);
467 sizerDown
->Add(m_lboxLog
, 1, wxGROW
| wxALL
, 5);
469 wxSizer
*sizerDown
= new wxBoxSizer(wxVERTICAL
);
471 wxBoxSizer
*sizerBtns
= new wxBoxSizer(wxHORIZONTAL
);
473 btn
= new wxButton(m_panel
, LboxTest_ClearLog
, _T("Clear &log"));
475 sizerBtns
->Add(10, 0); // spacer
477 btn
= new wxButton(m_panel
, LboxTest_Quit
, _T("E&xit"));
479 sizerDown
->Add(sizerBtns
, 0, wxALL
| wxALIGN_RIGHT
, 5);
481 // put everything together
482 sizerTop
->Add(sizerUp
, 1, wxGROW
| (wxALL
& ~wxBOTTOM
), 10);
483 sizerTop
->Add(0, 5, 0, wxGROW
); // spacer in between
484 sizerTop
->Add(sizerDown
, 0, wxGROW
| (wxALL
& ~wxTOP
), 10);
486 // final initialization and create the listbox
490 m_panel
->SetSizer(sizerTop
);
493 sizerTop
->SetSizeHints(this);
496 // now that everything is created we can redirect the log messages to the
498 m_logTarget
= new LboxLogger(m_lboxLog
, wxLog::GetActiveTarget());
499 wxLog::SetActiveTarget(m_logTarget
);
503 LboxTestFrame::~LboxTestFrame()
510 // ----------------------------------------------------------------------------
512 // ----------------------------------------------------------------------------
514 void LboxTestFrame::Reset()
516 if ( m_radioSelMode
->GetSelection() == LboxSel_Single
&&
517 !m_chkSort
->GetValue() &&
518 m_chkHScroll
->GetValue() &&
519 !m_chkVScroll
->GetValue() )
525 m_radioSelMode
->SetSelection(LboxSel_Single
);
526 m_chkSort
->SetValue(false);
527 m_chkHScroll
->SetValue(true);
528 m_chkVScroll
->SetValue(false);
533 void LboxTestFrame::CreateLbox()
536 switch ( m_radioSelMode
->GetSelection() )
539 wxFAIL_MSG( _T("unexpected radio box selection") );
541 case LboxSel_Single
: flags
|= wxLB_SINGLE
; break;
542 case LboxSel_Extended
: flags
|= wxLB_EXTENDED
; break;
543 case LboxSel_Multiple
: flags
|= wxLB_MULTIPLE
; break;
546 if ( m_chkVScroll
->GetValue() )
547 flags
|= wxLB_ALWAYS_SB
;
548 if ( m_chkHScroll
->GetValue() )
549 flags
|= wxLB_HSCROLL
;
550 if ( m_chkSort
->GetValue() )
555 if ( m_lbox
) // cache old items to restore later if listbox existed
557 int count
= m_lbox
->GetCount();
558 for ( int n
= 0; n
< count
; n
++ )
560 items
.Add(m_lbox
->GetString(n
));
563 m_sizerLbox
->Detach(m_lbox
);
567 m_lbox
= new wxListBox(m_panel
, LboxTest_Listbox
,
568 wxDefaultPosition
, wxDefaultSize
,
573 m_sizerLbox
->Add(m_lbox
, 1, wxGROW
| wxALL
, 5);
574 m_sizerLbox
->Layout();
578 m_lbox
->Connect(wxEVT_RIGHT_DOWN
,
579 wxMouseEventHandler(LboxTestFrame::OnListboxRDown
), NULL
, this);
582 // ----------------------------------------------------------------------------
584 // ----------------------------------------------------------------------------
586 void LboxTestFrame::OnButtonQuit(wxCommandEvent
& WXUNUSED(event
))
591 void LboxTestFrame::OnButtonReset(wxCommandEvent
& WXUNUSED(event
))
596 void LboxTestFrame::OnButtonCreate(wxCommandEvent
& WXUNUSED(event
))
601 void LboxTestFrame::OnButtonChange(wxCommandEvent
& WXUNUSED(event
))
603 wxArrayInt selections
;
604 int count
= m_lbox
->GetSelections(selections
);
605 wxString s
= m_textChange
->GetValue();
606 for ( int n
= 0; n
< count
; n
++ )
608 m_lbox
->SetString(selections
[n
], s
);
612 void LboxTestFrame::OnButtonDelete(wxCommandEvent
& WXUNUSED(event
))
615 if ( !m_textDelete
->GetValue().ToULong(&n
) ||
616 (n
>= (unsigned)m_lbox
->GetCount()) )
624 void LboxTestFrame::OnButtonDeleteSel(wxCommandEvent
& WXUNUSED(event
))
626 wxArrayInt selections
;
627 int n
= m_lbox
->GetSelections(selections
);
630 m_lbox
->Delete(selections
[--n
]);
634 void LboxTestFrame::OnButtonDeselectAll(wxCommandEvent
& WXUNUSED(event
))
636 m_lbox
->SetSelection(-1);
639 void LboxTestFrame::OnButtonClear(wxCommandEvent
& WXUNUSED(event
))
645 void LboxTestFrame::OnButtonClearLog(wxCommandEvent
& WXUNUSED(event
))
651 void LboxTestFrame::OnButtonAdd(wxCommandEvent
& WXUNUSED(event
))
653 static unsigned s_item
= 0;
655 wxString s
= m_textAdd
->GetValue();
656 if ( !m_textAdd
->IsModified() )
658 // update the default string
659 m_textAdd
->SetValue(wxString::Format(_T("test item %u"), ++s_item
));
665 void LboxTestFrame::OnButtonAddMany(wxCommandEvent
& WXUNUSED(event
))
667 // "many" means 1000 here
668 for ( unsigned n
= 0; n
< 1000; n
++ )
670 m_lbox
->Append(wxString::Format(_T("item #%u"), n
));
674 void LboxTestFrame::OnButtonAddSeveral(wxCommandEvent
& WXUNUSED(event
))
677 items
.Add(_T("First"));
678 items
.Add(_T("another one"));
679 items
.Add(_T("and the last (very very very very very very very very very very long) one"));
680 m_lbox
->InsertItems(items
, 0);
683 void LboxTestFrame::OnUpdateUICreateButton(wxUpdateUIEvent
& event
)
685 event
.Enable(m_dirty
);
688 void LboxTestFrame::OnUpdateUIDeleteButton(wxUpdateUIEvent
& event
)
691 event
.Enable(m_textDelete
->GetValue().ToULong(&n
) &&
692 (n
< (unsigned)m_lbox
->GetCount()));
695 void LboxTestFrame::OnUpdateUIDeleteSelButton(wxUpdateUIEvent
& event
)
697 wxArrayInt selections
;
698 event
.Enable(m_lbox
->GetSelections(selections
) != 0);
701 void LboxTestFrame::OnUpdateUIDeselectAllButton(wxUpdateUIEvent
& event
)
703 wxArrayInt selections
;
704 event
.Enable(m_lbox
->GetSelections(selections
) != 0);
707 void LboxTestFrame::OnUpdateUIClearButton(wxUpdateUIEvent
& event
)
709 event
.Enable(m_lbox
->GetCount() != 0);
712 void LboxTestFrame::OnUpdateUIAddSeveral(wxUpdateUIEvent
& event
)
714 event
.Enable(!(m_lbox
->GetWindowStyle() & wxLB_SORT
));
717 void LboxTestFrame::OnListbox(wxCommandEvent
& event
)
719 int sel
= event
.GetInt();
720 m_textDelete
->SetValue(wxString::Format(_T("%d"), sel
));
722 wxLogMessage(_T("Listbox item %d selected"), sel
);
725 void LboxTestFrame::OnListboxDClick(wxCommandEvent
& event
)
727 int sel
= event
.GetInt();
728 wxLogMessage(_T("Listbox item %d double clicked"), sel
);
731 void LboxTestFrame::OnListboxRDown(wxMouseEvent
& event
)
733 int item
= m_lbox
->HitTest(event
.GetPosition());
735 if ( item
!= wxNOT_FOUND
)
736 wxLogMessage(_T("Listbox item %d right clicked"), item
);
738 wxLogMessage(_T("Listbox right clicked but no item clicked upon"));
743 void LboxTestFrame::OnCheckOrRadioBox(wxCommandEvent
& WXUNUSED(event
))