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 // ============================================================================
24 #pragma implementation "lboxtest.cpp"
25 #pragma interface "lboxtest.cpp"
28 // ----------------------------------------------------------------------------
30 // ----------------------------------------------------------------------------
32 // for compilers that support precompilation, includes "wx/wx.h".
33 #include "wx/wxprec.h"
39 // for all others, include the necessary headers
44 #include "wx/dcclient.h"
46 #include "wx/button.h"
47 #include "wx/checkbox.h"
48 #include "wx/checklst.h"
49 #include "wx/listbox.h"
50 #include "wx/radiobox.h"
51 #include "wx/radiobut.h"
52 #include "wx/statbox.h"
53 #include "wx/stattext.h"
54 #include "wx/textctrl.h"
59 #ifdef __WXUNIVERSAL__
60 #include "wx/univ/theme.h"
61 #endif // __WXUNIVERSAL__
63 // ----------------------------------------------------------------------------
65 // ----------------------------------------------------------------------------
87 // ----------------------------------------------------------------------------
89 // ----------------------------------------------------------------------------
91 // Define a new application type, each program should derive a class from wxApp
92 class LboxTestApp
: public wxApp
95 // override base class virtuals
96 // ----------------------------
98 // this one is called on application startup and is a good place for the app
99 // initialization (doing it here and not in the ctor allows to have an error
100 // return: if OnInit() returns false, the application terminates)
101 virtual bool OnInit();
104 // Define a new frame type: this is going to be our main frame
105 class LboxTestFrame
: public wxFrame
109 LboxTestFrame(const wxString
& title
);
110 virtual ~LboxTestFrame();
114 void OnButtonReset(wxCommandEvent
& event
);
115 void OnButtonCreate(wxCommandEvent
& event
);
116 void OnButtonChange(wxCommandEvent
& event
);
117 void OnButtonDelete(wxCommandEvent
& event
);
118 void OnButtonDeleteSel(wxCommandEvent
& event
);
119 void OnButtonClear(wxCommandEvent
& event
);
120 void OnButtonClearLog(wxCommandEvent
& event
);
121 void OnButtonAdd(wxCommandEvent
& event
);
122 void OnButtonAddSeveral(wxCommandEvent
& event
);
123 void OnButtonAddMany(wxCommandEvent
& event
);
124 void OnButtonQuit(wxCommandEvent
& event
);
126 void OnListbox(wxCommandEvent
& event
);
127 void OnListboxDClick(wxCommandEvent
& 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 // the listbox for logging messages
180 wxListBox
*m_lboxLog
;
182 // the text entries for "Add/change string" and "Delete" buttons
183 wxTextCtrl
*m_textAdd
,
188 // the log target we use to redirect messages to the listbox
191 // any class wishing to process wxWindows events must use this macro
192 DECLARE_EVENT_TABLE()
195 // A log target which just redirects the messages to a listbox
196 class LboxLogger
: public wxLog
199 LboxLogger(wxListBox
*lbox
, wxLog
*logOld
)
202 //m_lbox->Disable(); -- looks ugly under MSW
206 virtual ~LboxLogger()
208 wxLog::SetActiveTarget(m_logOld
);
212 // implement sink functions
213 virtual void DoLog(wxLogLevel level
, const wxChar
*szString
, time_t t
)
215 // don't put trace messages into listbox or we can get into infinite
217 if ( level
== wxLOG_Trace
)
221 // cast is needed to call protected method
222 ((LboxLogger
*)m_logOld
)->DoLog(level
, szString
, t
);
227 wxLog::DoLog(level
, szString
, t
);
231 virtual void DoLogString(const wxChar
*szString
, time_t WXUNUSED(t
))
236 #ifdef __WXUNIVERSAL__
237 m_lbox
->AppendAndEnsureVisible(msg
);
238 #else // other ports don't have this method yet
241 // SetFirstItem() isn't implemented in wxGTK
243 m_lbox
->SetFirstItem(m_lbox
->GetCount() - 1);
248 // the control we use
251 // the old log target
255 // ----------------------------------------------------------------------------
257 // ----------------------------------------------------------------------------
259 IMPLEMENT_APP(LboxTestApp
)
261 // ----------------------------------------------------------------------------
263 // ----------------------------------------------------------------------------
265 BEGIN_EVENT_TABLE(LboxTestFrame
, wxFrame
)
266 EVT_BUTTON(LboxTest_Reset
, LboxTestFrame::OnButtonReset
)
267 EVT_BUTTON(LboxTest_Create
, LboxTestFrame::OnButtonCreate
)
268 EVT_BUTTON(LboxTest_Change
, LboxTestFrame::OnButtonChange
)
269 EVT_BUTTON(LboxTest_Delete
, LboxTestFrame::OnButtonDelete
)
270 EVT_BUTTON(LboxTest_DeleteSel
, LboxTestFrame::OnButtonDeleteSel
)
271 EVT_BUTTON(LboxTest_Clear
, LboxTestFrame::OnButtonClear
)
272 EVT_BUTTON(LboxTest_ClearLog
, LboxTestFrame::OnButtonClearLog
)
273 EVT_BUTTON(LboxTest_Add
, LboxTestFrame::OnButtonAdd
)
274 EVT_BUTTON(LboxTest_AddSeveral
, LboxTestFrame::OnButtonAddSeveral
)
275 EVT_BUTTON(LboxTest_AddMany
, LboxTestFrame::OnButtonAddMany
)
276 EVT_BUTTON(LboxTest_Quit
, LboxTestFrame::OnButtonQuit
)
278 EVT_TEXT_ENTER(LboxTest_AddText
, LboxTestFrame::OnButtonAdd
)
279 EVT_TEXT_ENTER(LboxTest_DeleteText
, LboxTestFrame::OnButtonDelete
)
281 EVT_UPDATE_UI_RANGE(LboxTest_Reset
, LboxTest_Create
,
282 LboxTestFrame::OnUpdateUICreateButton
)
284 EVT_UPDATE_UI(LboxTest_AddSeveral
, LboxTestFrame::OnUpdateUIAddSeveral
)
285 EVT_UPDATE_UI(LboxTest_Clear
, LboxTestFrame::OnUpdateUIClearButton
)
286 EVT_UPDATE_UI(LboxTest_DeleteText
, LboxTestFrame::OnUpdateUIClearButton
)
287 EVT_UPDATE_UI(LboxTest_Delete
, LboxTestFrame::OnUpdateUIDeleteButton
)
288 EVT_UPDATE_UI(LboxTest_Change
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
289 EVT_UPDATE_UI(LboxTest_ChangeText
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
290 EVT_UPDATE_UI(LboxTest_DeleteSel
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
292 EVT_LISTBOX(LboxTest_Listbox
, LboxTestFrame::OnListbox
)
293 EVT_LISTBOX_DCLICK(wxID_ANY
, LboxTestFrame::OnListboxDClick
)
294 EVT_CHECKBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
295 EVT_RADIOBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
298 // ============================================================================
300 // ============================================================================
302 // ----------------------------------------------------------------------------
304 // ----------------------------------------------------------------------------
306 bool LboxTestApp::OnInit()
308 wxFrame
*frame
= new LboxTestFrame(_T("wxListBox sample"));
311 //wxLog::AddTraceMask(_T("listbox"));
312 wxLog::AddTraceMask(_T("scrollbar"));
317 // ----------------------------------------------------------------------------
318 // top level frame class
319 // ----------------------------------------------------------------------------
321 LboxTestFrame::LboxTestFrame(const wxString
& title
)
322 : wxFrame(NULL
, wxID_ANY
, title
, wxPoint(100, 100))
326 m_radioSelMode
= (wxRadioBox
*)NULL
;
330 m_chkSort
= (wxCheckBox
*)NULL
;
333 m_lboxLog
= (wxListBox
*)NULL
;
334 m_sizerLbox
= (wxSizer
*)NULL
;
336 m_logTarget
= (wxLog
*)NULL
;
338 wxPanel
*panel
= new wxPanel(this, wxID_ANY
);
341 What we create here is a frame having 3 panes: the explanatory pane to
342 the left allowing to set the listbox styles and recreate the control,
343 the pane containing the listbox itself and the lower pane containing
344 the buttons which allow to add/change/delete strings to/from it.
346 wxSizer
*sizerTop
= new wxBoxSizer(wxVERTICAL
),
347 *sizerUp
= new wxBoxSizer(wxHORIZONTAL
),
349 *sizerRight
= new wxBoxSizer(wxVERTICAL
);
352 static const wxString modes
[] =
359 wxStaticBox
*box
= new wxStaticBox(panel
, wxID_ANY
, _T("&Set listbox parameters"));
360 m_radioSelMode
= new wxRadioBox(panel
, wxID_ANY
, _T("Selection &mode:"),
361 wxDefaultPosition
, wxDefaultSize
,
362 WXSIZEOF(modes
), modes
,
363 1, wxRA_SPECIFY_COLS
);
365 m_chkVScroll
= new wxCheckBox(panel
, wxID_ANY
, _T("Always show &vertical scrollbar"));
366 m_chkHScroll
= new wxCheckBox(panel
, wxID_ANY
, _T("Show &horizontal scrollbar"));
367 m_chkSort
= new wxCheckBox(panel
, wxID_ANY
, _T("&Sort items"));
369 sizerLeft
= new wxStaticBoxSizer(box
, wxVERTICAL
);
371 sizerLeft
->Add(m_chkVScroll
, 0, wxLEFT
| wxRIGHT
, 5);
372 sizerLeft
->Add(m_chkHScroll
, 0, wxLEFT
| wxRIGHT
, 5);
373 sizerLeft
->Add(m_chkSort
, 0, wxLEFT
| wxRIGHT
, 5);
374 sizerLeft
->Add(5, 5, 0, wxGROW
| wxALL
, 5); // spacer
375 sizerLeft
->Add(m_radioSelMode
, 0, wxGROW
| wxALL
, 5);
377 wxSizer
*sizerBtn
= new wxBoxSizer(wxHORIZONTAL
);
378 wxButton
*btn
= new wxButton(panel
, LboxTest_Reset
, _T("&Reset"));
379 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
380 btn
= new wxButton(panel
, LboxTest_Create
, _T("&Create"));
381 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
382 sizerLeft
->Add(sizerBtn
, 0, wxALIGN_CENTRE_HORIZONTAL
| wxALL
, 15);
385 wxStaticBox
*box2
= new wxStaticBox(panel
, wxID_ANY
, _T("&Change listbox contents"));
386 wxSizer
*sizerMiddle
= new wxStaticBoxSizer(box2
, wxVERTICAL
);
388 wxSizer
*sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
389 btn
= new wxButton(panel
, LboxTest_Add
, _T("&Add this string"));
390 m_textAdd
= new wxTextCtrl(panel
, LboxTest_AddText
, _T("test item 0"));
391 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
392 sizerRow
->Add(m_textAdd
, 1, wxLEFT
, 5);
393 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
395 btn
= new wxButton(panel
, LboxTest_AddSeveral
, _T("&Insert a few strings"));
396 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
398 btn
= new wxButton(panel
, LboxTest_AddMany
, _T("Add &many strings"));
399 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
401 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
402 btn
= new wxButton(panel
, LboxTest_Change
, _T("C&hange current"));
403 m_textChange
= new wxTextCtrl(panel
, LboxTest_ChangeText
, _T(""));
404 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
405 sizerRow
->Add(m_textChange
, 1, wxLEFT
, 5);
406 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
408 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
409 btn
= new wxButton(panel
, LboxTest_Delete
, _T("&Delete this item"));
410 m_textDelete
= new wxTextCtrl(panel
, LboxTest_DeleteText
, _T(""));
411 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
412 sizerRow
->Add(m_textDelete
, 1, wxLEFT
, 5);
413 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
415 btn
= new wxButton(panel
, LboxTest_DeleteSel
, _T("Delete &selection"));
416 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
418 btn
= new wxButton(panel
, LboxTest_Clear
, _T("&Clear"));
419 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
422 m_lbox
= new wxListBox(panel
, LboxTest_Listbox
,
423 wxDefaultPosition
, wxDefaultSize
,
426 sizerRight
->Add(m_lbox
, 1, wxGROW
| wxALL
, 5);
427 sizerRight
->SetMinSize(250, 0);
428 m_sizerLbox
= sizerRight
; // save it to modify it later
430 // the 3 panes panes compose the upper part of the window
431 sizerUp
->Add(sizerLeft
, 0, wxGROW
| (wxALL
& ~wxLEFT
), 10);
432 sizerUp
->Add(sizerMiddle
, 1, wxGROW
| wxALL
, 10);
433 sizerUp
->Add(sizerRight
, 1, wxGROW
| (wxALL
& ~wxRIGHT
), 10);
435 // the lower one only has the log listbox and a button to clear it
436 wxSizer
*sizerDown
= new wxStaticBoxSizer
438 new wxStaticBox(panel
, wxID_ANY
, _T("&Log window")),
441 m_lboxLog
= new wxListBox(panel
, wxID_ANY
);
442 sizerDown
->Add(m_lboxLog
, 1, wxGROW
| wxALL
, 5);
443 wxBoxSizer
*sizerBtns
= new wxBoxSizer(wxHORIZONTAL
);
444 btn
= new wxButton(panel
, LboxTest_ClearLog
, _T("Clear &log"));
446 sizerBtns
->Add(10, 0); // spacer
447 btn
= new wxButton(panel
, LboxTest_Quit
, _T("E&xit"));
449 sizerDown
->Add(sizerBtns
, 0, wxALL
| wxALIGN_RIGHT
, 5);
451 // put everything together
452 sizerTop
->Add(sizerUp
, 1, wxGROW
| (wxALL
& ~wxBOTTOM
), 10);
453 sizerTop
->Add(0, 5, 0, wxGROW
); // spacer in between
454 sizerTop
->Add(sizerDown
, 0, wxGROW
| (wxALL
& ~wxTOP
), 10);
456 // final initialization
460 panel
->SetAutoLayout(true);
461 panel
->SetSizer(sizerTop
);
464 sizerTop
->SetSizeHints(this);
466 // now that everything is created we can redirect the log messages to the
468 m_logTarget
= new LboxLogger(m_lboxLog
, wxLog::GetActiveTarget());
469 wxLog::SetActiveTarget(m_logTarget
);
472 LboxTestFrame::~LboxTestFrame()
477 // ----------------------------------------------------------------------------
479 // ----------------------------------------------------------------------------
481 void LboxTestFrame::Reset()
483 if ( m_radioSelMode
->GetSelection() == LboxSel_Single
&&
484 !m_chkSort
->GetValue() &&
485 m_chkHScroll
->GetValue() &&
486 !m_chkVScroll
->GetValue() )
492 m_radioSelMode
->SetSelection(LboxSel_Single
);
493 m_chkSort
->SetValue(false);
494 m_chkHScroll
->SetValue(true);
495 m_chkVScroll
->SetValue(false);
500 void LboxTestFrame::CreateLbox()
503 switch ( m_radioSelMode
->GetSelection() )
506 wxFAIL_MSG( _T("unexpected radio box selection") );
508 case LboxSel_Single
: flags
|= wxLB_SINGLE
; break;
509 case LboxSel_Extended
: flags
|= wxLB_EXTENDED
; break;
510 case LboxSel_Multiple
: flags
|= wxLB_MULTIPLE
; break;
513 if ( m_chkVScroll
->GetValue() )
514 flags
|= wxLB_ALWAYS_SB
;
515 if ( m_chkHScroll
->GetValue() )
516 flags
|= wxLB_HSCROLL
;
517 if ( m_chkSort
->GetValue() )
523 int count
= m_lbox
->GetCount();
524 for ( int n
= 0; n
< count
; n
++ )
526 items
.Add(m_lbox
->GetString(n
));
529 m_sizerLbox
->Detach(m_lbox
);
533 m_lbox
= new wxListBox(this, wxID_ANY
,
534 wxDefaultPosition
, wxDefaultSize
,
538 m_sizerLbox
->Add(m_lbox
, 1, wxGROW
| wxALL
, 5);
539 m_sizerLbox
->Layout();
544 // ----------------------------------------------------------------------------
546 // ----------------------------------------------------------------------------
548 void LboxTestFrame::OnButtonQuit(wxCommandEvent
& WXUNUSED(event
))
553 void LboxTestFrame::OnButtonReset(wxCommandEvent
& WXUNUSED(event
))
558 void LboxTestFrame::OnButtonCreate(wxCommandEvent
& WXUNUSED(event
))
563 void LboxTestFrame::OnButtonChange(wxCommandEvent
& WXUNUSED(event
))
565 wxArrayInt selections
;
566 int count
= m_lbox
->GetSelections(selections
);
567 wxString s
= m_textChange
->GetValue();
568 for ( int n
= 0; n
< count
; n
++ )
570 m_lbox
->SetString(selections
[n
], s
);
574 void LboxTestFrame::OnButtonDelete(wxCommandEvent
& WXUNUSED(event
))
577 if ( !m_textDelete
->GetValue().ToULong(&n
) ||
578 (n
>= (unsigned)m_lbox
->GetCount()) )
586 void LboxTestFrame::OnButtonDeleteSel(wxCommandEvent
& WXUNUSED(event
))
588 wxArrayInt selections
;
589 int n
= m_lbox
->GetSelections(selections
);
592 m_lbox
->Delete(selections
[--n
]);
596 void LboxTestFrame::OnButtonClear(wxCommandEvent
& WXUNUSED(event
))
601 void LboxTestFrame::OnButtonClearLog(wxCommandEvent
& WXUNUSED(event
))
606 void LboxTestFrame::OnButtonAdd(wxCommandEvent
& WXUNUSED(event
))
608 static size_t s_item
= 0;
610 wxString s
= m_textAdd
->GetValue();
611 if ( !m_textAdd
->IsModified() )
613 // update the default string
614 m_textAdd
->SetValue(wxString::Format(_T("test item %u"), ++s_item
));
620 void LboxTestFrame::OnButtonAddMany(wxCommandEvent
& WXUNUSED(event
))
622 // "many" means 1000 here
623 for ( size_t n
= 0; n
< 1000; n
++ )
625 m_lbox
->Append(wxString::Format(_T("item #%u"), n
));
629 void LboxTestFrame::OnButtonAddSeveral(wxCommandEvent
& WXUNUSED(event
))
632 items
.Add(_T("First"));
633 items
.Add(_T("another one"));
634 items
.Add(_T("and the last (very very very very very very very very very very long) one"));
635 m_lbox
->InsertItems(items
, 0);
638 void LboxTestFrame::OnUpdateUICreateButton(wxUpdateUIEvent
& event
)
640 event
.Enable(m_dirty
);
643 void LboxTestFrame::OnUpdateUIDeleteButton(wxUpdateUIEvent
& event
)
646 event
.Enable(m_textDelete
->GetValue().ToULong(&n
) &&
647 (n
< (unsigned)m_lbox
->GetCount()));
650 void LboxTestFrame::OnUpdateUIDeleteSelButton(wxUpdateUIEvent
& event
)
652 wxArrayInt selections
;
653 event
.Enable(m_lbox
->GetSelections(selections
) != 0);
656 void LboxTestFrame::OnUpdateUIClearButton(wxUpdateUIEvent
& event
)
658 event
.Enable(m_lbox
->GetCount() != 0);
661 void LboxTestFrame::OnUpdateUIAddSeveral(wxUpdateUIEvent
& event
)
663 event
.Enable(!(m_lbox
->GetWindowStyle() & wxLB_SORT
));
666 void LboxTestFrame::OnListbox(wxCommandEvent
& event
)
668 int sel
= event
.GetInt();
669 m_textDelete
->SetValue(wxString::Format(_T("%d"), sel
));
671 wxLogMessage(_T("Listbox item %d selected"), sel
);
674 void LboxTestFrame::OnListboxDClick(wxCommandEvent
& event
)
676 int sel
= event
.GetInt();
677 wxLogMessage(_T("Listbox item %d double clicked"), sel
);
680 void LboxTestFrame::OnCheckOrRadioBox(wxCommandEvent
& WXUNUSED(event
))