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
;
180 // the listbox for logging messages
181 wxListBox
*m_lboxLog
;
184 // the text entries for "Add/change string" and "Delete" buttons
185 wxTextCtrl
*m_textAdd
,
191 // the log target we use to redirect messages to the listbox
195 // any class wishing to process wxWidgets events must use this macro
196 DECLARE_EVENT_TABLE()
200 // A log target which just redirects the messages to a listbox
201 class LboxLogger
: public wxLog
204 LboxLogger(wxListBox
*lbox
, wxLog
*logOld
)
207 //m_lbox->Disable(); -- looks ugly under MSW
211 virtual ~LboxLogger()
213 wxLog::SetActiveTarget(m_logOld
);
217 // implement sink functions
218 virtual void DoLog(wxLogLevel level
, const wxChar
*szString
, time_t t
)
220 // don't put trace messages into listbox or we can get into infinite
222 if ( level
== wxLOG_Trace
)
226 // cast is needed to call protected method
227 ((LboxLogger
*)m_logOld
)->DoLog(level
, szString
, t
);
232 wxLog::DoLog(level
, szString
, t
);
236 virtual void DoLogString(const wxChar
*szString
, time_t WXUNUSED(t
))
241 #ifdef __WXUNIVERSAL__
242 m_lbox
->AppendAndEnsureVisible(msg
);
243 #else // other ports don't have this method yet
246 // SetFirstItem() isn't implemented in wxGTK
248 m_lbox
->SetFirstItem(m_lbox
->GetCount() - 1);
253 // the control we use
256 // the old log target
261 // ----------------------------------------------------------------------------
263 // ----------------------------------------------------------------------------
265 IMPLEMENT_APP(LboxTestApp
)
267 // ----------------------------------------------------------------------------
269 // ----------------------------------------------------------------------------
271 BEGIN_EVENT_TABLE(LboxTestFrame
, wxFrame
)
272 EVT_BUTTON(LboxTest_Reset
, LboxTestFrame::OnButtonReset
)
273 EVT_BUTTON(LboxTest_Create
, LboxTestFrame::OnButtonCreate
)
274 EVT_BUTTON(LboxTest_Change
, LboxTestFrame::OnButtonChange
)
275 EVT_BUTTON(LboxTest_Delete
, LboxTestFrame::OnButtonDelete
)
276 EVT_BUTTON(LboxTest_DeleteSel
, LboxTestFrame::OnButtonDeleteSel
)
277 EVT_BUTTON(LboxTest_Clear
, LboxTestFrame::OnButtonClear
)
279 EVT_BUTTON(LboxTest_ClearLog
, LboxTestFrame::OnButtonClearLog
)
281 EVT_BUTTON(LboxTest_Add
, LboxTestFrame::OnButtonAdd
)
282 EVT_BUTTON(LboxTest_AddSeveral
, LboxTestFrame::OnButtonAddSeveral
)
283 EVT_BUTTON(LboxTest_AddMany
, LboxTestFrame::OnButtonAddMany
)
284 EVT_BUTTON(LboxTest_Quit
, LboxTestFrame::OnButtonQuit
)
286 EVT_TEXT_ENTER(LboxTest_AddText
, LboxTestFrame::OnButtonAdd
)
287 EVT_TEXT_ENTER(LboxTest_DeleteText
, LboxTestFrame::OnButtonDelete
)
289 EVT_UPDATE_UI_RANGE(LboxTest_Reset
, LboxTest_Create
,
290 LboxTestFrame::OnUpdateUICreateButton
)
292 EVT_UPDATE_UI(LboxTest_AddSeveral
, LboxTestFrame::OnUpdateUIAddSeveral
)
293 EVT_UPDATE_UI(LboxTest_Clear
, LboxTestFrame::OnUpdateUIClearButton
)
294 EVT_UPDATE_UI(LboxTest_DeleteText
, LboxTestFrame::OnUpdateUIClearButton
)
295 EVT_UPDATE_UI(LboxTest_Delete
, LboxTestFrame::OnUpdateUIDeleteButton
)
296 EVT_UPDATE_UI(LboxTest_Change
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
297 EVT_UPDATE_UI(LboxTest_ChangeText
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
298 EVT_UPDATE_UI(LboxTest_DeleteSel
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
300 EVT_LISTBOX(LboxTest_Listbox
, LboxTestFrame::OnListbox
)
301 EVT_LISTBOX_DCLICK(wxID_ANY
, LboxTestFrame::OnListboxDClick
)
302 EVT_CHECKBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
303 EVT_RADIOBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
306 // ============================================================================
308 // ============================================================================
310 // ----------------------------------------------------------------------------
312 // ----------------------------------------------------------------------------
314 bool LboxTestApp::OnInit()
316 wxFrame
*frame
= new LboxTestFrame(_T("wxListBox sample"));
320 //wxLog::AddTraceMask(_T("listbox"));
321 wxLog::AddTraceMask(_T("scrollbar"));
327 // ----------------------------------------------------------------------------
328 // top level frame class
329 // ----------------------------------------------------------------------------
331 LboxTestFrame::LboxTestFrame(const wxString
& title
)
332 : wxFrame(NULL
, wxID_ANY
, title
, wxPoint(100, 100))
336 m_radioSelMode
= (wxRadioBox
*)NULL
;
340 m_chkSort
= (wxCheckBox
*)NULL
;
342 m_lbox
= (wxListBox
*)NULL
;
344 m_lboxLog
= (wxListBox
*)NULL
;
346 m_sizerLbox
= (wxSizer
*)NULL
;
349 m_logTarget
= (wxLog
*)NULL
;
352 wxPanel
*panel
= new wxPanel(this, wxID_ANY
);
355 What we create here is a frame having 3 panes: the explanatory pane to
356 the left allowing to set the listbox styles and recreate the control,
357 the pane containing the listbox itself and the lower pane containing
358 the buttons which allow to add/change/delete strings to/from it.
360 wxSizer
*sizerTop
= new wxBoxSizer(wxVERTICAL
),
361 *sizerUp
= new wxBoxSizer(wxHORIZONTAL
),
363 *sizerRight
= new wxBoxSizer(wxVERTICAL
);
366 static const wxString modes
[] =
373 wxStaticBox
*box
= new wxStaticBox(panel
, wxID_ANY
, _T("&Set listbox parameters"));
374 m_radioSelMode
= new wxRadioBox(panel
, wxID_ANY
, _T("Selection &mode:"),
375 wxDefaultPosition
, wxDefaultSize
,
376 WXSIZEOF(modes
), modes
,
377 1, wxRA_SPECIFY_COLS
);
379 m_chkVScroll
= new wxCheckBox(panel
, wxID_ANY
, _T("Always show &vertical scrollbar"));
380 m_chkHScroll
= new wxCheckBox(panel
, wxID_ANY
, _T("Show &horizontal scrollbar"));
381 m_chkSort
= new wxCheckBox(panel
, wxID_ANY
, _T("&Sort items"));
383 sizerLeft
= new wxStaticBoxSizer(box
, wxVERTICAL
);
385 sizerLeft
->Add(m_chkVScroll
, 0, wxLEFT
| wxRIGHT
, 5);
386 sizerLeft
->Add(m_chkHScroll
, 0, wxLEFT
| wxRIGHT
, 5);
387 sizerLeft
->Add(m_chkSort
, 0, wxLEFT
| wxRIGHT
, 5);
388 sizerLeft
->Add(5, 5, 0, wxGROW
| wxALL
, 5); // spacer
389 sizerLeft
->Add(m_radioSelMode
, 0, wxGROW
| wxALL
, 5);
391 wxSizer
*sizerBtn
= new wxBoxSizer(wxHORIZONTAL
);
392 wxButton
*btn
= new wxButton(panel
, LboxTest_Reset
, _T("&Reset"));
393 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
394 btn
= new wxButton(panel
, LboxTest_Create
, _T("&Create"));
395 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
396 sizerLeft
->Add(sizerBtn
, 0, wxALIGN_CENTRE_HORIZONTAL
| wxALL
, 15);
399 wxStaticBox
*box2
= new wxStaticBox(panel
, wxID_ANY
, _T("&Change listbox contents"));
400 wxSizer
*sizerMiddle
= new wxStaticBoxSizer(box2
, wxVERTICAL
);
402 wxSizer
*sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
403 btn
= new wxButton(panel
, LboxTest_Add
, _T("&Add this string"));
404 m_textAdd
= new wxTextCtrl(panel
, LboxTest_AddText
, _T("test item 0"));
405 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
406 sizerRow
->Add(m_textAdd
, 1, wxLEFT
, 5);
407 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
409 btn
= new wxButton(panel
, LboxTest_AddSeveral
, _T("&Insert a few strings"));
410 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
412 btn
= new wxButton(panel
, LboxTest_AddMany
, _T("Add &many strings"));
413 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
415 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
416 btn
= new wxButton(panel
, LboxTest_Change
, _T("C&hange current"));
417 m_textChange
= new wxTextCtrl(panel
, LboxTest_ChangeText
, wxEmptyString
);
418 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
419 sizerRow
->Add(m_textChange
, 1, wxLEFT
, 5);
420 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
422 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
423 btn
= new wxButton(panel
, LboxTest_Delete
, _T("&Delete this item"));
424 m_textDelete
= new wxTextCtrl(panel
, LboxTest_DeleteText
, wxEmptyString
);
425 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
426 sizerRow
->Add(m_textDelete
, 1, wxLEFT
, 5);
427 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
429 btn
= new wxButton(panel
, LboxTest_DeleteSel
, _T("Delete &selection"));
430 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
432 btn
= new wxButton(panel
, LboxTest_Clear
, _T("&Clear"));
433 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
436 m_lbox
= new wxListBox(panel
, LboxTest_Listbox
,
437 wxDefaultPosition
, wxDefaultSize
,
440 sizerRight
->Add(m_lbox
, 1, wxGROW
| wxALL
, 5);
441 sizerRight
->SetMinSize(250, 0);
442 m_sizerLbox
= sizerRight
; // save it to modify it later
444 // the 3 panes panes compose the upper part of the window
445 sizerUp
->Add(sizerLeft
, 0, wxGROW
| (wxALL
& ~wxLEFT
), 10);
446 sizerUp
->Add(sizerMiddle
, 1, wxGROW
| wxALL
, 10);
447 sizerUp
->Add(sizerRight
, 1, wxGROW
| (wxALL
& ~wxRIGHT
), 10);
449 // the lower one only has the log listbox and a button to clear it
451 wxSizer
*sizerDown
= new wxStaticBoxSizer
453 new wxStaticBox(panel
, wxID_ANY
, _T("&Log window")),
456 m_lboxLog
= new wxListBox(panel
, wxID_ANY
);
457 sizerDown
->Add(m_lboxLog
, 1, wxGROW
| wxALL
, 5);
459 wxSizer
*sizerDown
= new wxBoxSizer(wxVERTICAL
);
461 wxBoxSizer
*sizerBtns
= new wxBoxSizer(wxHORIZONTAL
);
463 btn
= new wxButton(panel
, LboxTest_ClearLog
, _T("Clear &log"));
465 sizerBtns
->Add(10, 0); // spacer
467 btn
= new wxButton(panel
, LboxTest_Quit
, _T("E&xit"));
469 sizerDown
->Add(sizerBtns
, 0, wxALL
| wxALIGN_RIGHT
, 5);
471 // put everything together
472 sizerTop
->Add(sizerUp
, 1, wxGROW
| (wxALL
& ~wxBOTTOM
), 10);
473 sizerTop
->Add(0, 5, 0, wxGROW
); // spacer in between
474 sizerTop
->Add(sizerDown
, 0, wxGROW
| (wxALL
& ~wxTOP
), 10);
476 // final initialization
480 panel
->SetSizer(sizerTop
);
483 sizerTop
->SetSizeHints(this);
486 // now that everything is created we can redirect the log messages to the
488 m_logTarget
= new LboxLogger(m_lboxLog
, wxLog::GetActiveTarget());
489 wxLog::SetActiveTarget(m_logTarget
);
492 m_lbox
->Connect(wxEVT_RIGHT_DOWN
,
493 wxMouseEventHandler(LboxTestFrame::OnListboxRDown
), NULL
, this);
496 LboxTestFrame::~LboxTestFrame()
503 // ----------------------------------------------------------------------------
505 // ----------------------------------------------------------------------------
507 void LboxTestFrame::Reset()
509 if ( m_radioSelMode
->GetSelection() == LboxSel_Single
&&
510 !m_chkSort
->GetValue() &&
511 m_chkHScroll
->GetValue() &&
512 !m_chkVScroll
->GetValue() )
518 m_radioSelMode
->SetSelection(LboxSel_Single
);
519 m_chkSort
->SetValue(false);
520 m_chkHScroll
->SetValue(true);
521 m_chkVScroll
->SetValue(false);
526 void LboxTestFrame::CreateLbox()
528 wxWindow
*parent
= m_lbox
->GetParent();
530 switch ( m_radioSelMode
->GetSelection() )
533 wxFAIL_MSG( _T("unexpected radio box selection") );
535 case LboxSel_Single
: flags
|= wxLB_SINGLE
; break;
536 case LboxSel_Extended
: flags
|= wxLB_EXTENDED
; break;
537 case LboxSel_Multiple
: flags
|= wxLB_MULTIPLE
; break;
540 if ( m_chkVScroll
->GetValue() )
541 flags
|= wxLB_ALWAYS_SB
;
542 if ( m_chkHScroll
->GetValue() )
543 flags
|= wxLB_HSCROLL
;
544 if ( m_chkSort
->GetValue() )
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
);
557 m_lbox
= new wxListBox(parent
, LboxTest_Listbox
,
558 wxDefaultPosition
, wxDefaultSize
,
562 m_sizerLbox
->Add(m_lbox
, 1, wxGROW
| wxALL
, 5);
563 m_sizerLbox
->Layout();
568 // ----------------------------------------------------------------------------
570 // ----------------------------------------------------------------------------
572 void LboxTestFrame::OnButtonQuit(wxCommandEvent
& WXUNUSED(event
))
577 void LboxTestFrame::OnButtonReset(wxCommandEvent
& WXUNUSED(event
))
582 void LboxTestFrame::OnButtonCreate(wxCommandEvent
& WXUNUSED(event
))
587 void LboxTestFrame::OnButtonChange(wxCommandEvent
& WXUNUSED(event
))
589 wxArrayInt selections
;
590 int count
= m_lbox
->GetSelections(selections
);
591 wxString s
= m_textChange
->GetValue();
592 for ( int n
= 0; n
< count
; n
++ )
594 m_lbox
->SetString(selections
[n
], s
);
598 void LboxTestFrame::OnButtonDelete(wxCommandEvent
& WXUNUSED(event
))
601 if ( !m_textDelete
->GetValue().ToULong(&n
) ||
602 (n
>= (unsigned)m_lbox
->GetCount()) )
610 void LboxTestFrame::OnButtonDeleteSel(wxCommandEvent
& WXUNUSED(event
))
612 wxArrayInt selections
;
613 int n
= m_lbox
->GetSelections(selections
);
616 m_lbox
->Delete(selections
[--n
]);
620 void LboxTestFrame::OnButtonClear(wxCommandEvent
& WXUNUSED(event
))
626 void LboxTestFrame::OnButtonClearLog(wxCommandEvent
& WXUNUSED(event
))
632 void LboxTestFrame::OnButtonAdd(wxCommandEvent
& WXUNUSED(event
))
634 static size_t s_item
= 0;
636 wxString s
= m_textAdd
->GetValue();
637 if ( !m_textAdd
->IsModified() )
639 // update the default string
640 m_textAdd
->SetValue(wxString::Format(_T("test item %u"), ++s_item
));
646 void LboxTestFrame::OnButtonAddMany(wxCommandEvent
& WXUNUSED(event
))
648 // "many" means 1000 here
649 for ( size_t n
= 0; n
< 1000; n
++ )
651 m_lbox
->Append(wxString::Format(_T("item #%u"), n
));
655 void LboxTestFrame::OnButtonAddSeveral(wxCommandEvent
& WXUNUSED(event
))
658 items
.Add(_T("First"));
659 items
.Add(_T("another one"));
660 items
.Add(_T("and the last (very very very very very very very very very very long) one"));
661 m_lbox
->InsertItems(items
, 0);
664 void LboxTestFrame::OnUpdateUICreateButton(wxUpdateUIEvent
& event
)
666 event
.Enable(m_dirty
);
669 void LboxTestFrame::OnUpdateUIDeleteButton(wxUpdateUIEvent
& event
)
672 event
.Enable(m_textDelete
->GetValue().ToULong(&n
) &&
673 (n
< (unsigned)m_lbox
->GetCount()));
676 void LboxTestFrame::OnUpdateUIDeleteSelButton(wxUpdateUIEvent
& event
)
678 wxArrayInt selections
;
679 event
.Enable(m_lbox
->GetSelections(selections
) != 0);
682 void LboxTestFrame::OnUpdateUIClearButton(wxUpdateUIEvent
& event
)
684 event
.Enable(m_lbox
->GetCount() != 0);
687 void LboxTestFrame::OnUpdateUIAddSeveral(wxUpdateUIEvent
& event
)
689 event
.Enable(!(m_lbox
->GetWindowStyle() & wxLB_SORT
));
692 void LboxTestFrame::OnListbox(wxCommandEvent
& event
)
694 int sel
= event
.GetInt();
695 m_textDelete
->SetValue(wxString::Format(_T("%d"), sel
));
697 wxLogMessage(_T("Listbox item %d selected"), sel
);
700 void LboxTestFrame::OnListboxDClick(wxCommandEvent
& event
)
702 int sel
= event
.GetInt();
703 wxLogMessage(_T("Listbox item %d double clicked"), sel
);
706 void LboxTestFrame::OnListboxRDown(wxMouseEvent
& event
)
708 int item
= m_lbox
->HitTest(event
.GetPosition());
710 if ( item
!= wxNOT_FOUND
)
711 wxLogMessage(_T("Listbox item %d right clicked"), item
);
713 wxLogMessage(_T("Listbox right clicked but no item clicked upon"));
718 void LboxTestFrame::OnCheckOrRadioBox(wxCommandEvent
& WXUNUSED(event
))