CListViewCtrl creation does not produce column header arrow indicating sort order
-
I have a Dialog, inheriting from
CDialogImpl
, which contains aCListViewCtrl
with three columns. In order to get the list items ordered correctly a custom sort function is used. It is in my handler forLVN_COLUMNCLICK<
(Clicking a column header) that that the column header has the triangular bitmap indicating sort direction set. On creation of the dialog, without the workaround shown below, no sort direction arrow appears on the header. I then have to call theLVN_COLUMNCLICK
handler (see code) from OnInitDialog to force a sort of the first column in the order that myLVN_COLUMNCLICK
handler sets the sort order triangular bitmap in the column header.LRESULT CPortsDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
...// Work-around to force list control to sort column 0 ascending on creation int idCtrl = 0; NMLISTVIEW nmlv; nmlv.iSubItem = 0; BOOL bHandled = FALSE; LPNMHDR lpNMHDR = reinterpret\_cast<LPNMHDR>(&nmlv); OnLvnColumnclick(idCtrl, lpNMHDR, bHandled); return 0;
}
This doesn't seem right; am I missing some feature that will ensure that upon creation a particular list column is sorted (using my custom sort) in, say, ascending order with the appropriate column header bitmap displayed to indicate this?
LRESULT CPortsDlg::OnLvnColumnclick(int /*idCtrl*/, LPNMHDR pNMHDR, BOOL& /*bHandled*/)
{
// Get some calls where m_hwnd is 0
if(!::IsWindow(m_hWnd))
{
return 0;
}// ListView Notification Message structure LPNMLISTVIEW pNMLV = reinterpret\_cast<LPNMLISTVIEW>(pNMHDR); // Want the format of the list column header HDITEM HeaderItem; HeaderItem.mask = HDI\_FORMAT; // Attach a CHeaderCtrl to this CListViewCtrl's header CHeaderCtrl HeaderCtrl = m\_ListViewCtrl.GetHeader(); if(!::IsWindow(HeaderCtrl.m\_hWnd)) { return 0; } // For each list column... int nColumnCount = HeaderCtrl.GetItemCount(); for(int nSelectedColumn = 0; nSelectedColumn < nColumnCount; nSelectedColumn++) { // Get the format for the sub-item (column) HeaderCtrl.GetItem(nSelectedColumn, &HeaderItem); // Remove any up/down arrow from this column HeaderItem.fmt &= ~(HDF\_SORTDOWN | HDF\_SORTUP); if(nSelectedColumn == pNMLV->iSubItem) { // If this is a different column from any selected before use an up-arrow otherwise // base it on changing the direction from m\_S
-
I have a Dialog, inheriting from
CDialogImpl
, which contains aCListViewCtrl
with three columns. In order to get the list items ordered correctly a custom sort function is used. It is in my handler forLVN_COLUMNCLICK<
(Clicking a column header) that that the column header has the triangular bitmap indicating sort direction set. On creation of the dialog, without the workaround shown below, no sort direction arrow appears on the header. I then have to call theLVN_COLUMNCLICK
handler (see code) from OnInitDialog to force a sort of the first column in the order that myLVN_COLUMNCLICK
handler sets the sort order triangular bitmap in the column header.LRESULT CPortsDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
...// Work-around to force list control to sort column 0 ascending on creation int idCtrl = 0; NMLISTVIEW nmlv; nmlv.iSubItem = 0; BOOL bHandled = FALSE; LPNMHDR lpNMHDR = reinterpret\_cast<LPNMHDR>(&nmlv); OnLvnColumnclick(idCtrl, lpNMHDR, bHandled); return 0;
}
This doesn't seem right; am I missing some feature that will ensure that upon creation a particular list column is sorted (using my custom sort) in, say, ascending order with the appropriate column header bitmap displayed to indicate this?
LRESULT CPortsDlg::OnLvnColumnclick(int /*idCtrl*/, LPNMHDR pNMHDR, BOOL& /*bHandled*/)
{
// Get some calls where m_hwnd is 0
if(!::IsWindow(m_hWnd))
{
return 0;
}// ListView Notification Message structure LPNMLISTVIEW pNMLV = reinterpret\_cast<LPNMLISTVIEW>(pNMHDR); // Want the format of the list column header HDITEM HeaderItem; HeaderItem.mask = HDI\_FORMAT; // Attach a CHeaderCtrl to this CListViewCtrl's header CHeaderCtrl HeaderCtrl = m\_ListViewCtrl.GetHeader(); if(!::IsWindow(HeaderCtrl.m\_hWnd)) { return 0; } // For each list column... int nColumnCount = HeaderCtrl.GetItemCount(); for(int nSelectedColumn = 0; nSelectedColumn < nColumnCount; nSelectedColumn++) { // Get the format for the sub-item (column) HeaderCtrl.GetItem(nSelectedColumn, &HeaderItem); // Remove any up/down arrow from this column HeaderItem.fmt &= ~(HDF\_SORTDOWN | HDF\_SORTUP); if(nSelectedColumn == pNMLV->iSubItem) { // If this is a different column from any selected before use an up-arrow otherwise // base it on changing the direction from m\_S
It doesn't seem unreasonable to me that you have to tell the control how it's sorted - I suspect that setting
HDF_SORTDOWN
orHDF_SORTUP
on the relevant column and callingm_ListViewCtrl.SortItems
would be sufficient - if that's the case, maybe you should refactor the header flag setting and control sorting into a separate function, so it could be called fromOnInitDialog
rather than calling the OnClick handler? [edit]MaybeCSortListViewCtrl
will do some of the sorting tasks for you, simplifying the overall job?[/edit] -
It doesn't seem unreasonable to me that you have to tell the control how it's sorted - I suspect that setting
HDF_SORTDOWN
orHDF_SORTUP
on the relevant column and callingm_ListViewCtrl.SortItems
would be sufficient - if that's the case, maybe you should refactor the header flag setting and control sorting into a separate function, so it could be called fromOnInitDialog
rather than calling the OnClick handler? [edit]MaybeCSortListViewCtrl
will do some of the sorting tasks for you, simplifying the overall job?[/edit]Stuart, I've done a test using
CSortListViewCtrl
(which I didn't know about) instead ofCListViewCtrl
. It seems that simply callingSetSortColumn(0)
both makes my handler forLVN_COLUMNCLICK
redundant and removes the need to call it from InitDialog. I haven't tried this with a custom sort yet but can see I will need to callSetColumnSortType(0, LVCOLSORT_CUSTOM)
. Much neater. Thanks.