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
);
128 void OnCheckOrRadioBox(wxCommandEvent
& event
);
130 void OnUpdateUIAddSeveral(wxUpdateUIEvent
& event
);
131 void OnUpdateUICreateButton(wxUpdateUIEvent
& event
);
132 void OnUpdateUIClearButton(wxUpdateUIEvent
& event
);
133 void OnUpdateUIDeleteButton(wxUpdateUIEvent
& event
);
134 void OnUpdateUIDeleteSelButton(wxUpdateUIEvent
& event
);
136 // reset the listbox parameters
139 // (re)create the listbox
142 // listbox parameters
143 // ------------------
145 // the selection mode
153 // should it be sorted?
156 // should it have horz scroll/vert scrollbar permanently shown?
160 // should the recreate button be enabled?
166 // the sel mode radiobox
167 wxRadioBox
*m_radioSelMode
;
170 wxCheckBox
*m_chkSort
,
174 // the listbox itself and the sizer it is in
176 wxSizer
*m_sizerLbox
;
179 // the listbox for logging messages
180 wxListBox
*m_lboxLog
;
183 // the text entries for "Add/change string" and "Delete" buttons
184 wxTextCtrl
*m_textAdd
,
190 // the log target we use to redirect messages to the listbox
194 // any class wishing to process wxWidgets events must use this macro
195 DECLARE_EVENT_TABLE()
199 // A log target which just redirects the messages to a listbox
200 class LboxLogger
: public wxLog
203 LboxLogger(wxListBox
*lbox
, wxLog
*logOld
)
206 //m_lbox->Disable(); -- looks ugly under MSW
210 virtual ~LboxLogger()
212 wxLog::SetActiveTarget(m_logOld
);
216 // implement sink functions
217 virtual void DoLog(wxLogLevel level
, const wxChar
*szString
, time_t t
)
219 // don't put trace messages into listbox or we can get into infinite
221 if ( level
== wxLOG_Trace
)
225 // cast is needed to call protected method
226 ((LboxLogger
*)m_logOld
)->DoLog(level
, szString
, t
);
231 wxLog::DoLog(level
, szString
, t
);
235 virtual void DoLogString(const wxChar
*szString
, time_t WXUNUSED(t
))
240 #ifdef __WXUNIVERSAL__
241 m_lbox
->AppendAndEnsureVisible(msg
);
242 #else // other ports don't have this method yet
245 // SetFirstItem() isn't implemented in wxGTK
247 m_lbox
->SetFirstItem(m_lbox
->GetCount() - 1);
252 // the control we use
255 // the old log target
260 // ----------------------------------------------------------------------------
262 // ----------------------------------------------------------------------------
264 IMPLEMENT_APP(LboxTestApp
)
266 // ----------------------------------------------------------------------------
268 // ----------------------------------------------------------------------------
270 BEGIN_EVENT_TABLE(LboxTestFrame
, wxFrame
)
271 EVT_BUTTON(LboxTest_Reset
, LboxTestFrame::OnButtonReset
)
272 EVT_BUTTON(LboxTest_Create
, LboxTestFrame::OnButtonCreate
)
273 EVT_BUTTON(LboxTest_Change
, LboxTestFrame::OnButtonChange
)
274 EVT_BUTTON(LboxTest_Delete
, LboxTestFrame::OnButtonDelete
)
275 EVT_BUTTON(LboxTest_DeleteSel
, LboxTestFrame::OnButtonDeleteSel
)
276 EVT_BUTTON(LboxTest_Clear
, LboxTestFrame::OnButtonClear
)
278 EVT_BUTTON(LboxTest_ClearLog
, LboxTestFrame::OnButtonClearLog
)
280 EVT_BUTTON(LboxTest_Add
, LboxTestFrame::OnButtonAdd
)
281 EVT_BUTTON(LboxTest_AddSeveral
, LboxTestFrame::OnButtonAddSeveral
)
282 EVT_BUTTON(LboxTest_AddMany
, LboxTestFrame::OnButtonAddMany
)
283 EVT_BUTTON(LboxTest_Quit
, LboxTestFrame::OnButtonQuit
)
285 EVT_TEXT_ENTER(LboxTest_AddText
, LboxTestFrame::OnButtonAdd
)
286 EVT_TEXT_ENTER(LboxTest_DeleteText
, LboxTestFrame::OnButtonDelete
)
288 EVT_UPDATE_UI_RANGE(LboxTest_Reset
, LboxTest_Create
,
289 LboxTestFrame::OnUpdateUICreateButton
)
291 EVT_UPDATE_UI(LboxTest_AddSeveral
, LboxTestFrame::OnUpdateUIAddSeveral
)
292 EVT_UPDATE_UI(LboxTest_Clear
, LboxTestFrame::OnUpdateUIClearButton
)
293 EVT_UPDATE_UI(LboxTest_DeleteText
, LboxTestFrame::OnUpdateUIClearButton
)
294 EVT_UPDATE_UI(LboxTest_Delete
, LboxTestFrame::OnUpdateUIDeleteButton
)
295 EVT_UPDATE_UI(LboxTest_Change
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
296 EVT_UPDATE_UI(LboxTest_ChangeText
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
297 EVT_UPDATE_UI(LboxTest_DeleteSel
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
299 EVT_LISTBOX(LboxTest_Listbox
, LboxTestFrame::OnListbox
)
300 EVT_LISTBOX_DCLICK(wxID_ANY
, LboxTestFrame::OnListboxDClick
)
301 EVT_CHECKBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
302 EVT_RADIOBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
305 // ============================================================================
307 // ============================================================================
309 // ----------------------------------------------------------------------------
311 // ----------------------------------------------------------------------------
313 bool LboxTestApp::OnInit()
315 wxFrame
*frame
= new LboxTestFrame(_T("wxListBox sample"));
319 //wxLog::AddTraceMask(_T("listbox"));
320 wxLog::AddTraceMask(_T("scrollbar"));
326 // ----------------------------------------------------------------------------
327 // top level frame class
328 // ----------------------------------------------------------------------------
330 LboxTestFrame::LboxTestFrame(const wxString
& title
)
331 : wxFrame(NULL
, wxID_ANY
, title
, wxPoint(100, 100))
335 m_radioSelMode
= (wxRadioBox
*)NULL
;
339 m_chkSort
= (wxCheckBox
*)NULL
;
341 m_lbox
= (wxListBox
*)NULL
;
343 m_lboxLog
= (wxListBox
*)NULL
;
345 m_sizerLbox
= (wxSizer
*)NULL
;
348 m_logTarget
= (wxLog
*)NULL
;
351 wxPanel
*panel
= new wxPanel(this, wxID_ANY
);
354 What we create here is a frame having 3 panes: the explanatory pane to
355 the left allowing to set the listbox styles and recreate the control,
356 the pane containing the listbox itself and the lower pane containing
357 the buttons which allow to add/change/delete strings to/from it.
359 wxSizer
*sizerTop
= new wxBoxSizer(wxVERTICAL
),
360 *sizerUp
= new wxBoxSizer(wxHORIZONTAL
),
362 *sizerRight
= new wxBoxSizer(wxVERTICAL
);
365 static const wxString modes
[] =
372 wxStaticBox
*box
= new wxStaticBox(panel
, wxID_ANY
, _T("&Set listbox parameters"));
373 m_radioSelMode
= new wxRadioBox(panel
, wxID_ANY
, _T("Selection &mode:"),
374 wxDefaultPosition
, wxDefaultSize
,
375 WXSIZEOF(modes
), modes
,
376 1, wxRA_SPECIFY_COLS
);
378 m_chkVScroll
= new wxCheckBox(panel
, wxID_ANY
, _T("Always show &vertical scrollbar"));
379 m_chkHScroll
= new wxCheckBox(panel
, wxID_ANY
, _T("Show &horizontal scrollbar"));
380 m_chkSort
= new wxCheckBox(panel
, wxID_ANY
, _T("&Sort items"));
382 sizerLeft
= new wxStaticBoxSizer(box
, wxVERTICAL
);
384 sizerLeft
->Add(m_chkVScroll
, 0, wxLEFT
| wxRIGHT
, 5);
385 sizerLeft
->Add(m_chkHScroll
, 0, wxLEFT
| wxRIGHT
, 5);
386 sizerLeft
->Add(m_chkSort
, 0, wxLEFT
| wxRIGHT
, 5);
387 sizerLeft
->Add(5, 5, 0, wxGROW
| wxALL
, 5); // spacer
388 sizerLeft
->Add(m_radioSelMode
, 0, wxGROW
| wxALL
, 5);
390 wxSizer
*sizerBtn
= new wxBoxSizer(wxHORIZONTAL
);
391 wxButton
*btn
= new wxButton(panel
, LboxTest_Reset
, _T("&Reset"));
392 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
393 btn
= new wxButton(panel
, LboxTest_Create
, _T("&Create"));
394 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
395 sizerLeft
->Add(sizerBtn
, 0, wxALIGN_CENTRE_HORIZONTAL
| wxALL
, 15);
398 wxStaticBox
*box2
= new wxStaticBox(panel
, wxID_ANY
, _T("&Change listbox contents"));
399 wxSizer
*sizerMiddle
= new wxStaticBoxSizer(box2
, wxVERTICAL
);
401 wxSizer
*sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
402 btn
= new wxButton(panel
, LboxTest_Add
, _T("&Add this string"));
403 m_textAdd
= new wxTextCtrl(panel
, LboxTest_AddText
, _T("test item 0"));
404 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
405 sizerRow
->Add(m_textAdd
, 1, wxLEFT
, 5);
406 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
408 btn
= new wxButton(panel
, LboxTest_AddSeveral
, _T("&Insert a few strings"));
409 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
411 btn
= new wxButton(panel
, LboxTest_AddMany
, _T("Add &many strings"));
412 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
414 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
415 btn
= new wxButton(panel
, LboxTest_Change
, _T("C&hange current"));
416 m_textChange
= new wxTextCtrl(panel
, LboxTest_ChangeText
, wxEmptyString
);
417 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
418 sizerRow
->Add(m_textChange
, 1, wxLEFT
, 5);
419 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
421 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
422 btn
= new wxButton(panel
, LboxTest_Delete
, _T("&Delete this item"));
423 m_textDelete
= new wxTextCtrl(panel
, LboxTest_DeleteText
, wxEmptyString
);
424 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
425 sizerRow
->Add(m_textDelete
, 1, wxLEFT
, 5);
426 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
428 btn
= new wxButton(panel
, LboxTest_DeleteSel
, _T("Delete &selection"));
429 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
431 btn
= new wxButton(panel
, LboxTest_Clear
, _T("&Clear"));
432 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
435 m_lbox
= new wxListBox(panel
, LboxTest_Listbox
,
436 wxDefaultPosition
, wxDefaultSize
,
439 sizerRight
->Add(m_lbox
, 1, wxGROW
| wxALL
, 5);
440 sizerRight
->SetMinSize(250, 0);
441 m_sizerLbox
= sizerRight
; // save it to modify it later
443 // the 3 panes panes compose the upper part of the window
444 sizerUp
->Add(sizerLeft
, 0, wxGROW
| (wxALL
& ~wxLEFT
), 10);
445 sizerUp
->Add(sizerMiddle
, 1, wxGROW
| wxALL
, 10);
446 sizerUp
->Add(sizerRight
, 1, wxGROW
| (wxALL
& ~wxRIGHT
), 10);
448 // the lower one only has the log listbox and a button to clear it
450 wxSizer
*sizerDown
= new wxStaticBoxSizer
452 new wxStaticBox(panel
, wxID_ANY
, _T("&Log window")),
455 m_lboxLog
= new wxListBox(panel
, wxID_ANY
);
456 sizerDown
->Add(m_lboxLog
, 1, wxGROW
| wxALL
, 5);
458 wxSizer
*sizerDown
= new wxBoxSizer(wxVERTICAL
);
460 wxBoxSizer
*sizerBtns
= new wxBoxSizer(wxHORIZONTAL
);
462 btn
= new wxButton(panel
, LboxTest_ClearLog
, _T("Clear &log"));
464 sizerBtns
->Add(10, 0); // spacer
466 btn
= new wxButton(panel
, LboxTest_Quit
, _T("E&xit"));
468 sizerDown
->Add(sizerBtns
, 0, wxALL
| wxALIGN_RIGHT
, 5);
470 // put everything together
471 sizerTop
->Add(sizerUp
, 1, wxGROW
| (wxALL
& ~wxBOTTOM
), 10);
472 sizerTop
->Add(0, 5, 0, wxGROW
); // spacer in between
473 sizerTop
->Add(sizerDown
, 0, wxGROW
| (wxALL
& ~wxTOP
), 10);
475 // final initialization
479 panel
->SetSizer(sizerTop
);
482 sizerTop
->SetSizeHints(this);
485 // now that everything is created we can redirect the log messages to the
487 m_logTarget
= new LboxLogger(m_lboxLog
, wxLog::GetActiveTarget());
488 wxLog::SetActiveTarget(m_logTarget
);
492 LboxTestFrame::~LboxTestFrame()
499 // ----------------------------------------------------------------------------
501 // ----------------------------------------------------------------------------
503 void LboxTestFrame::Reset()
505 if ( m_radioSelMode
->GetSelection() == LboxSel_Single
&&
506 !m_chkSort
->GetValue() &&
507 m_chkHScroll
->GetValue() &&
508 !m_chkVScroll
->GetValue() )
514 m_radioSelMode
->SetSelection(LboxSel_Single
);
515 m_chkSort
->SetValue(false);
516 m_chkHScroll
->SetValue(true);
517 m_chkVScroll
->SetValue(false);
522 void LboxTestFrame::CreateLbox()
525 switch ( m_radioSelMode
->GetSelection() )
528 wxFAIL_MSG( _T("unexpected radio box selection") );
530 case LboxSel_Single
: flags
|= wxLB_SINGLE
; break;
531 case LboxSel_Extended
: flags
|= wxLB_EXTENDED
; break;
532 case LboxSel_Multiple
: flags
|= wxLB_MULTIPLE
; break;
535 if ( m_chkVScroll
->GetValue() )
536 flags
|= wxLB_ALWAYS_SB
;
537 if ( m_chkHScroll
->GetValue() )
538 flags
|= wxLB_HSCROLL
;
539 if ( m_chkSort
->GetValue() )
545 int count
= m_lbox
->GetCount();
546 for ( int n
= 0; n
< count
; n
++ )
548 items
.Add(m_lbox
->GetString(n
));
551 m_sizerLbox
->Detach(m_lbox
);
555 m_lbox
= new wxListBox(this, wxID_ANY
,
556 wxDefaultPosition
, wxDefaultSize
,
560 m_sizerLbox
->Add(m_lbox
, 1, wxGROW
| wxALL
, 5);
561 m_sizerLbox
->Layout();
566 // ----------------------------------------------------------------------------
568 // ----------------------------------------------------------------------------
570 void LboxTestFrame::OnButtonQuit(wxCommandEvent
& WXUNUSED(event
))
575 void LboxTestFrame::OnButtonReset(wxCommandEvent
& WXUNUSED(event
))
580 void LboxTestFrame::OnButtonCreate(wxCommandEvent
& WXUNUSED(event
))
585 void LboxTestFrame::OnButtonChange(wxCommandEvent
& WXUNUSED(event
))
587 wxArrayInt selections
;
588 int count
= m_lbox
->GetSelections(selections
);
589 wxString s
= m_textChange
->GetValue();
590 for ( int n
= 0; n
< count
; n
++ )
592 m_lbox
->SetString(selections
[n
], s
);
596 void LboxTestFrame::OnButtonDelete(wxCommandEvent
& WXUNUSED(event
))
599 if ( !m_textDelete
->GetValue().ToULong(&n
) ||
600 (n
>= (unsigned)m_lbox
->GetCount()) )
608 void LboxTestFrame::OnButtonDeleteSel(wxCommandEvent
& WXUNUSED(event
))
610 wxArrayInt selections
;
611 int n
= m_lbox
->GetSelections(selections
);
614 m_lbox
->Delete(selections
[--n
]);
618 void LboxTestFrame::OnButtonClear(wxCommandEvent
& WXUNUSED(event
))
624 void LboxTestFrame::OnButtonClearLog(wxCommandEvent
& WXUNUSED(event
))
630 void LboxTestFrame::OnButtonAdd(wxCommandEvent
& WXUNUSED(event
))
632 static size_t s_item
= 0;
634 wxString s
= m_textAdd
->GetValue();
635 if ( !m_textAdd
->IsModified() )
637 // update the default string
638 m_textAdd
->SetValue(wxString::Format(_T("test item %u"), ++s_item
));
644 void LboxTestFrame::OnButtonAddMany(wxCommandEvent
& WXUNUSED(event
))
646 // "many" means 1000 here
647 for ( size_t n
= 0; n
< 1000; n
++ )
649 m_lbox
->Append(wxString::Format(_T("item #%u"), n
));
653 void LboxTestFrame::OnButtonAddSeveral(wxCommandEvent
& WXUNUSED(event
))
656 items
.Add(_T("First"));
657 items
.Add(_T("another one"));
658 items
.Add(_T("and the last (very very very very very very very very very very long) one"));
659 m_lbox
->InsertItems(items
, 0);
662 void LboxTestFrame::OnUpdateUICreateButton(wxUpdateUIEvent
& event
)
664 event
.Enable(m_dirty
);
667 void LboxTestFrame::OnUpdateUIDeleteButton(wxUpdateUIEvent
& event
)
670 event
.Enable(m_textDelete
->GetValue().ToULong(&n
) &&
671 (n
< (unsigned)m_lbox
->GetCount()));
674 void LboxTestFrame::OnUpdateUIDeleteSelButton(wxUpdateUIEvent
& event
)
676 wxArrayInt selections
;
677 event
.Enable(m_lbox
->GetSelections(selections
) != 0);
680 void LboxTestFrame::OnUpdateUIClearButton(wxUpdateUIEvent
& event
)
682 event
.Enable(m_lbox
->GetCount() != 0);
685 void LboxTestFrame::OnUpdateUIAddSeveral(wxUpdateUIEvent
& event
)
687 event
.Enable(!(m_lbox
->GetWindowStyle() & wxLB_SORT
));
690 void LboxTestFrame::OnListbox(wxCommandEvent
& event
)
692 int sel
= event
.GetInt();
693 m_textDelete
->SetValue(wxString::Format(_T("%d"), sel
));
695 wxLogMessage(_T("Listbox item %d selected"), sel
);
698 void LboxTestFrame::OnListboxDClick(wxCommandEvent
& event
)
700 int sel
= event
.GetInt();
701 wxLogMessage(_T("Listbox item %d double clicked"), sel
);
704 void LboxTestFrame::OnCheckOrRadioBox(wxCommandEvent
& WXUNUSED(event
))