Der GULP IT-Projektmarktindex misst seit 1998 kontinuierlich die über den GULP Server zugestellten Projektangebote. Der daraus gewonnene Index ist ein idealer Gradmesser für die Angebots- und Nachfragesituation am IT-Projektmarkt.

Link: GULP IT-Projektmarktindex: Der Gradmesser für die Angebots- und Nachfragesituation am IT.

Möchte man im Hauptmenü einer MFC-basierten Anwendung einen Menübefehl mit einem gesetzten “Häkchen” versehen, so gibt es verschiedene Möglichkeiten, dies zu tun. In diesem Zusammenhang habe ich bereits des Öfteren Code der folgenden Art gefunden:

// ---------------------------------------------
// Klasse.h
// ---------------------------------------------
class CKlasse : public CWnd
{
public:
	...
	afx_msg void OnBefehl( void );
	...
	DECLARE_MESSAGE_MAP()
};

// ---------------------------------------------
// Klasse.cpp
// ---------------------------------------------

BEGIN_MESSAGE_MAP
	ON_COMMAND( ID_BEFEHL, OnBefehl )
END_MESSAGE_MAP

void CKlasse::OnBefehl(void)
{
	// Ist das Häkchen vor dem Menübefehl gesetzt?
	UINT oldstate, checkstate;
	HMENU hMenu = AfxGetMainWnd()->GetMenu()->GetSafeHmenu();
	oldstate = ::GetMenuState( hMenu, ID_BEFEHL, MF_BYCOMMAND );
	checkstate = oldstate;
	checkstate &= MF_CHECKED;
	if ( checkstate == MF_CHECKED )
	{	// Das Häkchen ist gesetzt. Entferne das Häkchen nun.
		oldstate = 0;
		::CheckMenuItem( hMenu, ID_BEFEHL, oldstate );

		...
	}
	else
	{	// Das Häkchen ist nicht gesetzt. Setze es
		oldstate ^= MF_CHECKED;
		::CheckMenuItem ( hMenu, ID_BEFEHL, oldstate);

		...
	}
}

Das ist grundsätzlich nicht falsch und funktioniert ja auch. Insgesamt bietet die MFC dafür aber einen deutlich eleganteren Mechanismus, den ich nachfolgend mal kurz beschreiben möchte.

Möglichkeiten der MFC

Die MFC bietet für die einleitend beschriebene Problemstellung einen Mechanismus an, der mit Hilfe der Message-Map-Makros folgendermaßen implementiert werden kann:

// ---------------------------------------------
// KlasseNeu.h
// ---------------------------------------------
class CKlasseNeu : public CWnd
{
	BOOL m_bBefehlIsChecked;
public:
	...
	afx_msg void OnBefehl( void );
	afx_msg void OnUpdateBefehl( void );
	...
	DECLARE_MESSAGE_MAP()
}; 

// ---------------------------------------------
// KlasseNeu.cpp
// ---------------------------------------------

BEGIN_MESSAGE_MAP(CKlasseNeu, CWnd)
	ON_COMMAND( ID_BEFEHL, OnBefehl )
	ON_UPDATE_COMMAND_UI( ID_BEFEHL, OnUpdateBefehl )
END_MESSAGE_MAP()

void CKlasseNeu::OnBefehl(void)
{
	m_bBefehlIsChecked = !m_bBefehlIsChecked;

	if( m_bBefehlIsChecked )
	{
		...
	}
 	else
 	{
 		...
 	}
}

void CKlasseNeu::OnUpdateBefehl( CCmdUI* pCmdUI )
{
	pCmdUI->SetCheck( m_bBefehlIsChecked );
}

Das ist – wie man sehen kann – nicht nur viel einfacher zu lesen, sondern vom Coding her auch wesentlich eleganter, da man auf diese Weise gar nicht direkt auf die UI-Elemente zugreifen muss.

Weitere Möglichkeiten der MFC

Der Command- und Update-Mechachnismus bietet aber noch weitere Möglichkeiten. Zum Beispiel kann man mit dem ON_UPDATE_COMMAND_UI eine einzige Methode für mehrerer Update-Aktionen verwenden. Dies hat den Vorteil, dass die man die Klassendefinitionen in vielen Fällen stark reduzieren kann, weil man nicht mehr so viele Methoden benötigt. Beispiel:

// ---------------------------------------------
// KlasseNeu.cpp
// ---------------------------------------------

BEGIN_MESSAGE_MAP( CKlasseNeu, CWnd )
	ON_UPDATE_COMMAND_UI( ID_BEFEHL1, OnUpdateMenu )
	ON_UPDATE_COMMAND_UI( ID_BEFEHL2, OnUpdateMenu )
	ON_UPDATE_COMMAND_UI( ID_BEFEHL3, OnUpdateMenu )
END_MESSAGE_MAP()

void CKlasse::OnUpdateBefehl( CCmdUI* pCmdUI )
{
	switch( pCmdUI->m_nID )
	{
		case ID_BEFEHL1:
			pCmdUI->Enable( ... )
			pCmdUI->SetCheck( ... )
			break;
		case ID_BEFEHL2:
			pCmdUI->Enable( ... )
			...
			break;
		case ID_BEFEHL3:
			...
			break;
		default:
			// Unbekannter Befehl
			break;
	}
}

Es sollte auch berücksichtigt werden, dass in einem ON_UPDATE_COMMAND_UI-Handler nicht zu komplexe und berechnungsintensive Aktionen verwendet werden, da diese Handler sehr häufig aufgerufen werden.

In Analogie zum ON_UPDATE_COMMAND_UI-Handler gibt es auch einen ähnlich aufgebauten ON_COMMAND-Handler mit dem Namen ON_COMMAND_EX, der z.B. so eingesetzt werden kann:

ON_COMMAND_EX( ID_BEFEHL1, OnBefehl );
ON_COMMAND_EX( ID_BEFEHL2, OnBefehl );
ON_COMMAND_EX( ID_BEFEHL3, OnBefehl );

Mit der Methode

afx_msg BOOL OnBefehl( UINT nCmdUI );

kann man dann vollkommen analog zu den ON_UPDATE_COMMAND_UI-Methoden das hier machen:

BOOL CKlasseNeu::OnBefehl( UINT nCmdUI )
{
	switch( nCmdUI )
	{
		case ID_BEFEHL1:
			...
			break;
		case ID_BEFEHL2:
			...
			break;
		case ID_BEFEHL3:
			...
			break;
		default:
			// Unbekannter Befehl
			break;
	}
}

Insbesondere bei sehr übersichtlichen und miteinander verwandten Befehlen (z.B. Befehle aus dem Datei-Menü etc.), bietet sich eine solche Implementierung durchaus an.