「プログラミング」カテゴリーアーカイブ

カスタムカラーダイアログ

たまにはVC++ネタ。

コモンコントロールのカラーダイアログは、テンプレートとフックプロシージャでその振る舞いをカスタマイズできますが、そのテンプレートの使い方のサンプルです。というのも、ファイル選択ダイアログのようにカスタマイズ部分のテンプレートを作ればよいのかと思ったら、全部作らなければいけないのを知らなかったので…。

上図のように、標準のカラーダイアログにWEBでよく使われるカラーコード(ただの16進表記ですね)を表示・編集するエディットボックスを追加するサンプルをWTLで作ってみました。

まずダイアログリソースはWindows SDKのインクルードフォルダにあるColor.Dlgファイルからコピーします。ソリューションエクスプローラーからプロジェクトのリソースファイルを右クリックして、「コードの編集」で開いたら「Dialog」のところに貼り付けてカラーコード用のエディットボックスを追加します。

こんな感じです。

DLG_COLOR DIALOGEX 2, 0, 331, 184
STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CONTEXTHELP | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "色の設定"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
    LTEXT           "基本色(&B):",IDC_STATIC,4,4,140,9
    CONTROL         "",COLOR_BOX1,"Static",SS_SIMPLE | WS_GROUP | WS_TABSTOP,4,14,140,86
    LTEXT           "作成した色(&C):",IDC_STATIC,4,106,140,9
    CONTROL         "",COLOR_CUSTOM1,"Static",SS_SIMPLE | WS_GROUP | WS_TABSTOP,4,116,140,28
    PUSHBUTTON      "色の作成(&D) >>",COLOR_MIX,4,150,140,14,WS_GROUP
    DEFPUSHBUTTON   "OK",IDOK,4,166,44,14,WS_GROUP
    PUSHBUTTON      "キャンセル",IDCANCEL,52,166,44,14,WS_GROUP
    PUSHBUTTON      "ヘルプ(&H)",1038,100,166,44,14,WS_GROUP
    CONTROL         "",COLOR_RAINBOW,"Static",SS_SIMPLE | SS_SUNKEN,152,4,150,116
    CONTROL         "",COLOR_LUMSCROLL,"Static",SS_SIMPLE | SS_SUNKEN,310,4,8,116
    CONTROL         "",COLOR_CURRENT,"Static",SS_SIMPLE | SS_SUNKEN,152,124,52,15
    PUSHBUTTON      "&o",COLOR_SOLID,300,200,6,14,WS_GROUP
    RTEXT           "色",COLOR_SOLID_LEFT,153,141,13,9
    LTEXT           "| 純色(&O)",COLOR_SOLID_RIGHT,169,141,35,9
    RTEXT           "色合い(&E):",COLOR_HUEACCEL,204,126,49,9
    EDITTEXT        COLOR_HUE,257,124,18,12,WS_GROUP
    RTEXT           "鮮やかさ(&S):",COLOR_SATACCEL,204,140,49,9
    EDITTEXT        COLOR_SAT,257,138,18,12,WS_GROUP
    RTEXT           "明るさ(&L):",COLOR_LUMACCEL,204,154,49,9
    EDITTEXT        COLOR_LUM,257,152,18,12,WS_GROUP
    RTEXT           "赤(&R):",COLOR_REDACCEL,279,126,24,9
    EDITTEXT        COLOR_RED,306,124,18,12,WS_GROUP
    RTEXT           "緑(&G):",COLOR_GREENACCEL,279,140,24,9
    EDITTEXT        COLOR_GREEN,306,138,18,12,WS_GROUP
    RTEXT           "青(&U):",COLOR_BLUEACCEL,279,154,24,9
    EDITTEXT        COLOR_BLUE,306,152,18,12,WS_GROUP
    PUSHBUTTON      "色の追加(&A)",COLOR_ADD,152,166,172,14,WS_GROUP
    EDITTEXT        COLOR_HEX,164,152,40,12,ES_AUTOHSCROLL
    RTEXT           "#",IDC_STATIC,152,154,9,8
END

これだけだとColor.DlgからコピーしたリソースIDが定義されていないので、リソースファイル内とメインのcppファイルでSDKにあるColorDlg.hをインクルードします。

WTLにはCColorDialogがありますが、これと同じようにCColorDialogImplから派生してCCustomColorDialogを作成することにしましょう。EN_CHANGEでHSLまたはRGBのエディットボックスの内容が変化したことを検知して、カラーコード用のエディットボックスの内容を更新します。またカラーコード用のエディットボックスが更新されて6桁入力された時には、_GetSetRGBMessage() によって取得した SETRGBSTRING メッセージを送信することで選択色を更新します。

#pragma once

#include <atldlgs.h>

class CCustomColorDialog : public CColorDialogImpl<CCustomColorDialog>
{
public:
	CCustomColorDialog(COLORREF clrInit = 0, DWORD dwFlags = 0, HWND hWndParent = NULL)
		: CColorDialogImpl<CCustomColorDialog>(clrInit, dwFlags, hWndParent)
	{
		m_cc.Flags |= CC_ENABLETEMPLATE;
		m_cc.lpTemplateName = MAKEINTRESOURCE(DLG_COLOR);
		m_cc.hInstance = (HWND)_Module.m_hInst;
	}
	// override base class map and references to handlers
	BEGIN_MSG_MAP(CCustomColorDialog)
		MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
		COMMAND_CODE_HANDLER(EN_CHANGE, OnEnChange)
		CHAIN_MSG_MAP(CColorDialogImpl<CCustomColorDialog>)
	END_MSG_MAP()

// Handler prototypes (uncomment arguments if needed):
//	LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
//	LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
//	LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)

	LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		CenterWindow(GetParent());

		// HexEditに初期値を設定
		SendMessage(_GetSetRGBMessage(), 0, (LPARAM)m_cc.rgbResult);
		return TRUE;
	}

	LRESULT OnEnChange(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& /*bHandled*/)
	{
		CString strR, strG, strB, strHex;
		static bool bIgnoreHexUpdate=false;
		switch (wID)
		{
		case COLOR_HUE:
		case COLOR_SAT:
		case COLOR_LUM:
		case COLOR_RED:
		case COLOR_GREEN:
		case COLOR_BLUE:
			if (!bIgnoreHexUpdate)
			{
				GetDlgItemText(COLOR_RED, strR);
				GetDlgItemText(COLOR_GREEN, strG);
				GetDlgItemText(COLOR_BLUE, strB);
				strHex.Format(_T("%02x%02x%02x"), _ttol(strR), _ttol(strG), _ttol(strB));
				bIgnoreHexUpdate = true;
				SetDlgItemText(COLOR_HEX, strHex);
				bIgnoreHexUpdate = false;
			}
			break;
		case COLOR_HEX:
			if (!bIgnoreHexUpdate)
			{
				GetDlgItemText(COLOR_HEX, strHex);
				if (strHex.GetLength() != 6)
					break;
				strR = strHex.Mid(0, 2);
				strG = strHex.Mid(2, 2);
				strB = strHex.Mid(4, 2);
				strHex = _T("0x") + strB + strG + strR;
				LPTSTR lpszEnd=NULL;
				errno = 0;
				int lValue = _tcstol(strHex, &lpszEnd, 0);
				if (errno == ERANGE)
					return false;
				bIgnoreHexUpdate = true;
				SendMessage(_GetSetRGBMessage(), 0, (LPARAM)lValue);
				bIgnoreHexUpdate = false;
			}
			else
			{
				bIgnoreHexUpdate = false;
			}
			break;
		}
		return DefWindowProc();
	}
};

あとはサンプルプロジェクトを見れば分かると思います。

CustomColorSample (VS2010)

VS2005でメソッドやプロパティを追加するときに出るスクリプトエラー

VisualStudio2005の、ソリューションエクスプローラやクラスビューで右クリックして「メソッドの追加」や「プロパティの追加」を選択すると、何やらスクリプトエラーが出てウィザードがまともに動かないのは IE8 との組み合わせだからだそうです。

http://blogs.msdn.com/fmo_jp/archive/2009/04/02/visual-studio-2005-visual-studio-2008.aspx

対処方法は、HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\に「1000」という名前のキーを作成し、その中に「1207」という名前のDWORD値を「0」を設定して作成すればOK。

Visual Studio でのビルド番号更新

Visual Studio で開発するときに、ビルド番号を自動更新するためのスクリプトを作ってみました。

IncBuildNumber.vbs は最初にパラメータで指定された .rc ファイルのバックアップを作成します。(*.rc.bak)その後 .rc ファイルから文字列 FILEVERSION, PRODUCTVERSION, FileVersion, ProductVersion がある行を探し、その行に記載されているビルド番号を1増やします。

ビルド番号更新スクリプト(IncBuildNumber.vbs)
(ダウンロードしたら最初に右クリックのプロパティ画面から「ブロックの解除」を行って下さい)

このスクリプトをどこか適当な場所において、プロジェクトプロパティでReleaseのビルド前のイベントに以下の設定を行うと使用できます。以下の例では Visual Studio のインストールフォルダ $(VCInstallDir) に置いてあります。

CScript “$(VCInstallDir)IncBuildNumber.vbs” “$(ProjectDir)$(ProjectName).rc”

—-

2010/12/07 追記:リソース内にversionという文字列があった場合に誤動作していたので、多少誤動作しないように改善しておきました。

Visual C++ 2008 Feature Pack

最近MFCを使っていなかったので、Visual C++ 2008 Feature Packなんてものがあるのを知りませんでした。

Visual Studio 2008 はまだ買っていませんが、これでOffice2007風・Office2003風・VS2005風のUIが標準で簡単に作成できるのならちょっと欲しくなります。というか、こういうものがないからわざわざ WTL で色々なコントロールを探してきて作っていたのですが、その必要がなくなるわけですからね。

サンプル画面などは以下のページに。
http://msdn.microsoft.com/ja-jp/magazine/cc507634.aspx
http://codezine.jp/a/article/aid/2516.aspx?p=2

WTLでVS2005風メニュー

最近は C# で作ると最初から Office2003 風のメニューやツールバーになりますが、VC++/WTL だと Classic なメニューしかできません。ちょっと悔しいので Viksoe さんの WTL XP UI のメニューとツールバーだけをいじって VS2005 風にしてみました。

なんだか CustomDraw が思った通りに動かなくて、ちょっといい加減につくってあります。

ソースファイルのダウンロード

 

DirectX プログラミング

例えば沢山のオブジェクトを描画したくて DrawPrimitive の頂点バッファを作るとき、その頂点バッファをどうやって作るのが正しいのかということについて。

[方法1]
DrawPrimitive で描画する単位で CreateVertexBuffer を使って頂点バッファを作成しておく。(配列とかリストにしておく)
それを順番に DrawPrimitive で描画していく。

[方法2]
一回だけ CreateVertexBuffer を使って全てのオブジェクトの頂点バッファを作成しておく。
それを StartVertex でオフセットを指定して DrawPrimitive で順番に描画していく。

最初は StartVertex を指定するのが面倒くさいと思って 1 の方法でコーディングしていたのですが、オブジェクトの数が何十万とかになってくると CreateVertexBuffer が E_OUTOFMEMORY を返すようになってきました。

で、2の方法に変更すると問題なく動くのでやっぱり正しいのは2なんでしょうね。

一人でプログラミングしていると、誰にも聞けないのでやたらと時間がかかるときがあります。最初は「E_OUTOFMEMORYというのなら幾つまでなら作れるのか?」という視点で調べて、全く情報がないことに途方にくれていました。そのうちに書き方が違うのではないかということに気付いたのですが、それでも「正しい書き方」についての情報も見つけることはできませんでした。きっと知っている人には低レベルの問題だったのでしょうけど。

Vista対応

なんとか Vista 用のマシンを準備して、色々動作テストをしています。

Delphi 6 で作ったアプリケーションで、フォームに空の TImageList を貼り付けているものが動作しませんでした。フォームから TImageList を取り除き、フォームのコンストラクタで作成するようにすれば動くようです。TImageList の Width や Height が0のままでもダメですね。

その他文字の高さは DrawText などで取得しないと正しく描画できません。例えば12ポイントの文字を描画する際、今までは描画位置の計算に高さとしてそのまま「12」を使用しても問題ありませんでしたが、Vista では DrawText で実際に描画される高さを取得しないとうまくいきません。

古い開発環境を使っていると面倒臭いですね。

VS2005

一昨日から VS2005 を使い始めてみています。なんだか VS2003 に比べて不安定な感じがするのですが、みんなそうなんでしょうか。それとも VC++&WTL7.5という組み合わせが悪いのでしょうか。何度も何度も落ちるので使うのをやめたくなりますね。

ちなみに見た目の雰囲気は VS2003 の OfficeXP 風のフラットな感じのメニューの方が好きです。

もしかして買って損したのかも。