[an error occurred while processing this directive]
[an error occurred while processing this directive]#pragma once class CMyWindow : public CWindowImpldcが描画オブジェクトで、これに対してフォントとか色とか線の色とか太さとかを指定します。{ public: DECLARE_WND_CLASS(_T("Hello")); private: BEGIN_MSG_MAP_EX(CMyWindow) MSG_WM_PAINT(OnPaint) END_MSG_MAP() void OnPaint(HDC /*hDC*/){ PAINTSTRUCT ps; HDC hDC = BeginPaint(&ps); RECT rect; GetClientRect(&rect); DrawText(hDC, _T("Hello, ATL/WTL"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); EndPaint(&ps); } };
BEGIN_MSG_MAP_EX(CMyWindow) MSG_WM_PAINT(hoge) END_MSG_MAP()と(publicなとこに)書く。見て分かるようにこれはマクロで、一度展開されて正しいCのプログラムになり、その後コンパイルされる。ここではhogeの引数や返り値はさっぱり分からないけど、引数は描画関数としてふさわしく書かれていないといけない。WM_PAINTの場合は引数は(HDC)と書くらしい。あと、hogeでは何の関数か一見して分からないから、普通はOnPaintという名前を使う習慣である。
void OnPaint(HDC /*hDC*/){ CPaintDC dc(m_hWnd); CRect r; PAINTSTRUCT ps; dc.DrawText(_T("Kei"), -1, &r, DT_CENTER | DT_VCENTER); EndPaint(&ps); }とすればよい。
CFont font; font.CreatePointFont(200, _T("Arial Black")); dc.SetTextColor(RGB(0, 0, 0)); HFONT oldFont = dc.SelectFont(font); dc.SelectFont(hOldFont);oldFontは使いたかったら後で使える。
dc.DrawText(_T("Kei"), -1, &r_kei, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_CALCRECT );という風にDT_CALCRECTを追加しておくと、r_kei(元々の描画領域を指定していた長方形)に実際に文字列が描画されるサイズが代入される。例えば下のコードを実行すると、真ん中に描画される"Kei"という文字列の幅と、下からの位置が表示される。
void OnPaint(HDC /*hDC*/){ CPaintDC dc(m_hWnd); CRect r_all, r_kei; PAINTSTRUCT ps; GetClientRect(r_kei); dc.DrawText(_T("Kei"), -1, &r_kei, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_CALCRECT ); GetClientRect(r_all); dc.DrawText(_T("Kei"), -1, &r_all, DT_SINGLELINE | DT_CENTER | DT_VCENTER); char buf[256]; sprintf(buf, "btm : %d, rgh : %d", r_kei.bottom, r_kei.right); GetClientRect(r_all); dc.DrawText(_T(buf), -1, &r_all, DT_SINGLELINE | DT_LEFT | DT_TOP ); dc.DrawText(_T(buf), -1, &r_all, DT_SINGLELINE | DT_LEFT | DT_TOP ); EndPaint(&ps); }
MoveWindow(0, 0, 500, 500);のように使う。
BOOL ShowWindow(int nCmdShow) throw() { ATLASSERT(::IsWindow(m_hWnd)); return ::ShowWindow(m_hWnd, nCmdShow); }、色々いじっているといつの間にか動くようになった。 でもどこをなおしたのか不明…
class CMainDlg : public CDialogImplのように設定する。enumで定数を設定するのはC++では定石らしい。{ public: enum { IDD = IDD_DIALOG1 }; ...
BEGIN_MSG_MAP_EX(CMainDlg) COMMAND_ID_HANDLER_EX(IDOK, hoge) END_MSG_MAP()と書く。さっきの描画と異なるのは、イベントが起こったコントロール(ボタンのこと)のIDを明示しないといけない点。 hoge()は以下のように書く。
void hoge(UINT uNotifyCode, int nID, HWND hWndCtl){ ... }
Button button = new Button();みたいに書いてあって、buttonのメソッドを呼び出すことで色んな事(ラベルを変えるとか、色を変えるとか、非アクティブにするとか)ができる(気がする。) しかし、今まで書いてきた方法では、ボタンはIDしか分かっていなくて、ボタンの属性をどうやって変えるのか不明である。
CWnd *cwnd = GetDlgItem( IDC_BUTTON1 );のような感じ。 GetDlgItemで取得出来るのはウィンドウを表す"CWndへの"参照であって、ボタンを表す"CButtonへの"参照ではない。 しかし、そのIDがボタンであることが分かっていれば、(CButton *)というキャストをすることでCButtonとして用いることができる。
CButton btn = GetDlgItem( IDOK );みたいな感じ。
CWindow btn = GetDlgItem( IDOK ); btn.MoveWindow(100, 100, 100, 100);みたいに。
m_hDialogBrush = CreateSolidBrush(RGB(0, 0, 255)); ...みたいに。
LRESULT OnCtlColorDlg(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ return (long) m_hDialogBrush; }
MESSAGE_HANDLER(WM_CTLCOLORDLG, OnCtlColorDlg)を追加。
//(コンストラクタ内にて) // m_hDialogBrush = CreateSolidBrush(RGB(255, 255, 255)); LOGBRUSH logBrush; logBrush.lbStyle = BS_NULL; m_hDialogBrush = CreateBrushIndirect(&logBrush);これで、背景の再描画がされなくなる。
CFont font; font.CreatePointFont(20, _T("Arial")); ... font.CreatePointFont(12, _T("Arial")); ...そしたら、ATLで展開された部分のAssertで落ちる。
ATLASSERT(m_hFont == NULL)CreatePointFontは二度呼び出してはいけないらしい。 一々new()とdelete()を繰り返すことにして解決したけど、 多分Destroyなんとかっていうメソッドを呼び出してもいいと思う。
CFont *font = new CFont(); font->CreatePointFont(20, _T("Arial")); ... delete(font); font = new CFont(); font->CreatePointFont(12, _T("Arial")); ...
#define _ATL_APARTMENT_THREADED #define _ATL_NO_AUTOMATIC_NAMESPACE #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS #include <atlbase.h> #include <atlcom.h> #include <atlapp.h> #include <atlwin.h> #include <atlcrack.h> #include <atlmisc.h> #include <atlctrls.h> ...このdefineをうっかり#includeの後にしてしまうと、謎なエラー(デッドロックの可能性? )が出た。
0x8001010D: アプリケーションが入力同期呼び出しをディスパッチしているため、呼び出せません。。これの解説はここにあるけど、明示的にSendMessageなんて呼んだ覚えがないから焦りました。
void OnPaint(HDC /*hDC*/){ CPaintDC dc(m_hWnd); CBrush brush; brush.CreateSolidBrush(RGB(0,0,0)); CRect screen; GetClientRect(screen); dc.FillRect(screen, brush); }とするとよい。
void OnPaint(HDC /*hDC*/){ CPaintDC dc(m_hWnd); myFillBlack(dc); } void myFillBlack(CPaintDC& dc){ ... }