Click here to Skip to main content
Email Password   helpLost your password?

Sample Image - HistoryCombo_demo.jpg

Introduction

The History Combo class CHistoryCombo is based on CComboBox, and includes support for keeping item history, including reading from and saving to the registry. It can also be used to display the contents of an existing CRecentFileList object.

How to use it

Using the CHistoryCombo class is very straightforward. Follow the steps below to add one to an existing project:

  1. After putting the source files (HistoryCombo.cpp and HistoryCombo.h) into the directory you wish to use them from, add the files to your Visual Studio project.
  2. In the resource editor, add a combo where you wish.
  3. In Class Wizard, add a member variable for your combo control, selecting "Control" from the "Category" list, and selecting "CHistoryCombo" from the "Variable Type" list. (If CHistoryCombo does not appear in the list, you may need to delete your class wizard file (.clw) and regenerate it). I will assume your control variable name is m_comboHistory.
  4. Add a handler for WM_INITDIALOG in your dialog class if you don't already have one, and add the following code to it:
    m_comboHistory.LoadHistory("Settings", "HistoryCombo");

    (Note: you can specify any string you wish for the section, and key-prefix.)

  5. In your handler for the IDOK button, or wherever you choose, add the following:
    m_comboHistory.SaveHistory();

That's all you need to do.

Serialization, and using a string for storage

For examples on how to use the CArchive support, and the loading and saving from and to a string, see the demo program.

Documentation

Each function is documented in the CPP file, but here is a list of functions in CHistoryCombo:

CHistoryCombo(BOOL bAllowSortStyle = FALSE);
CString LoadHistory(LPCTSTR lpszSection, LPCTSTR lpszKeyPrefix, 
    BOOL bSaveRestoreLastCurrent = TRUE, LPCTSTR lpszKeyCurItem = NULL);
CString LoadHistory(CRecentFileList* pListMRU, BOOL bSelectMostRecent = TRUE);
void SaveHistory(BOOL bAddCurrentItemtoHistory = TRUE);
virtual void Serialize(CArchive& ar);
void SaveHistory(CArchive& ar, BOOL bAddCurrentItemtoHistory = TRUE);
void LoadHistory(CArchive& ar);
CArchive& operator<<(CArchive& ar, CHistoryCombo& ob);
CArchive& operator>>(CArchive& ar, CHistoryCombo& ob);
CString SaveHistoryToText(CString& sHistory, BOOL bAddCurrentItemToHistory = 
    TRUE, LPCTSTR lpszDelims = _T("\r\n"));
void LoadHistoryFromText(LPCTSTR lpszHistory, LPCTSTR lpszLastSelected = NULL,
    LPCTSTR lpszDelims = _T("\r\n"));
int AddString(LPCTSTR lpszString);
void SetMaxHistoryItems(int nMaxItems);
void ClearHistory(BOOL bDeleteRegistryEntries = TRUE);
void StoreValue(BOOL bIgnoreIfEmpty = TRUE);
void SetAutoComplete(BOOL bAutoComplete = TRUE);
BOOL GetAutoComplete();
static void SetAutoCompleteDefault(BOOL bAutoComplete = TRUE);
static BOOL GetAutoCompleteDefault()

History

Version 3.1 - 20 Apr 2007

Version 3.0 - 22 Jun 2004

Version 2.1 - 09 Jul 2003

Version 2 - 01 May 2002

Version 1 - 12 Apr 2001

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralQuestion
Piccinano
2:01 14 Mar '10  
Where the data of the ComboBox are saved in the registry?
GeneralI need help
sebilkullan
23:18 16 Dec '09  
Hi,

Your work is great. Also, can you help me?

I have created an custom combobox. I have derived it from CWND. In clasical combobox, it is possible to hide the dropdown listbox when user clicks on the dialog(not on a control). Normally, I put the hiding code, killfocus message of the listbox. Clicking any control it hides itself. But when clicking on the dialog, there happend noting since the dialog does not get the focus.

Short, I want to let the dropping listbox disappear when I click on dialog asif I click on any control.
Do you have any idea?
GeneralThanks
ranu_hai
1:10 25 Feb '08  
It was helpfull ......


was looking out for something like this
GeneralExcellent!
Steve_Harris
5:13 7 Nov '06  
Nice one. To make it even better I've added in the autocompletion code from Chris Maunder's CComboCompletion class. Smile

The next task will be to save and load the list of entries via SQL... Frown


GeneralRe: Excellent!
Paul S. Vickery
5:51 20 Apr '07  
Thanks for the compliment. It's a bit late for you now, but I've just uploaded an update which includes Chris Maunder's auto-completion code, as well as making it compilable in VS2003/2005.

If you add SQL support, be sure to tell me! Wink



"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)

GeneralGood,but...
Fzz
17:01 11 Oct '05  
It's really a good combobox, but a little pity.

The author used CString to store all history, but If I want to delete what I have add to list, so it's hard to do.

Maybe a CArray or CList is pretty to store the history, it's easy to addList, deletelist!!Blush

Benny fun
AnswerRe: Good,but...
Paul S. Vickery
5:32 17 Oct '05  
I think you've misunderstood the implementation and usage of my control.

I don't store the history in a CString. The history is simply the text stored in the combo's items.

In essence, apart from the extra functions to load and store the history, it behaves exactly like any other combo-box, so to add items you can use AddString, InsertString etc, and to delete items you can use the normal DeleteString function.

The class uses a new version of AddString to make sure that items are always stored in reverse order to that in which they are added. There is also a StoreHistory function which takes the current edit control contents and adds it to the list (as the top-most item).

In trying to allow flexibility, I have made it such that you can populate the combo from the user's profile, a CRecentFileList or an archive. You can save the history to any of these three also, or to a CString for you to store as you wish.

I agree that it would be useful to load/store from/to a CArray/CList, and I may consider adding that to a future update.



"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
GeneralRe: Good,but...
Fzz
3:52 21 Oct '05  
Hi,thanks for you kindly reply.

I want to implement the function such as: when I dropdown the list, and press DEL key, so it'll delete the highlighted item. Would you give me some advice?

Benny fun
GeneralUNICODE support? test engine won't let you cut/paste greek into combobox
Michael Shiels
16:57 8 Feb '05  
I would have expected that to work no?
Generalmore than one comboBox in the same dialog?
m3t3ora
21:07 11 Aug '03  
hi ther!

is it possible to implement more than 1 history comboboxes in the same dialog?Confused
if yes, please show me how to do so? thank you very much for your time n effort!Smile Rose

GeneralHow to get CHistoryCombo object in toolbar in CMainFrame?
kydfru
22:49 22 Jun '03  
I tried the folowing code:
[code]
// CDialogBar m_wndSearchBar;
// create m_wndSearchBar, pass to ReBar::AddBar, etc ...
CHistoryCombo *m_pcomboSearchQuery = (CHistoryCombo *)m_wndSearchBar.GetDlgItem(IDC_COMBO_SEARCH_QUERY);
m_pcomboSearchQuery->LoadHistory("Settings", "SearchQueryHistory");
[/code]
The last string cause assertion in CString code.
So I think I acually get CComboBox pointer not CHistoryCombo.
Is there any way to get a CHistoryCombo pointer?
I know that I can constuct CHistoryCombo directly and then pass to CReBar::AddBar()
but is I think to build all toolbars from dialog resources is more good code style.
GeneralRe: How to get CHistoryCombo object in toolbar in CMainFrame?
Paul S. Vickery
0:18 23 Jun '03  
If your dialog bar does not have the combo explicitly declared (and subclassed) as a CHistoryCombo then it will not be one. In fact GetDlgItem() will probably return it as a CTempWnd*. You can find out by adding a line of code like:
	TRACE("Combo class = %s\n", m_pcomboSearchQuery->GetRuntimeClass()->m_lpszClassName);
To get it to be a CHistoryCombo you will at some point need to subclass it to one. You could either create your own class derived from CDialogBar and a member variable to it like:
	CHistoryCombo m_combo
and then override the OnCreate in your class and do something like:
	m_combo.SubclassDlgItem(IDC_COMBO_SEARCH_QUERY, this);
or, you could avoid having your own CDialogBar-derived class by handling it in the main frame, by adding the CHistoryCombo member to the CMainFrame class, and sometime after creating the dialog-bar do something like:
	m_combo.SubclassDlgItem(IDC_COMBO_SEARCH_QUERY, &m_wndSearchBar);
Once you have done one of the above, you can then use m_combo to access the combo as a CHistoryCombo.

(The example in the MSDN documentation for CWnd::SubclassDlgItem shows something similar to this)


"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
GeneralThank you very much for your class and for your help!
kydfru
0:37 23 Jun '03  
I did use the last your example with SubclassDlgItem.
Its works well.
Thank you again!
GeneralA Bug? It cann't show large text in edit box!
Zhongzhu
4:17 14 Apr '03  
Hi,I found that your CHistoryCombo control has some problem:When the text in the edit box of the combobox is large, the more text exceed the edit box width doesn't appear at all. Can you tell me why? Is it a bug?Cry

liuzz
GeneralRe: A Bug? It cann't show large text in edit box!
Paul S. Vickery
7:00 14 Apr '03  
To allow text to be entered in the edit box of a combo that is longer than the width of the combo the CBS_AUTOHSCROLL must be used on the combo box. This is the case for all combo boxes. (My demo doesn't have this style and so text will be limited to the combo's width.)


---
"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
GeneralThanks a lot!
Zhongzhu
16:32 14 Apr '03  
The problem has been solved. Thanks you!;P

liuzz
GeneralRe: A Bug? It cann't show large text in edit box!
no_reg_name
0:25 30 Jun '04  
Is it be possible to scroll the text on the right automatically?

For example if you have long paths (e.g. D:\Program Files\Microsoft Visual Studio .NET 2003\CompactFrameworkSDK\ConnectionManager\Bin) while 'navigating' to it, would be much more useful to show the right hand side of the text (e.g. ...\CompactFrameworkSDK\ConnectionManager\Bin), rather than left part (e.g. D:\Program Files\Microsoft Visual Studio .NET 2003\...).

Can your class do this?
GeneralRe: A Bug? It cann't show large text in edit box!
Paul S. Vickery
1:58 2 Jul '04  
The standard combo box does this when you click on the item, or select it from the drop-list. My class is no different in this respect.



"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
GeneralRe: A Bug? It cann't show large text in edit box!
no_reg_name
0:39 5 Jul '04  
Right, ok.

I was thinking more, when the drop-down is actually showing, before making the selection, the text to be moved on the right, so the right hand side of the text will be visible.

However since then the only soultion I could find was to have an owner-drawn list box, unless you have any other ideas?

Thanks.
GeneralSerializing a ComboBox
EPulse
22:55 26 Aug '02  
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...
GeneralRe: Serializing a ComboBox
Paul S. Vickery
1:01 28 Aug '02  
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)
GeneralRe: Serializing a ComboBox
EPulse
1:38 28 Aug '02  
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...




GeneralRe: Serializing a ComboBox
Paul S. Vickery
2:35 28 Aug '02  
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)
GeneralRe: Serializing a ComboBox
EPulse
0:12 3 Sep '02  

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.

GeneralRe: Serializing a ComboBox
Paul S. Vickery
23:38 23 Jun '04  
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)


Last Updated 20 Apr 2007 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010