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 // ----------------------------------------------------------------------------
84 // ----------------------------------------------------------------------------
86 // ----------------------------------------------------------------------------
88 // Define a new application type, each program should derive a class from wxApp
89 class LboxTestApp
: public wxApp
92 // override base class virtuals
93 // ----------------------------
95 // this one is called on application startup and is a good place for the app
96 // initialization (doing it here and not in the ctor allows to have an error
97 // return: if OnInit() returns false, the application terminates)
98 virtual bool OnInit();
101 // Define a new frame type: this is going to be our main frame
102 class LboxTestFrame
: public wxFrame
106 LboxTestFrame(const wxString
& title
);
107 virtual ~LboxTestFrame();
111 void OnButtonReset(wxCommandEvent
& event
);
112 void OnButtonCreate(wxCommandEvent
& event
);
113 void OnButtonChange(wxCommandEvent
& event
);
114 void OnButtonDelete(wxCommandEvent
& event
);
115 void OnButtonDeleteSel(wxCommandEvent
& event
);
116 void OnButtonClear(wxCommandEvent
& event
);
118 void OnButtonClearLog(wxCommandEvent
& event
);
120 void OnButtonAdd(wxCommandEvent
& event
);
121 void OnButtonAddSeveral(wxCommandEvent
& event
);
122 void OnButtonAddMany(wxCommandEvent
& event
);
123 void OnButtonQuit(wxCommandEvent
& event
);
125 void OnListbox(wxCommandEvent
& event
);
126 void OnListboxDClick(wxCommandEvent
& event
);
127 void OnListboxRDown(wxMouseEvent
& event
);
129 void OnCheckOrRadioBox(wxCommandEvent
& event
);
131 void OnUpdateUIAddSeveral(wxUpdateUIEvent
& event
);
132 void OnUpdateUICreateButton(wxUpdateUIEvent
& event
);
133 void OnUpdateUIClearButton(wxUpdateUIEvent
& event
);
134 void OnUpdateUIDeleteButton(wxUpdateUIEvent
& event
);
135 void OnUpdateUIDeleteSelButton(wxUpdateUIEvent
& event
);
137 // reset the listbox parameters
140 // (re)create the listbox
143 // listbox parameters
144 // ------------------
146 // the selection mode
154 // should it be sorted?
157 // should it have horz scroll/vert scrollbar permanently shown?
161 // should the recreate button be enabled?
167 // the sel mode radiobox
168 wxRadioBox
*m_radioSelMode
;
171 wxCheckBox
*m_chkSort
,
175 // the listbox itself and the sizer it is in
177 wxSizer
*m_sizerLbox
;
179 // panel the controls such as the listbox are in
183 // the listbox for logging messages
184 wxListBox
*m_lboxLog
;
187 // the text entries for "Add/change string" and "Delete" buttons
188 wxTextCtrl
*m_textAdd
,
194 // the log target we use to redirect messages to the listbox
198 // any class wishing to process wxWidgets events must use this macro
199 DECLARE_EVENT_TABLE()
203 // A log target which just redirects the messages to a listbox
204 class LboxLogger
: public wxLog
207 LboxLogger(wxListBox
*lbox
, wxLog
*logOld
)
210 //m_lbox->Disable(); -- looks ugly under MSW
214 virtual ~LboxLogger()
216 wxLog::SetActiveTarget(m_logOld
);
220 // implement sink functions
221 virtual void DoLog(wxLogLevel level
, const wxChar
*szString
, time_t t
)
223 // don't put trace messages into listbox or we can get into infinite
225 if ( level
== wxLOG_Trace
)
229 // cast is needed to call protected method
230 ((LboxLogger
*)m_logOld
)->DoLog(level
, szString
, t
);
235 wxLog::DoLog(level
, szString
, t
);
239 virtual void DoLogString(const wxChar
*szString
, time_t WXUNUSED(t
))
244 #ifdef __WXUNIVERSAL__
245 m_lbox
->AppendAndEnsureVisible(msg
);
246 #else // other ports don't have this method yet
249 // SetFirstItem() isn't implemented in wxGTK
251 m_lbox
->SetFirstItem(m_lbox
->GetCount() - 1);
256 // the control we use
259 // the old log target
264 // ----------------------------------------------------------------------------
266 // ----------------------------------------------------------------------------
268 IMPLEMENT_APP(LboxTestApp
)
270 // ----------------------------------------------------------------------------
272 // ----------------------------------------------------------------------------
274 BEGIN_EVENT_TABLE(LboxTestFrame
, wxFrame
)
275 EVT_BUTTON(LboxTest_Reset
, LboxTestFrame::OnButtonReset
)
276 EVT_BUTTON(LboxTest_Create
, LboxTestFrame::OnButtonCreate
)
277 EVT_BUTTON(LboxTest_Change
, LboxTestFrame::OnButtonChange
)
278 EVT_BUTTON(LboxTest_Delete
, LboxTestFrame::OnButtonDelete
)
279 EVT_BUTTON(LboxTest_DeleteSel
, LboxTestFrame::OnButtonDeleteSel
)
280 EVT_BUTTON(LboxTest_Clear
, LboxTestFrame::OnButtonClear
)
282 EVT_BUTTON(LboxTest_ClearLog
, LboxTestFrame::OnButtonClearLog
)
284 EVT_BUTTON(LboxTest_Add
, LboxTestFrame::OnButtonAdd
)
285 EVT_BUTTON(LboxTest_AddSeveral
, LboxTestFrame::OnButtonAddSeveral
)
286 EVT_BUTTON(LboxTest_AddMany
, LboxTestFrame::OnButtonAddMany
)
287 EVT_BUTTON(LboxTest_Quit
, LboxTestFrame::OnButtonQuit
)
289 EVT_TEXT_ENTER(LboxTest_AddText
, LboxTestFrame::OnButtonAdd
)
290 EVT_TEXT_ENTER(LboxTest_DeleteText
, LboxTestFrame::OnButtonDelete
)
292 EVT_UPDATE_UI_RANGE(LboxTest_Reset
, LboxTest_Create
,
293 LboxTestFrame::OnUpdateUICreateButton
)
295 EVT_UPDATE_UI(LboxTest_AddSeveral
, LboxTestFrame::OnUpdateUIAddSeveral
)
296 EVT_UPDATE_UI(LboxTest_Clear
, LboxTestFrame::OnUpdateUIClearButton
)
297 EVT_UPDATE_UI(LboxTest_DeleteText
, LboxTestFrame::OnUpdateUIClearButton
)
298 EVT_UPDATE_UI(LboxTest_Delete
, LboxTestFrame::OnUpdateUIDeleteButton
)
299 EVT_UPDATE_UI(LboxTest_Change
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
300 EVT_UPDATE_UI(LboxTest_ChangeText
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
301 EVT_UPDATE_UI(LboxTest_DeleteSel
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
303 EVT_LISTBOX(LboxTest_Listbox
, LboxTestFrame::OnListbox
)
304 EVT_LISTBOX_DCLICK(wxID_ANY
, LboxTestFrame::OnListboxDClick
)
305 EVT_CHECKBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
306 EVT_RADIOBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
309 // ============================================================================
311 // ============================================================================
313 // ----------------------------------------------------------------------------
315 // ----------------------------------------------------------------------------
317 bool LboxTestApp::OnInit()
319 wxFrame
*frame
= new LboxTestFrame(_T("wxListBox sample"));
323 //wxLog::AddTraceMask(_T("listbox"));
324 wxLog::AddTraceMask(_T("scrollbar"));
330 // ----------------------------------------------------------------------------
331 // top level frame class
332 // ----------------------------------------------------------------------------
334 LboxTestFrame::LboxTestFrame(const wxString
& title
)
335 : wxFrame(NULL
, wxID_ANY
, title
, wxPoint(100, 100))
339 m_radioSelMode
= (wxRadioBox
*)NULL
;
343 m_chkSort
= (wxCheckBox
*)NULL
;
345 m_lbox
= (wxListBox
*)NULL
;
347 m_lboxLog
= (wxListBox
*)NULL
;
349 m_sizerLbox
= (wxSizer
*)NULL
;
352 m_logTarget
= (wxLog
*)NULL
;
355 m_panel
= new wxPanel(this, wxID_ANY
);
358 What we create here is a frame having 3 panes: the explanatory pane to
359 the left allowing to set the listbox styles and recreate the control,
360 the pane containing the listbox itself and the lower pane containing
361 the buttons which allow to add/change/delete strings to/from it.
363 wxSizer
*sizerTop
= new wxBoxSizer(wxVERTICAL
),
364 *sizerUp
= new wxBoxSizer(wxHORIZONTAL
),
366 *sizerRight
= new wxBoxSizer(wxVERTICAL
);
369 static const wxString modes
[] =
376 wxStaticBox
*box
= new wxStaticBox(m_panel
, wxID_ANY
, _T("&Set listbox parameters"));
377 m_radioSelMode
= new wxRadioBox(m_panel
, wxID_ANY
, _T("Selection &mode:"),
378 wxDefaultPosition
, wxDefaultSize
,
379 WXSIZEOF(modes
), modes
,
380 1, wxRA_SPECIFY_COLS
);
382 m_chkVScroll
= new wxCheckBox(m_panel
, wxID_ANY
, _T("Always show &vertical scrollbar"));
383 m_chkHScroll
= new wxCheckBox(m_panel
, wxID_ANY
, _T("Show &horizontal scrollbar"));
384 m_chkSort
= new wxCheckBox(m_panel
, wxID_ANY
, _T("&Sort items"));
386 sizerLeft
= new wxStaticBoxSizer(box
, wxVERTICAL
);
388 sizerLeft
->Add(m_chkVScroll
, 0, wxLEFT
| wxRIGHT
, 5);
389 sizerLeft
->Add(m_chkHScroll
, 0, wxLEFT
| wxRIGHT
, 5);
390 sizerLeft
->Add(m_chkSort
, 0, wxLEFT
| wxRIGHT
, 5);
391 sizerLeft
->Add(5, 5, 0, wxGROW
| wxALL
, 5); // spacer
392 sizerLeft
->Add(m_radioSelMode
, 0, wxGROW
| wxALL
, 5);
394 wxSizer
*sizerBtn
= new wxBoxSizer(wxHORIZONTAL
);
395 wxButton
*btn
= new wxButton(m_panel
, LboxTest_Reset
, _T("&Reset"));
396 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
397 btn
= new wxButton(m_panel
, LboxTest_Create
, _T("&Create"));
398 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
399 sizerLeft
->Add(sizerBtn
, 0, wxALIGN_CENTRE_HORIZONTAL
| wxALL
, 15);
402 wxStaticBox
*box2
= new wxStaticBox(m_panel
, wxID_ANY
, _T("&Change listbox contents"));
403 wxSizer
*sizerMiddle
= new wxStaticBoxSizer(box2
, wxVERTICAL
);
405 wxSizer
*sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
406 btn
= new wxButton(m_panel
, LboxTest_Add
, _T("&Add this string"));
407 m_textAdd
= new wxTextCtrl(m_panel
, LboxTest_AddText
, _T("test item 0"));
408 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
409 sizerRow
->Add(m_textAdd
, 1, wxLEFT
, 5);
410 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
412 btn
= new wxButton(m_panel
, LboxTest_AddSeveral
, _T("&Insert a few strings"));
413 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
415 btn
= new wxButton(m_panel
, LboxTest_AddMany
, _T("Add &many strings"));
416 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
418 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
419 btn
= new wxButton(m_panel
, LboxTest_Change
, _T("C&hange current"));
420 m_textChange
= new wxTextCtrl(m_panel
, LboxTest_ChangeText
, wxEmptyString
);
421 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
422 sizerRow
->Add(m_textChange
, 1, wxLEFT
, 5);
423 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
425 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
426 btn
= new wxButton(m_panel
, LboxTest_Delete
, _T("&Delete this item"));
427 m_textDelete
= new wxTextCtrl(m_panel
, LboxTest_DeleteText
, wxEmptyString
);
428 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
429 sizerRow
->Add(m_textDelete
, 1, wxLEFT
, 5);
430 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
432 btn
= new wxButton(m_panel
, LboxTest_DeleteSel
, _T("Delete &selection"));
433 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
435 btn
= new wxButton(m_panel
, LboxTest_Clear
, _T("&Clear"));
436 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
439 sizerRight
->SetMinSize(250, 0);
440 m_sizerLbox
= sizerRight
; // save it to modify it later
442 // the 3 panes panes compose the upper part of the window
443 sizerUp
->Add(sizerLeft
, 0, wxGROW
| (wxALL
& ~wxLEFT
), 10);
444 sizerUp
->Add(sizerMiddle
, 1, wxGROW
| wxALL
, 10);
445 sizerUp
->Add(sizerRight
, 1, wxGROW
| (wxALL
& ~wxRIGHT
), 10);
447 // the lower one only has the log listbox and a button to clear it
449 wxSizer
*sizerDown
= new wxStaticBoxSizer
451 new wxStaticBox(m_panel
, wxID_ANY
, _T("&Log window")),
454 m_lboxLog
= new wxListBox(m_panel
, wxID_ANY
);
455 sizerDown
->Add(m_lboxLog
, 1, wxGROW
| wxALL
, 5);
457 wxSizer
*sizerDown
= new wxBoxSizer(wxVERTICAL
);
459 wxBoxSizer
*sizerBtns
= new wxBoxSizer(wxHORIZONTAL
);
461 btn
= new wxButton(m_panel
, LboxTest_ClearLog
, _T("Clear &log"));
463 sizerBtns
->Add(10, 0); // spacer
465 btn
= new wxButton(m_panel
, LboxTest_Quit
, _T("E&xit"));
467 sizerDown
->Add(sizerBtns
, 0, wxALL
| wxALIGN_RIGHT
, 5);
469 // put everything together
470 sizerTop
->Add(sizerUp
, 1, wxGROW
| (wxALL
& ~wxBOTTOM
), 10);
471 sizerTop
->Add(0, 5, 0, wxGROW
); // spacer in between
472 sizerTop
->Add(sizerDown
, 0, wxGROW
| (wxALL
& ~wxTOP
), 10);
474 // final initialization and create the listbox
478 m_panel
->SetSizer(sizerTop
);
481 sizerTop
->SetSizeHints(this);
484 // now that everything is created we can redirect the log messages to the
486 m_logTarget
= new LboxLogger(m_lboxLog
, wxLog::GetActiveTarget());
487 wxLog::SetActiveTarget(m_logTarget
);
490 m_lbox
->Connect(wxEVT_RIGHT_DOWN
,
491 wxMouseEventHandler(LboxTestFrame::OnListboxRDown
), NULL
, this);
494 LboxTestFrame::~LboxTestFrame()
501 // ----------------------------------------------------------------------------
503 // ----------------------------------------------------------------------------
505 void LboxTestFrame::Reset()
507 if ( m_radioSelMode
->GetSelection() == LboxSel_Single
&&
508 !m_chkSort
->GetValue() &&
509 m_chkHScroll
->GetValue() &&
510 !m_chkVScroll
->GetValue() )
516 m_radioSelMode
->SetSelection(LboxSel_Single
);
517 m_chkSort
->SetValue(false);
518 m_chkHScroll
->SetValue(true);
519 m_chkVScroll
->SetValue(false);
524 void LboxTestFrame::CreateLbox()
527 switch ( m_radioSelMode
->GetSelection() )
530 wxFAIL_MSG( _T("unexpected radio box selection") );
532 case LboxSel_Single
: flags
|= wxLB_SINGLE
; break;
533 case LboxSel_Extended
: flags
|= wxLB_EXTENDED
; break;
534 case LboxSel_Multiple
: flags
|= wxLB_MULTIPLE
; break;
537 if ( m_chkVScroll
->GetValue() )
538 flags
|= wxLB_ALWAYS_SB
;
539 if ( m_chkHScroll
->GetValue() )
540 flags
|= wxLB_HSCROLL
;
541 if ( m_chkSort
->GetValue() )
546 if ( m_lbox
) // cache old items to restore later if listbox existed
548 int count
= m_lbox
->GetCount();
549 for ( int n
= 0; n
< count
; n
++ )
551 items
.Add(m_lbox
->GetString(n
));
554 m_sizerLbox
->Detach(m_lbox
);
558 m_lbox
= new wxListBox(m_panel
, LboxTest_Listbox
,
559 wxDefaultPosition
, wxDefaultSize
,
564 m_sizerLbox
->Add(m_lbox
, 1, wxGROW
| wxALL
, 5);
565 m_sizerLbox
->Layout();
569 m_lbox
->Connect(wxEVT_RIGHT_DOWN
,
570 wxMouseEventHandler(LboxTestFrame::OnListboxRDown
), NULL
, this);
573 // ----------------------------------------------------------------------------
575 // ----------------------------------------------------------------------------
577 void LboxTestFrame::OnButtonQuit(wxCommandEvent
& WXUNUSED(event
))
582 void LboxTestFrame::OnButtonReset(wxCommandEvent
& WXUNUSED(event
))
587 void LboxTestFrame::OnButtonCreate(wxCommandEvent
& WXUNUSED(event
))
592 void LboxTestFrame::OnButtonChange(wxCommandEvent
& WXUNUSED(event
))
594 wxArrayInt selections
;
595 int count
= m_lbox
->GetSelections(selections
);
596 wxString s
= m_textChange
->GetValue();
597 for ( int n
= 0; n
< count
; n
++ )
599 m_lbox
->SetString(selections
[n
], s
);
603 void LboxTestFrame::OnButtonDelete(wxCommandEvent
& WXUNUSED(event
))
606 if ( !m_textDelete
->GetValue().ToULong(&n
) ||
607 (n
>= (unsigned)m_lbox
->GetCount()) )
615 void LboxTestFrame::OnButtonDeleteSel(wxCommandEvent
& WXUNUSED(event
))
617 wxArrayInt selections
;
618 int n
= m_lbox
->GetSelections(selections
);
621 m_lbox
->Delete(selections
[--n
]);
625 void LboxTestFrame::OnButtonClear(wxCommandEvent
& WXUNUSED(event
))
631 void LboxTestFrame::OnButtonClearLog(wxCommandEvent
& WXUNUSED(event
))
637 void LboxTestFrame::OnButtonAdd(wxCommandEvent
& WXUNUSED(event
))
639 static size_t s_item
= 0;
641 wxString s
= m_textAdd
->GetValue();
642 if ( !m_textAdd
->IsModified() )
644 // update the default string
645 m_textAdd
->SetValue(wxString::Format(_T("test item %u"), ++s_item
));
651 void LboxTestFrame::OnButtonAddMany(wxCommandEvent
& WXUNUSED(event
))
653 // "many" means 1000 here
654 for ( size_t n
= 0; n
< 1000; n
++ )
656 m_lbox
->Append(wxString::Format(_T("item #%u"), n
));
660 void LboxTestFrame::OnButtonAddSeveral(wxCommandEvent
& WXUNUSED(event
))
663 items
.Add(_T("First"));
664 items
.Add(_T("another one"));
665 items
.Add(_T("and the last (very very very very very very very very very very long) one"));
666 m_lbox
->InsertItems(items
, 0);
669 void LboxTestFrame::OnUpdateUICreateButton(wxUpdateUIEvent
& event
)
671 event
.Enable(m_dirty
);
674 void LboxTestFrame::OnUpdateUIDeleteButton(wxUpdateUIEvent
& event
)
677 event
.Enable(m_textDelete
->GetValue().ToULong(&n
) &&
678 (n
< (unsigned)m_lbox
->GetCount()));
681 void LboxTestFrame::OnUpdateUIDeleteSelButton(wxUpdateUIEvent
& event
)
683 wxArrayInt selections
;
684 event
.Enable(m_lbox
->GetSelections(selections
) != 0);
687 void LboxTestFrame::OnUpdateUIClearButton(wxUpdateUIEvent
& event
)
689 event
.Enable(m_lbox
->GetCount() != 0);
692 void LboxTestFrame::OnUpdateUIAddSeveral(wxUpdateUIEvent
& event
)
694 event
.Enable(!(m_lbox
->GetWindowStyle() & wxLB_SORT
));
697 void LboxTestFrame::OnListbox(wxCommandEvent
& event
)
699 int sel
= event
.GetInt();
700 m_textDelete
->SetValue(wxString::Format(_T("%d"), sel
));
702 wxLogMessage(_T("Listbox item %d selected"), sel
);
705 void LboxTestFrame::OnListboxDClick(wxCommandEvent
& event
)
707 int sel
= event
.GetInt();
708 wxLogMessage(_T("Listbox item %d double clicked"), sel
);
711 void LboxTestFrame::OnListboxRDown(wxMouseEvent
& event
)
713 int item
= m_lbox
->HitTest(event
.GetPosition());
715 if ( item
!= wxNOT_FOUND
)
716 wxLogMessage(_T("Listbox item %d right clicked"), item
);
718 wxLogMessage(_T("Listbox right clicked but no item clicked upon"));
723 void LboxTestFrame::OnCheckOrRadioBox(wxCommandEvent
& WXUNUSED(event
))