|
Hi,
how to derive a CCtrlView from this wonderful CSortListCtrl? per instance, the CListView MFC class is a derived CCtrlView class using the MFC CListCtrl.
in the .h:
class CMyListView : public CCtrlView
{
...
}
in the .cpp:
IMPLEMENT_DYNCREATE(CMyListView, CCtrlView)
CMyListView::CMyListView() :
CCtrlView(_T("SysListView32"), WS_VISIBLE | WS_CHILD | WS_BORDER)
{
}
so now, I should put "CSortListCtrl" instead of "SysListView32" but it crashes on creation of the CMyListView. (I used SysListView32 in this example as this is the CListCtrl class name; so those lines above will give you the standard CListView view that uses the CListCtrl control).
The CCtrlView expect a LPCTSTR in the first argument, which is the name of the class of the control you want to imbed in the CtrlView View.
What am I doing wrong? Is the CSortListCtrl missing some definition to make it a useful control (i.e. a control which we could imbed in a CtrlView)? or am I just not defining my CCtrlView derived class correctly?
of course, I put the message handling, to make it complete:
BEGIN_MESSAGE_MAP(CMyListView, CCtrlView)
ON_WM_NCDESTROY()
END_MESSAGE_MAP()
and the GetListCtrl() method, but it's the definition of the class that make it crashes (cause if I use "SysListView32", everything is fine)
Thanks
Mat
|
|
|
|
|
i have problems when i close the windows and i open again,because when i add an item appear an error. i think that it is because i dont delete the column before so when i set heading i have 8 unless 4. but i try to delete the column with deletecolumn() but it dosnt work, also i try with deleteallitem() and deleteitem(..) .
BOOL Ver::OnInitDialog()
{
CDialog::OnInitDialog();
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
SetIcon(m_hIcon, FALSE)
(void)m_ctlList.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT );
m_ctlList.SetHeadings( _T("Codigo,50;Categoria,150;Descripcion,350;Precio,50") );
int Index;
char Palabra[100];
CString Codigo, Categoria, Descripcion, Precio;
for (Index = 0; Index < Cant; Index++)
{
strcpy (Palabra, AllPrice[Index]);
Codigo = strtok(Palabra, "|");
Descripcion = strtok(NULL, "|");
Precio= strtok(NULL, "|");
Categoria = strtok(NULL, "|");
(void)m_ctlList.AddItem( _T(Codigo), _T(Categoria), _T(Descripcion), _T(Precio) ); // i have problems hire when i open the dialog again
}
}
m_ctlList.SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
i dont know what i have to do someone can help??
Emiliano
|
|
|
|
|
hi,Emiliano,i have solved this problem last night.the following is the revised code.
BOOL CSortListCtrl::SetHeadings( const CString& strHeadings )
{
int iStart = 0;
m_iNumColumns = 0;//zhao
for( ;; )
{
const int iComma = strHeadings.Find( _T(','), iStart );
if( iComma == -1 )
break;
const CString strHeading = strHeadings.Mid( iStart, iComma - iStart );
iStart = iComma + 1;
int iSemiColon = strHeadings.Find( _T(';'), iStart );
if( iSemiColon == -1 )
iSemiColon = strHeadings.GetLength();
const int iWidth = atoi( strHeadings.Mid( iStart, iSemiColon - iStart ) );
iStart = iSemiColon + 1;
if( InsertColumn( m_iNumColumns++, strHeading, LVCFMT_LEFT, iWidth ) == -1 )
return FALSE;
}
return TRUE;
}
|
|
|
|
|
Hy,
I read your cery useful article.
In my application I use a CSortListCtrl, and a make a search function for it.
Also the searching work good, but I have trouble with selecting!?
I try the following lines:
m_list.SetHotItem(i);
m_list.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED | LVIS_FOCUSED);
m_list.RedrawItems(i, i);
m_list.EnsureVisible(i, FALSE);
m_list.SetSelectionMark(i);
The HotItem working good, but not select the traditional way (blue backgroung color)
EnsureVisible also OK, but not make any selection.
SetItemState, SetSelectionMark doesn't work, and I dont't know why?
Can you help me, how can I select my search result (only one item)?
Regards,
Zoltan
|
|
|
|
|
I had the same problem, what ended up being the cause was my SortListCtrl was out of focus.
When I returned focus to the SortListCtrl itself, then the row selection stuff worked fine.
|
|
|
|
|
I made a program that uses the sort list control and it requires to delete all items (using DeleteAllItems(); ) and insert new items when a user presses a button. However, when it tries to delete allitems after it inserts new ones it crashes. When I debugged it said " Unhandled exception in myprogram.exe: 0xC0000005: Access Violation" and then points to the FreeItemMemory(const int iItem) function.
<br />
void CSortListCtrl::FreeItemMemory( const int iItem )<br />
{<br />
ItemData* pid = reinterpret_cast<ItemData*>( CListCtrl::GetItemData( iItem ) );<br />
<br />
(points:((here) LPTSTR* arrpsz = pid->arrpsz;<br />
<br />
for( int i = 0; i < m_iNumColumns; i++ )<br />
delete[] arrpsz[ i ];<br />
<br />
delete[] arrpsz;<br />
delete pid;<br />
<br />
VERIFY( CListCtrl::SetItemData( iItem, NULL ) );<br />
}<br />
Can someone help please. thanks in advance.
|
|
|
|
|
Anybody can help on this? Thanks!
|
|
|
|
|
Hi comunity,
i need litle help to use this function to draw a arrow on listcontrolheader, where should i implemented this funcion OnPaint() ??? I coment out this lines in :
// change the item to owner drawn.
/*HD_ITEM hditem;
hditem.mask = HDI_FORMAT;
VERIFY( GetItem( iSortColumn, &hditem ) );
hditem.fmt |= HDF_OWNERDRAW;
VERIFY( SetItem( iSortColumn, &hditem ) );*/
and i change the SortHeaderCtrl.h with the function OnPaint(),
//{{AFX_MSG(CSortHeaderCtrl)
// NOTE - the ClassWizard will add and remove member functions here.
afx_msg void OnPaint();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
and i change the SortHeaderCtrl.cpp with the function OnPaint(),
where should i call this OnPaint(), witch place in my SortHeaderCtrl.cpp to show an arrow on a Listheader?? I hope you can understand me
With best regards
Mirsad
|
|
|
|
|
OnPaint is called automatically by the MFC framework for a WM_PAINT message
You can invoke Invalidate() method to send WM_PAINT message.
|
|
|
|
|
Another solution - replace function CSortHeaderCtrl::SetSortArrow with:
for(int i = 0; i < this->GetItemCount(); ++i)
{
HDITEM hditem = {0};
hditem.mask = HDI_FORMAT;
VERIFY( this->GetItem( i, &hditem ) );
hditem.fmt &= ~(HDF_SORTDOWN|HDF_SORTUP);
if (i == iSortColumn)
{
hditem.fmt |= bSortAscending ? HDF_SORTDOWN : HDF_SORTUP;
}
VERIFY( this->SetItem( i, &hditem ) );
}
taken from here:
http://www.codeproject.com/KB/list/clistctrl_sort.aspx
|
|
|
|
|
Hello,
thanks i try your solution!
regards
termal
|
|
|
|
|
Can I use this control with UNICODE string (CString,wchar_t)? thanks!
|
|
|
|
|
|
Hi,
Thanks for a great control - very easy to incorporate!
I had a column of hexadecimal numbers that wasn't sorting correctly. The solution I decided upon was to check both values before deciding which compare function to use:
------------------------------
Old:
int CALLBACK CSortListCtrl::CompareFunction( LPARAM lParam1, LPARAM lParam2, LPARAM lParamData )
{
.
.
if( IsNumber( pszText1 ) )
return pListCtrl->m_bSortAscending ? NumberCompare( pszText1, pszText2 ) : NumberCompare( pszText2, pszText1 );
else if( IsDate( pszText1 ) )
return pListCtrl->m_bSortAscending ? DateCompare( pszText1, pszText2 ) : DateCompare( pszText2, pszText1 );
else
// text.
return pListCtrl->m_bSortAscending ? lstrcmp( pszText1, pszText2 ) : lstrcmp( pszText2, pszText1 );
}
New:
int CALLBACK CSortListCtrl::CompareFunction( LPARAM lParam1, LPARAM lParam2, LPARAM lParamData )
{
.
.
if( IsNumber( pszText1 ) && IsNumber( pszText2 ) )
return pListCtrl->m_bSortAscending ? NumberCompare( pszText1, pszText2 ) : NumberCompare( pszText2, pszText1 );
else if( IsDate( pszText1 ) && IsDate( pszText2 ) )
return pListCtrl->m_bSortAscending ? DateCompare( pszText1, pszText2 ) : DateCompare( pszText2, pszText1 );
else
// text.
return pListCtrl->m_bSortAscending ? lstrcmp( pszText1, pszText2 ) : lstrcmp( pszText2, pszText1 );
}
------------------------------
Anyway, it's enough of a "general-purpose tightening" that I thought it might be useful to provide to others. Thanks again for saving me a lot of time!
Thanks,
Dave
|
|
|
|
|
@dbarndt: I think your solution is not complete. The best would be to 'watch' the item data on inserting, e.g. cache the information if the column is number,date or string.
i would suggest something like (may be not already working, but as a start)
in the class declaration
<br />
enum(TYPE_UNKNOWN=0,TYPE_NUMBER,...);<br />
std::map<int,int> TypeCache;
and in SetItemText():
<br />
if(IsNumber(pText) <br />
&& (TypeCache[nCol]==TYPE_UNKNOWN)<br />
||(TypeCache[nCol]==TYPE_NUMBER))<br />
{<br />
TypeCache[nCol]=TYPE_NUMBER;<br />
}<br />
else if(IsDate(pText) <br />
&& (TypeCache[nCol]==TYPE_UNKNOWN)<br />
||(TypeCache[nCol]==TYPE_DATE))<br />
{<br />
TypeCache[nCol]=TYPE_DATE;<br />
}<br />
else<br />
TypeCache[nCol]=TYPE_STRING;
this way, the whole column gets type date (or string) when 'any' of the items does not match criteria for number (or string).
important is:
- that type unknown (initial call for this column) can be changed to any type
- type date or type number can only be changed to 'string'
you also have to change the compare function, read out the cache for the type instead of interpreting the text (would be much faster, too )
One Problem is still left: MS missed to make SetItemText() virtual, if you handle the class via CListCtrl* while adding data, the lparam is not set! oes anyone have an idea how to solve this issue? Maybe via OnChildNotify() ?
-- modified at 11:15 Sunday 5th March, 2006
|
|
|
|
|
Have you finished your suggestion?
If yes. Could you send me the new files with your changes.
You can send to ruifrazao@hotmail.com
Thanks. Rui
|
|
|
|
|
Dear M. Jackson, can you please explain to us, the ignorants, what the hell is
this (void) thing i keep seeing all around, for example:
(void)dc.SelectObject( &rgn );
With all my regards, this is an explicit bullshit and waste of time, don't you agree??
|
|
|
|
|
Some compilers will warn if you do not handle return values from functions. Casting with (void) is one way to make it shut up.
Lint is also quite noisy about not handling return values.
I wonder though what's up with your attitude? Do you normally approach people like this?
--
Weiter, weiter, ins verderben.
Wir müssen leben bis wir sterben.
I blog too now[^]
|
|
|
|
|
Hi folks
I need to change header and columns.
I am doing that by inserting columns with:
void RedoHeader ()
{
CHeaderCtrl *pHeader = m_List.GetHeaderCtrl();
int iColumns=pHeader->GetItemCount ();
for (int i=iColumns; i>=0; i--)
pHeader->DeleteItem (i);
m_List.SetHeadings(_T(szNewColumns));
m_List.LoadColumnInfo();
m_List.AddItem (_T(szNewItems);
}
It works fine but when i call it a second time it does not display the items. They are actually added becuase i can read them, and i see the scrollbar moving but they are not visible.
Anyone has an idea?
Thank you
Thomas
Thomas Rusch
|
|
|
|
|
Hi,
I added two functions which I missed:
int CSortListCtrl::InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int Format, int nWidth, int nSubItem)
{
if (nCol >= m_iNumColumns)
m_iNumColumns = nCol+1;
return CListCtrl::InsertColumn(nCol, lpszColumnHeading, Format, nWidth, nSubItem);
}
int CSortListCtrl::InsertItem( int index, LPCTSTR pszText, int image)
{
const int iIndex = CListCtrl::InsertItem( index, pszText, image );
LPTSTR* arrpsz = new LPTSTR[ m_iNumColumns ];
arrpsz[ 0 ] = new TCHAR[ lstrlen( pszText ) + 1 ];
(void)lstrcpy( arrpsz[ 0 ], pszText );
for (int i = 1; i < m_iNumColumns; ++i)
arrpsz[ i ] = 0;
VERIFY( SetTextArray( iIndex, arrpsz ) );
return iIndex;
}
class CSortListCtrl : public CListCtrl
{
...
int InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int Format = LVCFMT_LEFT, int nWidth = -1, int nSubItem = -1);
int InsertItem( int index, LPCTSTR pszText, int = 0);
...
};
It's now a bit more compatible with the standard CListCtrl.
Sincerely
Volkmar Kostka
|
|
|
|
|
Thank you sir!
I was trying to sort out a problem I was having with migrating from the standard ListCtrl to this code and inserting your functions made for a quick fix. I appreciate it!
|
|
|
|
|
Hi!
Nice initiative.
However addings these two functions to the Extended list control causes the application to crash at startup.
I didn't yet started to figure out what's the problem.
If anybody knows, please post a message here.
Best wishes!
I am in love with VC++
|
|
|
|
|
This is because AddItem is implemented in terms of InsertItem, both of which are calling SetTextArray(), the second call of which ASSERTs because there is item data.
The simplest solution is to change the call to InsertItem in AddItem to CListCtrl::InsertItem
--
http://www.coruscant.ltd.uk/
|
|
|
|
|
In the CSortHeaderCtrl::SetSortArrow() method, there is a bug
// for every column, clear the sort up/down flags
for ( int i=0; i < GetItemCount(); i++ )
{
HD_ITEM hditem;
GetItem(i, &hditem);
hditem.mask = HDI_FORMAT;
hditem.mask = HDI_FORMAT needs to be set before the call to GetItem
ie the above snippet should read:
// for every column, clear the sort up/down flags
for ( int i=0; i < GetItemCount(); i++ )
{
HD_ITEM hditem;
hditem.mask = HDI_FORMAT;
GetItem(i, &hditem);
|
|
|
|
|
Hi Mark!
I guess you are not aware of CListCtrl::FindItem function.
in your article you said (you wrote "real" in CAPS )
Implementation
It was a REAL pain to do, your callback function gets the item data for the two rows to compare, but what use is that, you need the text to compare! This control stores the text for the columns in the item data, so the compare function can get at it, it also allows users of the control to use the item data as usual.
You can always find index of item by providing item data and use FindItem function and once you have index, you can get everything about that item.
Here is what I do inside a list control sorting callback function.
<br />
int <br />
CMyListCtrl::CompareProc(LPARAM lParam1, LPARAM lParam2)<br />
{<br />
int nRet = 0;<br />
LVFINDINFO fi = { 0 };<br />
fi.flags = LVFI_PARAM;<br />
fi.lParam = lParam1;<br />
int item1 = FindItem(&fi);<br />
<br />
fi.lParam = lParam2;<br />
int item2 = FindItem(&fi);<br />
CString csTextItem1 = GetItemText(item1, mnSortCol);<br />
CString csTextItem2 = GetItemText(item2, mnSortCol); <br />
nRet = _tcsicmp((LPCTSTR)csTextItem1, (LPCTSTR)csTextItem2);<br />
return mbSortAscending ? nRet : -nRet; <br />
}<br />
Note that mnSortColumn and mbSortAscending are class members, mnSortColumn represents the column on which user is sorting and mbSortAscending represents if we are sorting in ascending or descending order.
There is a drawback to my approach too, item data for every single item need to be unique, if they are not then this function will not sort correctly, I personally never had a situation where I had to provide same item data for multiple items in the list control, but you never know.
Furthermore, if the programmer completely forgets to provide item data for inserted items, this approach will not work at all, so providing unique item data for items is a pre-requisite for this callback to work.
Thanks for sharing your effort with others though, it is appreciable.
/yawar
I have no signature!
|
|
|
|
|