|
Is it possible to have the same functionality here using serialization? I mean deriving a class from CComboBox and implementing serialization for the ComboBox elements. I tried to do this but my serialize() function doesn't get called and CObject's get called instead. Although, the IMPLEMENT_SERIAL() and DECLARE_SERIAL() were there.
Can any one tell my why, thanx...
|
|
|
|
|
It would help if you could post some of your code (or email it to me) so I can see how you're trying to do it. Are you using the >>/<< operators, or Serialize(ar), or ReadObject/WriteObject? I would have thought that the simplest way is to either have a CHistoryCombo::Serialize() function, and call it directly, or to have overrides of LoadHistory/SaveHistory that take a CArchive&.
---
"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
|
|
|
|
|
Hello Paul,
This is how i wrote the CSerialComboBox:
///////////////////////////////////////////
class CSerialComboBox : public CComboBox
{
DECLARE_SERIAL(CSerialComboBox)
// Construction
public:
CSerialComboBox();
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSerialComboBox)
//}}AFX_VIRTUAL
// Implementation
public:
void Serialize(CArchive& ar);
virtual ~CSerialComboBox();
// Generated message map functions
protected:
//{{AFX_MSG(CSerialComboBox)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
// SerialComboBox.cpp : implementation file
//
#include "stdafx.h"
#include "logFilter.h"
#include "SerialComboBox.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_SERIAL(CSerialComboBox, CComboBox, VERSIONABLE_SCHEMA )
/////////////////////////////////////////////////////////////////////////////
// CSerialComboBox
CSerialComboBox::CSerialComboBox()
{
}
CSerialComboBox::~CSerialComboBox()
{
}
void CSerialComboBox::Serialize(CArchive &ar)
{
CComboBox::Serialize(ar);
CString strTemp;
int nCount = CComboBox::GetCount();
if(ar.IsStoring())
{
for (int i=0; i <= nCount; i++)
{
CComboBox::GetLBText( i, (char*) LPCTSTR(strTemp));
ar << strTemp;
}
}
else {
}
}
BEGIN_MESSAGE_MAP(CSerialComboBox, CComboBox)
//{{AFX_MSG_MAP(CSerialComboBox)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
and here how it is used in my dialog class:
void CMainDialog::OnExit()
{
CFile fSerial;
CFileException fileEx;
// fSerial.Open("presist.mus",CFile::Read
if (!fSerial.Open("presist.mus",
CFile::modeCreate | CFile::modeWrite, &fileEx))
{
PrintFileException(fileEx.m_cause);
TRACE( "File Exception: Can't creat presistance file");
exit(2); //Can't creat output file
}
CArchive arcSerial(&fSerial,CArchive::store);
CSerialComboBox *FileNames, *FilterCriteria;
FileNames = (CSerialComboBox*) GetDlgItem(IDC_FILENAME);
FilterCriteria = (CSerialComboBox*) GetDlgItem(IDC_CRITERIA);
//FileNames->Serialize(fserial);
FilterCriteria->Serialize(arcSerial);
exit(0);
}
the problem is that the Serialize() in CSerialComboBox class doesn't get called and the one in CObject which only returns. One more thing, the visual studio recognizes the CSerialComboBox but when i want to go to the funtion definitions it says that they are not defined. what might be the reason for that...
Thanx alot for your help,
Bye...
|
|
|
|
|
The main problem isn't with the serialization. It is this:
FilterCriteria = (CSerialComboBox*) GetDlgItem(IDC_CRITERIA); You can't simply cast a CWnd* to a CSerialComboBox* . Whatever you cast it to it's still really a CWnd* . If you break in a debugger after the line above, and look at what it says FilterCriteria is, it will tell you it's a CTempWnd* .
You need to subclass the control to a CSerialComboBox to be able to use it as that. This is normally done by setting up a member variable mapping using the ClassWizard. This subclasses the window handle.
When you call the MFC GetDlgItem() , the function first gets the HWND for the control, and then it looks it up to find the CWnd* it is currently mapped to (see documentation for CWnd::FromHandle ). In your case it's not mapped to anything so you get a CTempWnd object. The function then always returns it as a CWnd* .
If you had already subclassed it to a CSerialComboBox , then the pointer returned would be a CSerialComboBox* (albeit upcast to a CWnd* ), and the debugger would show it as that. (Using something like DYNAMIC_DOWNCAST can help with making sure you have the correct cast.)
So, to fix your problem, map the control to a CSerialComboBox .
As for the functions not being found, I assume you mean in the ClassView. The best remedy for this is to delete your workspace's ncb file. You will need to close the workspace first.
Perhaps I could make a suggestion about your Serialize() function. When serializing a list of items where the number of items is dynamic, it s a good idea to store the number of items first, then store each item in a loop. Then, on loading, you will then first read the number of items, then you know how many times to loop and read the actual items.
I hope this helps!
---
"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
|
|
|
|
|
hi Paul,
Your are right about that, I gotta subclass my combobox for it to work.
Thanx alot for your advice and happy coding..
MM.
|
|
|
|
|
I have now posted an update which includes serialising to and from a CArchive object.
"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
|
|
|
|
|
Doing MFC for years, I feel like a totally beginner now:
Also I get the notifications (CBN_XXX), when I select a history from the droplist, every time I query the edit control-part of the combobox for the current text (via GetWindowText) in response to such a CBN_XXX notification, it returns me the content of the edit control, as it was BEFORE the entry from the history droplist was selected.
I'm still investigating, but I don't know, whether it's related to your class or to combobox in general.
Any suggestions?
--
See me: www.magerquark.de
|
|
|
|
|
While in the handlers for the CBN_XXX notifications, the window text has not yet been updated. Therefore any call to GetWindowText() will only ever return the 'old' text. To get the newly selected text you must use:
CString sText;
int nIndex = combo.GetCurSel();
if (nIndex >= 0)
combo.GetLBText(nIndex, sText);
The only exceptions to this are for the CBN_EDITCHANGE and CBN_EDITUPDATE notifications, where you should use GetWindowText(), and not GetLBText().
(This is not related to my class; it is the same for comboboxes in general.)
---
"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
|
|
|
|
|
|
I would suggest to overload the functions LoadHistory and SaveHistory to be able to load/save from a string in memory, which in turn enables me to store the history in a database field.
Maybe I'll add it and post it here?!
--
See me: www.magerquark.de
|
|
|
|
|
It would be good if you could post it here. I will be updating the downloads soon with a fix for SetMaxHistoryItems, so it would be good to include your change also.
---
"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
|
|
|
|
|
I have posted an update which includes save to/load from a string.
"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
|
|
|
|
|
|
Hi,
Your control is very cool but the SetMaxHistory doesn't work in my code.
I set a value of 5 items, but the list is always growing over five items ??
In your example you don't use this function, how to use it ?
Thanks a lot
Regards
Olivier
Help yourself and codeproject will help you
|
|
|
|
|
The SetMaxHistory and other associated bits of code didn't work . I have posted an update to the article, with new downloads, which fixes this, so hopefully it will be updated soon .
---
"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
|
|
|
|
|
Thanks a lot, SetMaxHistory is working very well now.;)
Help yourself and codeproject will help you
|
|
|
|
|
i using combo box in sdi appln but when i used ur class CComboxEx instead of CComboBox it is not working any specific reason
Thahnks
Rajesh
|
|
|
|
|
You haven't said in what way it isn't working, but deriving from CComboBoxEx instead of CComboBox will give you problems. This is because CComboBoxEx is not a drop-in replacement for CComboBox.
The methods commonly used in CComboBox (AddString etc) just don't exist in CComboBoxEx. In fact, if you try and send the appropriate messages (eg CB_ADDSTRING) it will cause an MFC "Not-implemented" exception.
What features are you looking for in CComboBoxEx that you don't get from CComboBox? Perhaps you (or someone else) could create a new CComboBox-derived class to add the feature(s) you are looking for. I have done this in order to have case-sensitivity in a CComboBox (see my Case-sensitive ComboBox article).
---
"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
|
|
|
|
|
I think the data exchange can be done simpler with the help of the DoDataExchange function. I did the data exchange by adding the following lines to the DoDataExchange function:
if(pDX->m_bSaveAndValidate)
m_comboHistory.SaveHistory();
else
m_comboHistory.LoadHistory("Settings", "HistoryCombo");
Regards,
Patrick
|
|
|
|
|
Yes indeed you could use the DoDataExchange mechanism in this way. My only concern would be that the history is then loaded or saved every time UpdateData is called.
So, if in your OnOK handler, you call UpdateData(TRUE), do some validation, then don't allow the dialog to be closed, the history has already been saved, even if the user already presses cancel.
Also, conversely, if you wish to update any controls by member variables mapped to them, it is likely you will call UpdateData(FALSE), in which case the history in the combo will be reset to the history in the registry.
If you do it this way and it works for your usage of the control, then all well and good.
|
|
|
|
|
Nice. But I'm curious why ClearHistory() takes a bool arg.
"There is always one more bug..."
http://www.ravib.com
ravib@ravib.com
|
|
|
|
|
The comment and definition for ClearHistory() is:
<font color="green">
<font color="blue">void</font> <font color="black">CHistoryCombo::ClearHistory(BOOL bDeleteRegistryEntries</font><font color="green"></font><font color="black">)</font>
ClearHistory() takes a single BOOL argument which, if TRUE, causes the registry entries where the history is stored to be deleted. If FALSE, or the combo is using CRecentFileList instead of having the registry keys supplied, then no attempt is made to delete the registry entries and the function simply clears the combo list (CComboBox::ResetContent()).
As you can see by the fact that the BOOL arg is by default TRUE, it is usual to delete the registry entries when clearing the history.
There is usually no need to delete the registry entries when using CRecentFileList as CRecentFileList::WriteList() clears the whole section and re-writes it. ClearHistory() could be made to do this if CHistoryCombo was to cache the pointer to the CRecentFileList used to populate the list, and then remove all its items, and the write the list.
|
|
|
|
|
I should learn to read. Thanks,
/ravi
"There is always one more bug..."
http://www.ravib.com
ravib@ravib.com
|
|
|
|
|
Does this have any new features that aren't in my own combobox MRU class? (http://www.codeproject.com/combobox/mrucombo.asp)
--Mike--
http://home.inreach.com/mdunn/
The Signature, back by popular demand: Buffy. Pajamas.
|
|
|
|
|
Not sure, but one restriction that you noted in your article is requirement that the strings be valid filenames. I was looking for a history combo that doesn't need or have anything to do with MRU files--just one less change I have to make.
|
|
|
|