Link to home
Start Free TrialLog in
Avatar of gurly
gurly

asked on

Changing a CComboBox style to CBS_SORT

Hi,

I'm trying to change the style of a CComboBox after it has been created.
I want to add & remove the CBS_SORT style.
I use the following code:
m_oCombo.ModifyStyleEx(0, CBS_SORT);
and
m_oCombo.ModifyStyleEx(CBS_SORT, 0);
But none of these lines seems to work.
Is the CBS_SORT style unchangeable after the combo has been created ?

If not, I guess I will have to implement an owner-draw combo-box, and override the CompareItem method.
Does anyone have an example of a DrawItem function for a regular combo-box ?

Thanks for your help.
Avatar of fl0yd
fl0yd

A few things that need clarification:

* Use
m_oCombo.ModifyStyle( 0, CBS_SORT );
to add the CBS_SORT style. It's not an extended style so don't use ModifyStyleEx
* I'm not sure whether this newly set style yields an  immediate response or if it applies only if you add new strings to the combobox.
* You are confusing owner-drawn controls with a derived class. Owner-drawn controls give you the ability to do the drawing of the items yourself. Deriving your own class inherits the entire functionality from the parent and gives you the opportunity to customize every single aspect without changing the rest. So this is what you are looking for, when you want to only change the CompareItem-method.
Avatar of gurly

ASKER

A. You are right about the ModifyStyleEx. I also tried it with ModifyStyle and it didn't work (just didn't notice I haven't changed it back when I put the sample code here).

B. I change the style right after I call ResetContent and just before I fill the combo-box with new strings, and still - it doesn't work.

C. I know the difference between owner-drawn controls and derived classes. The fact is that in order to override the CompareItem method I have to derive my own class from CComboBox and change the control style to owner-drawn.
c.)

Where does it say so? The MSDN states that you have to implement CompareItem if you have an owner drawn combo-box. It doesn't say that you have to make it owner-drawn to override the CWnd::OnCompareItem-function.
Avatar of gurly

ASKER

But if the control is not owner-drawn the CompareItem method is never called.
That's why I was referring to OnCompareItem...
Avatar of gurly

ASKER

Still - the OnCompareItem is also not called if the control is not owner-drawn.
From MSDN:
"The system sends the WM_COMPAREITEM message to determine the relative position of a new item in the sorted list of an owner-drawn combo box or list box. "
ASKER CERTIFIED SOLUTION
Avatar of fl0yd
fl0yd

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of gurly

ASKER

Thanks for the link.
By now I implemented something similar myself.
I have one problem, though.
The lpDrawItemStruct->itemData doesn't hold the item text in case I called SetItemData for that item.
I don't want my item data to be a complicated struct holding the item text along with other data I need.
I just need to hold a number with the item.

Any ideas on how I can get the item text in the DrawItem & CompareItem functions ?
Hi!
CBS_SORT is the creation time style that is style that control use only during self creation and changing such styles after creation will not change control mode.
IMHO you need destroy existing control and recreate it again with needed style.
That's certainly not the way you want to go, migel. Deriving a class from CComcoBox, adding a private

BOOL m_bSort;

and a public member function

BOOL SetSort( BOOL b = TRUE ) { BOOL tmp = m_bSort; m_bSort = b; return tmp; }

will be clearly superior. In your CompareItem()-function add the following line at the very beginning:

if( !m_bSort )
    return;

This is definately a lot better concerning memory footprint, memory fragmentation and, possibly most important, runtime performance. Thinks about all those objects that have to be destroyed and recreated...
but for using CompareItem you have to use OWNERDRAW combo isn`t you?
And what is the big deal about it?
This methods called only when new item added into the combobox.
so if you will use your technique then you anyway will erase all elements and readd they again
This methods called only when new item added into the combobox.
so if you will use your technique then you anyway will erase all elements and readd they again
This methods called only when new item added into the combobox.
so if you will use your technique then you anyway will erase all elements and readd they again
Even if that were the case then at least the entire window isn't destroyed. Think about how your suggestion will flicker... I doubt, that there is the need to re-insert the items though. An InvalidateRect( NULL, FALSE ); should be sufficient.
Avatar of gurly

ASKER

I understand I will have to use an owner-drawn combo-box.
The only question left is:
How can I get the item text in the DrawItem / CopareItem methods, when the item is an actual DWORD set with SetItemData ?
did you try it by hand??
Avatar of gurly

ASKER

I understand I will have to use an owner-drawn combo-box.
The only question left is:
How can I get the item text in the DrawItem / CopareItem methods, when the item is an actual DWORD set with SetItemData ?
Avatar of gurly

ASKER

migel,
What do you mean ?
Since you called SetItemData, you would know what the DWORD_PTR points to.
Avatar of gurly

ASKER

fl0yd,
You are correct, but as I said earlier, I don't want to save the item text in the data structure.
The DWORD_PTR is extra data for me, not an item identifier.
oops my prefious post is for fl0yd
1. Is your combo created with CBS_HASSTRINGS?
if  with than you can use CComboBox::GetLBText(id);
2 or you can use itemData member of the DRAWITEMSTRUCT passed into the DrawItem this member hold data you pass in the SetItemData call

void CMyComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{

   LPCTSTR lpszText = (LPCTSTR) lpDrawItemStruct->itemData;
// rest of code
}
gurly,
    I assume that itemData points to the actual data you have some means to evaluate the string from there. If you don't want the combobox to store the string for you (which I think is a good choice) it is somewhere stored in the structure/class that itemData points to.
Avatar of gurly

ASKER

migel,

1. LPCTSTR lpszText = (LPCTSTR) lpDrawItemStruct->itemData;
want get me the item text since it holds the item data.

2. When my combo has the style CBS_HASSTRINGS the CompareItem function is not called.
so you need define struct (as fl0yd) that hodls both item string and item data and store pointers to the structs in the item data
you have no another choose
Avatar of gurly

ASKER

fl0yd,
I'm not sure I understand what you mean: how can the combo store the string for me ? Is it by the structure the item data points to (which I don't want to add the string to) ?
Or are you talking about something else ?
If you call CComboBox::AddString( LPCTSTR ), then the control stores the string for you. You can delete the c-string that you supplied for this function call after it returned since the control made a copy of it. I'm not sure, how you would get that string when doing the drawing. You will find information on that either from the link I provided above or you will have to look through this section in the msdn.
Avatar of gurly

ASKER

Thanks for your help.