Add wxListCtrl::SetHeaderAttr()

This method can be used to change the list view header appearance.

Add the method declaration, documentation, show it in the sample and implement
it for wxMSW (only, for now).
This commit is contained in:
Vadim Zeitlin 2016-04-17 17:43:09 +02:00
parent dfb993274c
commit 5388c7a72e
7 changed files with 154 additions and 0 deletions

View File

@ -71,6 +71,7 @@ All (GUI):
- Add support for wxSL_MIN_MAX_LABELS and wxSL_VALUE_LABEL to XRC (ousnius).
- Update Scintilla to v3.6.3 (Paul Kulchenko).
- Make wxDataViewCtrl::Expand() expand ancestors in native ports too.
- Add wxListCtrl::SetHeaderAttr().
wxGTK:

View File

@ -411,6 +411,9 @@ public:
void SetAlternateRowColour(const wxColour& colour);
wxColour GetAlternateRowColour() const { return m_alternateRowColour.GetBackgroundColour(); }
// Header attributes support: only implemented in wxMSW currently.
virtual bool SetHeaderAttr(const wxItemAttr& WXUNUSED(attr)) { return false; }
// Checkboxes support: only implemented in wxMSW currently.
virtual bool HasCheckboxes() const { return false; }
virtual bool EnableCheckboxes(bool WXUNUSED(enable) = true) { return false; }

View File

@ -16,6 +16,7 @@
#include "wx/vector.h"
class wxMSWListItemData;
class wxMSWListHeaderCustomDraw;
// define this symbol to indicate the availability of SetColumnsOrder() and
// related functions
@ -115,6 +116,9 @@ public:
bool SetForegroundColour(const wxColour& col);
bool SetBackgroundColour(const wxColour& col);
// Header attributes
virtual bool SetHeaderAttr(const wxItemAttr& attr) wxOVERRIDE;
// Gets information about this column
bool GetColumn(int col, wxListItem& item) const;
@ -461,6 +465,10 @@ private:
void OnCharHook(wxKeyEvent& event);
// Object using for header custom drawing if necessary, may be NULL.
wxMSWListHeaderCustomDraw* m_headerCustomDraw;
wxDECLARE_DYNAMIC_CLASS(wxListCtrl);
wxDECLARE_EVENT_TABLE();
wxDECLARE_NO_COPY_CLASS(wxListCtrl);

View File

@ -1052,6 +1052,25 @@ public:
*/
bool SetColumnsOrder(const wxArrayInt& orders);
/**
Change the font and the colours used for the list control header.
This method can be used to change the appearance of the header shown by
the control in report mode (unless @c wxLC_NO_HEADER style is used).
Currently it is implemented only for wxMSW and does nothing in the
other ports.
@param attr The object containing the font and text and background
colours to use. It may be default, i.e. not specify any custom font
nor colours, to reset any previously set custom attribute.
@return @true if the attributes have been updated or @false if this is
not supported by the current platform.
@since 3.1.1
*/
bool SetHeaderAttr(const wxItemAttr& attr);
/**
Sets the image list associated with the control.

View File

@ -137,6 +137,7 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(LIST_SET_FG_COL, MyFrame::OnSetFgColour)
EVT_MENU(LIST_SET_BG_COL, MyFrame::OnSetBgColour)
EVT_MENU(LIST_ROW_LINES, MyFrame::OnSetRowLines)
EVT_MENU(LIST_CUSTOM_HEADER_ATTR, MyFrame::OnCustomHeaderAttr)
EVT_MENU(LIST_TOGGLE_MULTI_SEL, MyFrame::OnToggleMultiSel)
EVT_MENU(LIST_SHOW_COL_INFO, MyFrame::OnShowColInfo)
EVT_MENU(LIST_SHOW_SEL_INFO, MyFrame::OnShowSelInfo)
@ -160,6 +161,7 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_UPDATE_UI(LIST_SHOW_COL_INFO, MyFrame::OnUpdateUIEnableInReport)
EVT_UPDATE_UI(LIST_TOGGLE_HEADER, MyFrame::OnUpdateUIEnableInReport)
EVT_UPDATE_UI(LIST_CUSTOM_HEADER_ATTR, MyFrame::OnUpdateUIEnableInReport)
EVT_UPDATE_UI(LIST_TOGGLE_MULTI_SEL, MyFrame::OnUpdateToggleMultiSel)
EVT_UPDATE_UI(LIST_TOGGLE_CHECKBOXES, MyFrame::OnUpdateToggleCheckboxes)
@ -276,6 +278,7 @@ MyFrame::MyFrame(const wxChar *title)
menuCol->Append(LIST_SET_FG_COL, wxT("&Foreground colour..."));
menuCol->Append(LIST_SET_BG_COL, wxT("&Background colour..."));
menuCol->AppendCheckItem(LIST_ROW_LINES, wxT("Alternating colours"));
menuCol->AppendCheckItem(LIST_CUSTOM_HEADER_ATTR, "&Custom header attributes");
wxMenuBar *menubar = new wxMenuBar;
menubar->Append(menuFile, wxT("&File"));
@ -894,6 +897,20 @@ void MyFrame::OnSetRowLines(wxCommandEvent& event)
m_listCtrl->Refresh();
}
void MyFrame::OnCustomHeaderAttr(wxCommandEvent& event)
{
wxItemAttr attr;
if ( event.IsChecked() )
{
attr.SetTextColour(*wxBLUE);
attr.SetFont(wxFontInfo(24).Italic());
}
//else: leave it as default to disable custom header attributes
if ( !m_listCtrl->SetHeaderAttr(attr) )
wxLogMessage("Sorry, header attributes not supported on this platform");
}
void MyFrame::OnAdd(wxCommandEvent& WXUNUSED(event))
{
m_listCtrl->InsertItem(m_listCtrl->GetItemCount(), wxT("Appended item"));

View File

@ -132,6 +132,7 @@ protected:
void OnSetFgColour(wxCommandEvent& event);
void OnSetBgColour(wxCommandEvent& event);
void OnSetRowLines(wxCommandEvent& event);
void OnCustomHeaderAttr(wxCommandEvent& event);
void OnToggleMultiSel(wxCommandEvent& event);
void OnShowColInfo(wxCommandEvent& event);
void OnShowSelInfo(wxCommandEvent& event);
@ -221,6 +222,7 @@ enum
LIST_SET_FG_COL,
LIST_SET_BG_COL,
LIST_ROW_LINES,
LIST_CUSTOM_HEADER_ATTR,
LIST_TOGGLE_MULTI_SEL,
LIST_TOGGLE_HEADER,
LIST_TOGGLE_BELL,

View File

@ -42,6 +42,7 @@
#include "wx/vector.h"
#include "wx/msw/private.h"
#include "wx/msw/private/customdraw.h"
#include "wx/msw/private/keyboard.h"
// Currently gcc doesn't define NMLVFINDITEM, and DMC only defines
@ -229,6 +230,34 @@ public:
wxDECLARE_NO_COPY_CLASS(wxMSWListItemData);
};
// wxMSWListHeaderCustomDraw: custom draw helper for the header
class wxMSWListHeaderCustomDraw : public wxMSWImpl::CustomDraw
{
public:
wxMSWListHeaderCustomDraw()
{
}
// Make this field public to let wxListCtrl update it directly when its
// header attributes change.
wxItemAttr m_attr;
private:
virtual bool HasCustomDrawnItems() const wxOVERRIDE
{
// We only exist if the header does need to be custom drawn.
return true;
}
virtual const wxItemAttr*
GetItemAttr(DWORD_PTR WXUNUSED(dwItemSpec)) const wxOVERRIDE
{
// We use the same attribute for all items for now.
return &m_attr;
}
};
wxBEGIN_EVENT_TABLE(wxListCtrl, wxListCtrlBase)
EVT_PAINT(wxListCtrl::OnPaint)
EVT_CHAR_HOOK(wxListCtrl::OnCharHook)
@ -255,6 +284,8 @@ void wxListCtrl::Init()
m_textCtrl = NULL;
m_hasAnyAttr = false;
m_headerCustomDraw = NULL;
}
bool wxListCtrl::Create(wxWindow *parent,
@ -434,6 +465,8 @@ wxListCtrl::~wxListCtrl()
delete m_imageListSmall;
if (m_ownsImageListState)
delete m_imageListState;
delete m_headerCustomDraw;
}
// ----------------------------------------------------------------------------
@ -520,6 +553,68 @@ bool wxListCtrl::SetBackgroundColour(const wxColour& col)
return true;
}
bool wxListCtrl::SetHeaderAttr(const wxItemAttr& attr)
{
// We need to propagate the change of the font to the native header window
// as it also affects its layout.
bool fontChanged;
// Start or stop custom drawing the header.
if ( attr.IsDefault() )
{
if ( !m_headerCustomDraw )
{
// Nothing changed, skip refreshing the control below.
return true;
}
fontChanged = m_headerCustomDraw->m_attr.HasFont();
delete m_headerCustomDraw;
m_headerCustomDraw = NULL;
}
else // We do have custom attributes.
{
if ( !m_headerCustomDraw )
m_headerCustomDraw = new wxMSWListHeaderCustomDraw();
if ( m_headerCustomDraw->m_attr == attr )
{
// As above, skip refresh.
return true;
}
fontChanged = attr.GetFont() != m_headerCustomDraw->m_attr.GetFont();
m_headerCustomDraw->m_attr = attr;
}
if ( HWND hwndHdr = ListView_GetHeader(GetHwnd()) )
{
if ( fontChanged )
{
// Don't just reset the font if no font is specified, as the header
// uses the same font as the listview control and not the ugly
// default GUI font by default.
const wxFont& font = attr.HasFont() ? attr.GetFont() : GetFont();
// We need to tell the header about its new font to let it compute
// its new height.
::SendMessage(hwndHdr, WM_SETFONT,
(WPARAM)GetHfontOf(font), MAKELPARAM(TRUE, 0));
}
// Refreshing the listview makes it notice the change in height of its
// header and redraws it too. We probably could do something less than
// a full refresh, but it doesn't seem to be worth it, the header
// attributes won't be changed that often, so keep it simple for now.
Refresh();
}
//else: header not shown or not in report view?
return true;
}
// Gets information about this column
bool wxListCtrl::GetColumn(int col, wxListItem& item) const
{
@ -2085,6 +2180,15 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
// doesn't seem to have any negative consequences
return true;
case NM_CUSTOMDRAW:
if ( m_headerCustomDraw )
{
*result = m_headerCustomDraw->HandleCustomDraw(lParam);
if ( *result != CDRF_DODEFAULT )
return true;
}
wxFALLTHROUGH;
default:
ignore = true;
}