MFCでCSOButtonを使う

 

これが正解かどうかは不明です。pieCKに入れ込んであります。

ここでは、プロジェクト作成から説明してみます。

まず、AppWizardで 「WCE MFC AppWizard」を選択します。

お手頃なCFormViewを使うことにします。プロジェクトを作って雛型を作成してください。

最初に、CMainFrameのOnCreateからメニューやツールバーの記述を
削除してしまいます。

一度コンパイルしてエラーがないことを確認してください。

私の環境でCFormViewを使ってDEBUGモードでコンパイルするとリンクエラーが出るので、
無理やり以下の記述を Stdafx.cppに書き込みました。特に問題は起きませんので大丈夫
かと思います。Releaseモードでコンパイルするとエラーになりません。
#ifdef _DEBUGを忘れずに!

#include "stdafx.h"
#ifdef _DEBUG
void CScrollView::OnPrepareDC(class CDC *pDC,void const *pUnused)
{
	CView::OnPrepareDC(pDC, pUnused);
}
#endif

それからデバッガを動かす時にメモリ不足になってファイルCOPYできないと言われたら
SetMemDiv(ExeRepllogが入っている場所(SDK CD-ROM)に入っています)を起動し
てメモリの割当を変更してね。2MB位あれば大丈夫かな?


以下の2つのファイルを新規に作ります。

MYCSO.H

 
#ifndef __MYCSO_H__
#define __MYCSO_H__
#include 
class CCsoExStyle 
{
public: //初期化が面倒なので、クラスにしてみました。デフォルトが使えるのは便利でしょ。
	CSO_EXSTYLE m_exs;
	CCsoExStyle()
	{
		m_exs.BtnID = 0;
		m_exs.FaceColor = CLR_INVALID;
		m_exs.TextColor = CLR_INVALID;
		m_exs.TransparentColor = CLR_INVALID;
		m_exs.Bold = FALSE;
		m_exs.Italic = FALSE;
	};
	~CCsoExStyle(){};
	void SetButtonID(DWORD dwID)
	{
		m_exs.BtnID = dwID;
	}
	operator CSO_EXSTYLE *() // SetCSOExStyleを呼び出すためのキャスト用
	{
		return &m_exs;
	}
};

class CCsoButton : public CButton
{
protected:
	CMenu *m_pMenu;
public:
	CCsoButton();
	~CCsoButton();
	void SetFocusMode(bool bFocus);
	bool GetFocusMode();
	void SetMenu(int nIDR_MENU, int nSubMenuPos, DWORD style);
	void SetCSOExStyle(CSO_EXSTYLE * pExStyle);
	//他にもいくつか機能があったような=自分で作ってください。
};
#endif

MYCSO.CPP

#include "stdafx.h"
#include "mfccso.h"
static bool bMFCCSO_Initialized = false;

//コンストラクタでInitCSOButtonを1回だけ呼び出していますが、OnInitInstanceの方が確実なのかも?
CCsoButton::CCsoButton()
{
	if (!bMFCCSO_Initialized)
		InitCSOButton(AfxGetApp()->m_hInstance);
	bMFCCSO_Initialized = true;
	m_pMenu = NULL;
} 
CCsoButton::~CCsoButton()
{
	if (m_pMenu)
		delete m_pMenu;
}

void CCsoButton::SetFocusMode(bool bFocus)
{
	SendMessage(CSO_BM_SETFOCUSMODE, (WPARAM)(bFocus ? TRUE: FALSE), 0);
}
bool CCsoButton::GetFocusMode()
{
	return SendMessage(CSO_BM_GETFOCUSMODE, 0, 0) ? true : false;
}
void CCsoButton::SetMenu(int nIDR_MENU, int nSubMenuPos,  DWORD style)
{
	if (m_pMenu)
		delete m_pMenu;
	m_pMenu = new CMenu;
	m_pMenu->LoadMenu(nIDR_MENU);
	CString strA;
	m_pMenu->GetMenuString(nMenuPos, strA, MF_BYPOSITION); //メニュータイトルをボタンタイトルにする
	SetWindowText(strA);
	CMenu *pSubMenu = m_pMenu->GetSubMenu(nMenuPos); //サブメニューをCSOButtonに入れる
	this->SendMessage(CSO_BM_SETMENU,
		(WPARAM)(pSubMenu->m_hMenu),
		(LPARAM)(style));
}
void CCsoButton::SetCSOExStyle(CSO_EXSTYLE * pExStyle)
{
	SendMessage(CSO_BM_SETEXSTYLE,
		0,
		(LPARAM)pExStyle); //単に呼び出しているだけです。
}

これらを自分のプロジェクトに含めます。


次に、ダイアログ(IDD_xxxxxxx_FORM) を編集します。

CSOButtonとしたい位置にプッシュボタンを配置します。メニュー用以外のボタンの
押された時のハンドラを作ります。(ダイアログエディタで該当ボタンをダブルクリック
すると出来るCFormViewのメソッドです。)

次に、各ボタンの変数をクラスウィザードで作ります。

CxxxxViewにボタン変数が定義されているので、このCButton m_xxxxxを
CCsoButtonと変更します。以下のような感じになります。

	//{{AFX_DATA(CTestCSOBARView)
	enum { IDD = IDD_TESTCSOBAR_FORM };
	CCsoButton	m_btnHelp;
	CCsoButton	m_btnEdit;
	CCsoButton	m_btnFile;
	CCsoButton	m_btnEND;
	//}}AFX_DATA

 

CxxxxViewにCxxxViewクラス定義の前の位置に上記 MYCSO.Hをインクルードします。

ダイアログエディタに戻ります。

定義したボタン(IDを忘れないで下さいね)を削除します。

ユーザ定義コントロール「」を削除したボタンの位置にそれぞれ作成します。この時の
IDは先ほど削除したボタンのIDをつけます。クラス名に"CSOButton"と入れます。
ボタン表示でなくなりますけど気にしないで下さい。


次に使いたいメニューを作ります。

IDR_MAINFRAMEでも良いのですが、CSOButtonがハンドリングしてくれるのは、
CMainFrameでは無く、CxxxxViewにメッセージを投げてしまいます。IDR_MAINFRAME
のID_FILE_XXXX群はCMainFrameに投げなければならないものですので、このままでは
使えません。基本的に新しくメニューを定義してください。そのメニューをCxxxxxViewに
クラスウィザードで割り当てておきます。

メニューのタイトル(開かないで表示される文字)がCSOButtonの表示文字になるように
CCsoButtonのSetMenuで操作しています。また、メニューはIDR_MAINFRAMEのように
複数のサブメニューを持っていても構いません。サブメニュー番号を指定できます。

ファイル=サブメニュー番号 0、編集=サブメニュー番号 1、ヘルプ=サブメニュー番号 2 です。

 

CxxxxViewのOnInitialUpdateにて

void CTestCSOBARView::OnInitialUpdate() 
{
	CFormView::OnInitialUpdate();
	CCsoExStyle EX;
	EX.SetButtonID(CSO_ID_CLOSE);
	m_btnEND.SetCSOExStyle(EX); // これは終了ボタンとしました。
	EX.SetButtonID(0);
	m_btnEdit.SetCSOExStyle(EX); //これらはメニュー用ボタンです。
	m_btnFile.SetCSOExStyle(EX);
	m_btnHelp.SetCSOExStyle(EX);
	m_btnFile.SetMenu(IDR_VIEWMENU, 0, POPUPMENU_DOWN); //ここではViewMenuのサブメニューを左端が0として設定します。
	m_btnEdit.SetMenu(IDR_VIEWMENU, 1, POPUPMENU_DOWN);
	m_btnHelp.SetMenu(IDR_VIEWMENU, 2, POPUPMENU_DOWN);
}

ボタンPushのハンドラ(Onxxxx)に必要な処理を記述します。

これでOKです。

リンクエラーが出る場合は CSO.LIBをリンクしてください。

以上です。

実行結果については責任を負えませんので、自己解決してください。

私は面倒くさがりなので、CSOButtonを使っていません。PocketPCなどに簡単に移植できなく
なるのは困りますので、CSOButtonを使う気になりません。=pieCKには入れてみました。
(入れた感想:んー少しはラジェンダのソフトみたいになりました==終了ボタン)

ここで公開したソースコードは勝手に変更して使ってください。もっと良い手段があれば、
メールで知らせてください。

CSOツールバーはインプリメントする気にならないのでやめました。MFCのツールバーを
使っても同じようなことができますので、特に必要ないんじゃないかと、、、CToolBarから
派生して内部にCSOツールバーを持つようにすれば作れるとは思うけど、面倒なので
考えていません。

上記について私になにか言いたいという方は掲示板に投稿してください。

2002年1月26日  担当:大久保