CodeGuru
Earthweb Search
Forums Wireless Jars Gamelan Developer.com
CodeGuru Navigation
Member Sign In
User ID:
Password:
Remember Me:
Forgot Password?
Not a member?
Click here for more information and to register.

jobs.internet.com

internet.commerce
Partners & Affiliates
Memory
Home Improvement
Promotional Pens
Televisions
Logo Design
Computer Deals
Auto Insurance Quote
KVM Switches
Free Business Cards
Memory Upgrades
Calling Cards
Server Racks
Promos and Premiums
Compare Prices


RSS Feeds

RSSAll

RSSVC++/C++

RSS.NET/C#

RSSVB

See more EarthWeb Network feeds

Home >> Visual C++ / C++ >> Controls >> Rich Edit Control

Looking for ways to overcome project jams? Discover strategies for becoming a better project manager. Download Exclusive eBook Now.

Providing a Format toolbar
Rating:

Zafir Anjum (view profile)
August 6, 1998


A rich edit control without UI to change the character and paragraph formatting is not really very useful as a rich text editor. In this section we will develop code for a Format toolbar that can be used with a CRichEditView derivative. There is no hard link between the toolbar itself and the CRichEditView, so we can even use this toolbar with a sub-class of CRichEditCtrl. The only extra work would be to make sure that some of the notifications sent by the toolbar gets forwarded to the control.

There is a huge scope for improvement in the code given here, but intergrating this in your application should be fairly easy. When you feel that you need more functionality out of the Format toolbar, take a look at the WordPad sample that comes with your Visual C++ CD. This sample is the actual source code for the WordPad applet that ships with Windows. Be warned though, it takes a little time to understand the code.

Step 1: Create a toolbar control resource

The first thing we need to do is create a toolbar control resource. Actually you can create a toolbar from a bitmap but it is lot easier to work with a toolbar control. The resource editor has quite a good support for it.
(continued)



Turbo Screen Sharing
Adobe Acrobat Connect Professional offers users the ability to have a more productive and engaging web conferencing experience while providing the IT department with a program that efficiently utilizes bandwidth and minimally impacts the infrastructure. Learn More! »

Informal Learning: Extending the Impact of Enterprise Ideas and Information
Forward-thinking organizations are turning to enterprise learning in their quest to be better informed, better skilled, better supported at the point of need, and more competitive in their respective marketplaces. Learn More! »

Rapid E-Learning: Maturing Technology Brings Balance and Possibilities
Rapid e-learning addresses both time and cost issues by using technology tools to shift the dynamics of e-learning development. Learn why more skilled learning professionals use these tools and how you can get a solution to keep pace with your business demands. »

Delivering on the Promise of ELearning
This white paper defines the framework to launch e-learning as a set of teaching, training, and learning practices not bound by a specific technology platform or learning management system. It offers practical suggestions for creating digital learning experiences that engage learners by building interest and motivation and providing opportunities for active participation. »

This is what the toolbar control looks like in the resource editor. Give the toolbar control resource the ID - IDR_FORMATBAR. Actually choose any name but you should be willing to replace all occurance of IDR_FORMATBAR in the code below with the new ID.

The first two buttons are place holders for the Font Name combobox and the Font Size combobox. The other buttons are pretty obvious. Once we have the images, we should go ahead and set the properties. Besides specifying an ID for each button, we should also provide the prompt string. The prompt string is used for the help text that appears in the status bar and the tooltip text.

The 'Toolbar Button Properties' dialog is shown above for the Font Name button. The table below lists suggested IDs and prompt strings - in the same sequence they appear in the toolbar.

IDPrompt
IDC_FONTNAMEChanges the font of the selection\nFont
IDC_FONTSIZEChanges the font size of the selection\nFont Size
ID_CHAR_BOLDMakes the selection bold (toggle)\nBold
ID_CHAR_ITALICMakes the selection italics (toggle)\nItalic
ID_CHAR_UNDERLINEFormats the selection with a continuous underline (toggle)\nUnderline
ID_CHAR_COLORFormats the selection with a color\nColor
ID_PARA_LEFTLeft-justifies paragraphs\nLeft Justify
ID_PARA_CENTERCenter-justifies paragraphs\nCenter Justify
ID_PARA_RIGHTRight-justifies paragraph\nRight Justify
ID_INSERT_BULLETInserts a bullet on this line\nBullet

Step 2: Create a CFormatBar class

I used the Class Wizard to create this class. The class wizard did not have the option of specifying the CToolBar class as the base class, so I chose the CToolBarCtrl class as the base class and then in the source files, changed it to CToolBar. The advantage of using a CToolBar is that it is already hooked into the Doc-View architecture of MFC. This helps in updating the toolbar and the status bar.

The code for the CFormatBar class header file is given below. You will notice that besides declaring the CFormatBar class, it also declares CHARNMHDR struct. This is used to send custom notification messages whenever the font name or the font size changes. The FN_SETFORMAT and FN_GETFORMAT defines are the custom notification message values.

The CFormatBar constructor takes a default value which is set to IDR_FORMATBAR. This is useful only if you already have a resource with the ID IDR_FORMATBAR that you are using for some other purpose.

#if !defined(AFX_FORMATBAR_H__76705223_1E1F_11D1_830C_5CB0BB000000__INCLUDED_)
#define AFX_FORMATBAR_H__76705223_1E1F_11D1_830C_5CB0BB000000__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// FormatBar.h : header file
//



/////////////////////////////////////////////////////////////////////////////
// CFormatBar window

struct CHARNMHDR : public NMHDR
{
	CHARFORMAT cf;
	CHARNMHDR() {cf.cbSize = sizeof(CHARFORMAT);}
};

// Define format notifications constant
#define FN_SETFORMAT	0x1000
#define FN_GETFORMAT	0x1001


class CFormatBar : public CToolBar
{
// Construction
public:
	enum { IDD = IDR_FORMATBAR };
	CFormatBar(UINT nID = IDD );

// Attributes
public:

// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CFormatBar)
	public:
	virtual BOOL PreTranslateMessage(MSG* pMsg);
	//}}AFX_VIRTUAL

// Implementation
public:
	virtual ~CFormatBar();

protected:
	void FillFontName( CDC *pDC );
	virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler);


protected:
	CComboBox	m_cmbFontName;
	CComboBox	m_cmbFontSize;

	// Generated message map functions
protected:
	afx_msg void OnSelectFontName();
	afx_msg void OnSelectFontSize();

	//{{AFX_MSG(CFormatBar)
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
	//}}AFX_MSG

	DECLARE_MESSAGE_MAP()

private:
	UINT nToolbarID;
	static int CALLBACK EnumFontFamProc(ENUMLOGFONT *lpelf,
					NEWTEXTMETRIC *lpntm,
					int nFontType,
					LPARAM lParam);

};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_FORMATBAR_H__76705223_1E1F_11D1_830C_5CB0BB000000__INCLUDED_)

The code in the implementation file for CFormatBar now follows.

/////////////////////////////////////////////////////////////////////////////
// FormatBar.cpp : implementation file
//

#include "stdafx.h"
#include "RichEdit.h"
#include "FormatBar.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CFormatBar

// Declare const array of font sizes
const static int nFontSizes[] =
	{8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72};


CFormatBar::CFormatBar(UINT nID )
{
	nToolbarID = nID;
}

CFormatBar::~CFormatBar()
{
}


BEGIN_MESSAGE_MAP(CFormatBar, CToolBar)
	//{{AFX_MSG_MAP(CFormatBar)
	ON_WM_CREATE()
	//}}AFX_MSG_MAP
	ON_CBN_SELENDOK(IDC_FONTNAME, OnSelectFontName)
	ON_CBN_SELENDOK(IDC_FONTSIZE, OnSelectFontSize)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CFormatBar message handlers

int CFormatBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CToolBar::OnCreate(lpCreateStruct) == -1)
		return -1;

	// Load the toolbar
	if( !LoadToolBar( nToolbarID ) )
		return -1;


	// Get the average char width
	CClientDC dc(this);

	// Determine the size required by the font comboboxes
	// We will use the DEFAULT_GUI_FONT
	HGDIOBJ hFont = GetStockObject( DEFAULT_GUI_FONT );
	CFont font;
	font.Attach( hFont );
	dc.SelectObject( font );

	TEXTMETRIC tm;
	dc.GetTextMetrics( &tm );
	int cxChar = tm.tmAveCharWidth;
	int cyChar = tm.tmHeight + tm.tmExternalLeading;


	// Create the Font Name combo
	CRect rect;
	GetItemRect( CommandToIndex(IDC_FONTNAME), &rect );
	rect.right = rect.left + (LF_FACESIZE+4)*cxChar;
	rect.bottom = rect.top + 16*cyChar;

	SetButtonInfo( CommandToIndex(IDC_FONTNAME), IDC_FONTNAME,
				TBBS_SEPARATOR, rect.Width() );

	UINT nCreateStyle = WS_TABSTOP|WS_VISIBLE|WS_VSCROLL;
	if (!m_cmbFontName.Create(nCreateStyle|CBS_DROPDOWNLIST|CBS_SORT,
		rect, this, IDC_FONTNAME))
	{
		TRACE0("Failed to create Font Name combo-box\n");
		return -1;
	}


	// Create Font Size combo
	GetItemRect( CommandToIndex(IDC_FONTSIZE), &rect );
	rect.right = rect.left + 10*cxChar;
	rect.bottom = rect.top + 16*cyChar;

	SetButtonInfo( CommandToIndex(IDC_FONTSIZE), IDC_FONTSIZE,
				TBBS_SEPARATOR, rect.Width() );

	if (!m_cmbFontSize.Create(nCreateStyle|CBS_DROPDOWN|WS_HSCROLL,
		rect, this, IDC_FONTSIZE))
	{
		TRACE0("Failed to create Font Size combo-box\n");
		return -1;
	}
	m_cmbFontSize.LimitText(4);


	// Set the font for the combo boxes to DEFAULT_GUI_FONT
	m_cmbFontName.SetFont(&font);
	m_cmbFontSize.SetFont(&font);

	// Fill the Font names in the Font Name combo
	::EnumFontFamilies( dc.m_hDC, NULL, (FONTENUMPROC)EnumFontFamProc,
				(LPARAM) this );

	// Fill the Font Size combo
	CString sSize;
	int nSizeCount = sizeof(nFontSizes) / sizeof(nFontSizes[0]);
	for( int i=0; i < nSizeCount; i++ )
	{
		sSize.Format("%d", nFontSizes[i] );
		m_cmbFontSize.AddString( sSize );
	}

	return 0;
}

int CALLBACK CFormatBar::EnumFontFamProc(ENUMLOGFONT *lpelf, NEWTEXTMETRIC *lpntm,
					int nFontType, LPARAM lParam)
{
	CFormatBar* pWnd = (CFormatBar*)lParam;

	// Add the font name to the combo
	pWnd->m_cmbFontName.AddString(lpelf->elfLogFont.lfFaceName);

	return 1;		// 1 to continue enumeration
}

void CFormatBar::OnSelectFontName()
{
	TCHAR szFontName[LF_FACESIZE];
	int nIndex = m_cmbFontName.GetCurSel();
	m_cmbFontName.GetLBText( nIndex, szFontName );

	// If font name is empty - return
	if( szFontName[0] == 0 )
		return;

	CHARNMHDR fh;
	CHARFORMAT& cf = fh.cf;
	fh.hwndFrom = m_hWnd;
	fh.idFrom = GetDlgCtrlID();
	fh.code = FN_SETFORMAT;
	cf.dwMask = CFM_FACE;

	_tcsncpy(cf.szFaceName, szFontName, LF_FACESIZE);	//strncpy

	GetOwner()->SendMessage(WM_NOTIFY, fh.idFrom, (LPARAM)&fh);
}

void CFormatBar::OnSelectFontSize()
{
	TCHAR szSize[5];
	int index = m_cmbFontSize.GetCurSel();
	if( index != CB_ERR )
		m_cmbFontSize.GetLBText(index, szSize );
	else
		m_cmbFontSize.GetWindowText( szSize, 5 );

	// Get size in Twips
	int nSize = _ttoi( szSize ) * 20;			// atoi for tchar

	if( !nSize )
		return;

	CHARNMHDR fh;
	CHARFORMAT& cf = fh.cf;
	fh.hwndFrom = m_hWnd;
	fh.idFrom = GetDlgCtrlID();
	fh.code = FN_SETFORMAT;

	cf.dwMask = CFM_SIZE;
	cf.yHeight = nSize;

	GetOwner()->SendMessage(WM_NOTIFY, fh.idFrom, (LPARAM)&fh);
}

void CFormatBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
{
	// Take care of the regular toolbar buttons
	CToolBar::OnUpdateCmdUI( pTarget, bDisableIfNoHndler);

	// Don't update the combo boxes if user changing font attribute
	CWnd *pWnd = GetFocus();
	if( pWnd == &m_cmbFontName || m_cmbFontSize.IsChild(pWnd) )
		return;

	// get the current font from the view and update
	CHARNMHDR fh;
	CHARFORMAT& cf = fh.cf;
	fh.hwndFrom = m_hWnd;
	fh.idFrom = GetDlgCtrlID();
	fh.code = FN_GETFORMAT;

	CWnd *pOwnerWnd = GetOwner();
	if( !GetOwner()->SendMessage(WM_NOTIFY, fh.idFrom, (LPARAM)&fh) )
	{
		TRACE0("The Rich Edit View/Control has to handle the FN_GETFORMAT\n"
			"notification for the Format Bar to work properly\n");
		return;
	}

	// Update the font only if the selection font is different
	TCHAR szName[LF_FACESIZE];
	m_cmbFontName.GetWindowText( szName, LF_FACESIZE );

	// the selection must be same font and charset to display correctly
	if ((cf.dwMask & (CFM_FACE|CFM_CHARSET)) != (CFM_FACE|CFM_CHARSET))
		m_cmbFontName.SetCurSel( -1 );
	else if( ::_tcscmp( szName, cf.szFaceName ) != 0 )
	{
		if( m_cmbFontName.SelectString( -1, cf.szFaceName ) == CB_ERR )
			m_cmbFontName.SetCurSel( -1 );
	}


	// Update the font size
	TCHAR szSize[5];
	m_cmbFontSize.GetWindowText( szSize, 5 );
	int nSize = _ttoi( szSize );				// atoi for tchar

	// Update the font size only if selection is different 
	int nSelSize = (cf.dwMask & CFM_SIZE) ? cf.yHeight/20 : 0;
	if( nSize != nSelSize )
	{
		if(cf.dwMask & CFM_SIZE)
		{
			CString strSize;
			strSize.Format("%d", nSelSize );
			m_cmbFontSize.SetWindowText( strSize );
		}
		else
			m_cmbFontSize.SetCurSel(-1);
	}
}

BOOL CFormatBar::PreTranslateMessage(MSG* pMsg)
{
	if (pMsg->message == WM_KEYDOWN)
	{
		NMHDR nm;
		nm.hwndFrom = m_hWnd;
		nm.idFrom = GetDlgCtrlID();
		nm.code = NM_RETURN;
		switch (pMsg->wParam)
		{
		case VK_RETURN:
			// Send change notification
			if( m_cmbFontName.IsChild(GetFocus()) )
				OnSelectFontName();
			else if( m_cmbFontSize.IsChild(GetFocus()) )
				OnSelectFontSize();
			//Fall through
		case VK_ESCAPE:
			GetOwner()->SendMessage(WM_NOTIFY, nm.idFrom, (LPARAM)&nm);
			return TRUE;
		}
	}

	return CToolBar::PreTranslateMessage(pMsg);
}

At the top of the file, the nFontSizes array is declared. This array is initialized to the commonly used font sizes and is used to initialize the font size combobox. To make the design simple, the CFormatBar class has beed designed so that the user is always provided with this list of sizes even though the font may not support all of these sizes. The user can also type in an arbitrary value for the font size.

The OnCreate() function calls the base class version of the function so that the toolbar gets created. It then loads the toolbar from the resource and creates the two comboboxes - for font name and font size. To make place for the comboboxes, the place holder buttons are resized using the SetButtonInfo() function. We use the font that will be used in the combobox to determine a reasonable width for the control. Since a font name can have at most LF_FACESIZE characters, we use this number and the average width of a character to determine the width of the font name combobox. LF_FACESIZE by the way is a constant defined as 32. Similarly we make the font size combobox wide enough to accommodate 4 characters.

The font name combobox is created with the CBS_DROPDOWNLIST style. This style forces the user to select one of the listed styles. You may want to change this style to CBS_DROPDOWN so that the user may specify a font that may not be available on the machine. The font size combobox uses the CBS_DROPDOWN style to allow the user to type in any point size or select from the list.

At the end, the OnCreate() function populates the font size combobox by calling the EnumFontFamilies() function, which in turn calls the EnumFontFamProc() for each font on the system (the screen device context). It is EnumFontFamProc() that actually adds the font names to the combobox. OnCreate() also populates the font size combobox from the array of common font sizes.

The OnSelectFontName() is called when the user selects a list item in the font name combobox. Notice the entry ON_CBN_SELENDOK(IDC_FONTNAME, OnSelectFontName) in the message map hooking up this function. This function is also called when the user hits the enter key. The purpose of this function is to send out a notification so that the rich edit control can be updated. It uses an extended notification header so that it can also pass on the character format information. Note that it uses a custom notification code. It is the responsibility of the rich edit control class to handle this notification and change the format accordingly. Similarly, the OnSelectFontSize() handles the font size combobox.

The OnUpdateCmdUI() function is called by the framework to update the status of the toolbar. We override this function because the Format Bar has the two comboboxes. The toolbar buttons get updated by the regular ON_UPDATE_COMMAND_UI() message map macros but the combobox needs special handling. This function basically gets the font information about the current selection from the rich edit control and updates the font comboboxes. This of course doesn't make sense if the user is trying to change the font. The function, therefore returns immediately if either of the comboboxes have the input focus. Here again a custom notification is sent out. The FN_GETFORMAT should be handled by the rich edit control and the control should return the format information through the notification header structure.

Overriding the PreTranslateMessage() is how we tackle the situation when the user presses the enter or the escape key. When the user presses the enter key, it calls the OnSelectFontName() or the OnSelectFontSize() function, whichever is appropriate. The function then sends the NM_RETURN notification. This is another notification that the rich edit control has to look out for. On receiving this message, the rich edit control should take back the input focus.

Step 3: Create the Format toolbar

To create the format toolbar, first add a CFormatBar member variable in the CMainFrame class. Actually any frame class that will contain the CRichEditView or CRichEditCtrl will do.
protected:  // control bar embedded members
	CFormatBar	m_wndFormatBar;

Create the format toolbar in the OnCreate() function. Here's sample code that does that.

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
		return -1;

	if (!m_wndFormatBar.Create(this, WS_CHILD | WS_VISIBLE |
			CBRS_TOP |CBRS_TOOLTIPS|CBRS_FLYBY,
			IDR_FORMATBAR) )
	{
		TRACE0("Failed to create FormatBar\n");
		return -1;      // fail to create
	}
	m_wndFormatBar.SetWindowText( _T("Format") );
	m_wndFormatBar.EnableDocking(CBRS_ALIGN_TOP | CBRS_ALIGN_BOTTOM);
	EnableDocking(CBRS_ALIGN_ANY);
	DockControlBar( &m_wndFormatBar );

	:
	:
	:

	return 0;
}

Step 4: Add handlers for format toolbar notifications

As we have already covered, the CFormatBar sends a couple of custom notification as well as the NM_RETURN notification. These notifications inform the rich edit control about activities on the toolbar. The Class Wizard won't be able to help you add these handlers, so you would have to add the entries to the message map yourself.
BEGIN_MESSAGE_MAP(CMyRichEditView, CRichEditView)
	//{{AFX_MSG_MAP(CMyRichEditView)
	:
	:
	//}}AFX_MSG_MAP
	ON_NOTIFY(FN_GETFORMAT, IDR_FORMATBAR, OnGetCharFormat)
	ON_NOTIFY(FN_SETFORMAT, IDR_FORMATBAR, OnSetCharFormat)
	ON_NOTIFY(NM_RETURN, IDR_FORMATBAR, OnBarReturn)
END_MESSAGE_MAP()

The implementation of the handler functions are quite simple. The OnGetCharFormat() function simply gets the format of the current selection and returns this through the notification header. The OnSetCharFormat() receives the format information through the notification header and applies it to the current selection. The OnBarReturn() simply sets focus to the rich edit control.

void CMyRichEditView::OnGetCharFormat(NMHDR* pNMHDR, LRESULT* pRes)
{
	((CHARNMHDR*)pNMHDR)->cf = GetCharFormatSelection();
	*pRes = 1;
}

void CMyRichEditView::OnSetCharFormat(NMHDR* pNMHDR, LRESULT* pRes)
{
	SetCharFormat(((CHARNMHDR*)pNMHDR)->cf);
	*pRes = 1;
}

void CMyRichEditView::OnBarReturn(NMHDR*, LRESULT* )
{
	SetFocus();
}

Step 5: Add UPDATE_COMMAND_UI & COMMAND handlers

The CRichEditView class already provides support for all but one of the remaining format toolbar buttons. So all we need to do is hook up the message map entries so that the proper functions get called. The only function that we have to write is for the color button. The message map entries and the OnColorPick() function is shown below. We do not have to write the other functions since they are already defined in CRichEditView.
BEGIN_MESSAGE_MAP(CMyRichEditView, CRichEditView)
	//{{AFX_MSG_MAP(CMyRichEditView)
	:
	:
	ON_COMMAND(ID_CHAR_COLOR, OnColorPick)
	ON_COMMAND(ID_CHAR_BOLD, OnCharBold)
	ON_UPDATE_COMMAND_UI(ID_CHAR_BOLD, OnUpdateCharBold)
	ON_COMMAND(ID_CHAR_ITALIC, OnCharItalic)
	ON_UPDATE_COMMAND_UI(ID_CHAR_ITALIC, OnUpdateCharItalic)
	ON_COMMAND(ID_CHAR_UNDERLINE, OnCharUnderline)
	ON_UPDATE_COMMAND_UI(ID_CHAR_UNDERLINE, OnUpdateCharUnderline)
	ON_COMMAND(ID_PARA_CENTER, OnParaCenter)
	ON_UPDATE_COMMAND_UI(ID_PARA_CENTER, OnUpdateParaCenter)
	ON_COMMAND(ID_PARA_LEFT, OnParaLeft)
	ON_UPDATE_COMMAND_UI(ID_PARA_LEFT, OnUpdateParaLeft)
	ON_COMMAND(ID_PARA_RIGHT, OnParaRight)
	ON_UPDATE_COMMAND_UI(ID_PARA_RIGHT, OnUpdateParaRight)
	ON_COMMAND(ID_INSERT_BULLET, OnBullet)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


void CMyRichEditView::OnColorPick()
{
	CColorDialog dlg;

	if( dlg.DoModal() == IDOK ){
		CRichEditView::OnColorPick(dlg.GetColor());
	}
}

Tools:
Add www.codeguru.com to your favorites
Add www.codeguru.com to your browser search box
IE 7 | Firefox 2.0 | Firefox 1.5.x
Receive news via our XML/RSS feed

Improve How You Manage Information: Becoming a Better Project Manager. Exclusive eBook - Download Now.
Generate Complete .NET Web Apps in Minutes . Download Iron Speed Designer today.
Best Practices for Developing a Web Site. Checklists, Tips & Strategies. Download Exclusive eBook Now.
Becoming a Better Project Manager. Checklists, Tips & Strategies. Download Exclusive eBook Now.
Is it time to make your move to the multi-threaded and parallel processing world? Find out!


RATE THIS ARTICLE:   Excellent  Very Good  Average  Below Average  Poor  

(You must be signed in to rank an article. Not a member? Click here to register)

Latest Comments:
About the Font Families Combo box - Legacy CodeGuru (08/19/2003)
Expanded combobox buttons hide other buttons beneath it - Legacy CodeGuru (07/07/2003)
A solution for VC++.NET - Legacy CodeGuru (02/23/2003)
How to change text direction - Legacy CodeGuru (03/04/2002)
How to insert an OLE object into a CRichEditCtrl - Legacy CodeGuru (11/13/2001)

View All Comments
Add a Comment:
Title:
Comment:
Pre-Formatted: Check this if you want the text to display with the formatting as typed (good for source code)



(You must be signed in to comment on an article. Not a member? Click here to register)


JupiterOnlineMedia

internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

Jupitermedia Corporate Info


Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers