たいちうです。また質問させてください。
Win2000 VC++6.0 SP5 MFC SDI で開発しています。
MSFlexGridを使って横向きの棒グラフのようなものを作成したいのですが、
どのような方法が良いのでしょうか?
まず、MSFlexGrid のセルにビットマップを貼り付ける方法ですが、
これではセルをまたがった図形を表示できません。
棒グラフ程度なら、矩形を分割して各セルに貼り付けられますが、
より複雑な図形の描画・消去が大変そうです。
次に、CStaticをMSFlexGridに重ねて描画しようかとも思ったのですが、
図形の更新のタイミングがつかめません。
グリッドの作成時やスクロールなどでは、CViewのPreTranslateMessageで、
WM_PAINTを捕らえられませんでした。
MSFlexGridを使わなくても構いません。
どなたか楽な方法を教えていただけないでしょうか?
このままでは、ビットマップを分割するか、スクロールするグリッドを
1から作るかの、2つの手段を検討することになりそうです。
楽をするためにFlexGridを考えたのでしょうか?
CViewでの図形の描画は入門書にたくさん書いてありますので、こちらを勉強したほうがよいの
と思います
CViewでの描画はOnDrawをオーバライドします。
WM_PAINTはメッセージマップで受け取ります。
チュートリアルをきちんと勉強するほうが近道と感じます。
汎さま
回答有難うございます。
ですが、私のしたい事がうまく伝えられなかったようです。
> 楽をするためにFlexGridを考えたのでしょうか?
そうです。グリッドを表示させたり、スクロールさせたりを自分でコーディングするのが
面倒だった為、MSFlexGridの上にグラフを描画させようとしました。
ちなみにMSFlexGridはCViewの上に動的に作成しています。
コントロールの上に描画をさせたい為、CView::OnDrawで描いてはグラフの上に
MSFlexGridを上書きされてしまいます。CButtonの上に書くような場合には、CButtonを
継承させたクラスのPreTranslateMessageでWM_PAINTを捕まえる事が出来たのですが、
MSFlexGridでは、これを継承させたクラスでも、貼り付けたCViewでもWM_PAINTを
捕まえる事が出来ませんでした。少なくともこの方法ではActiveXの場合、
出来ないんだと思います。
その後も色々試しましたが、MSFlexGridをサブクラス化して、スクロールの場合も含めて
WM_PAINTを拾う事が出来ました。MFCとSDKの混じったコードになりましたが、
なんとかなりそうです。
実際に描画してスクロールにも成功したら、また報告させてもらいます。
なんとか解決しました。
わざわざ載せるまでもないかもしれませんが、
CViewにMSFlexGridを表示させる方法と、サブクラス化する方法を書いておきます。
WNDPROC OldProc;
void *pGrid;
LRESULT CALLBACK NewProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT ret = OldProc(hwnd, message, wParam, lParam);
if (message == WM_PAINT)
((CMyView*)pGrid)->DrawGraph();
return ret;
}
void CMyView::OnInitialUpdate()
{
CView::OnInitialUpdate();
m_grid.Create(grid, WS_CHILD | WS_VISIBLE,
CRect(0, 0, 0, 0), this, IDC_GRID_GANTT);
OldProc = (WNDPROC)::SetWindowLong(m_grid.m_hWnd, GWL_WNDPROC,
(LONG)NewProc);
pGrid = this;
}
void CMyView::DrawGraph()
{
// ここに描画
}
この他、CMyView::OnSize()も処理しています。
結局、スクロールに合わせた描画をする必要があったので、MSFlexGridを使う
メリットは小さかったかもしれません。
返事がおくれて申し訳ありません。
解決されてなによりです。
一般にグリッドコントロールはこのコントロールの機能を使うために使用します。
今回はグリッドコントロールの機能は使わないように受け取りましたので、
それならViewに直接描画するなり
Viewの上に子ウィンドウを生成して描画すなりするほうが
簡単だと思ったまででした。
ちなみにMFCのサブクラス化は
CWnd::SubclassWindow(); 関数
サブクラス化の解除は
CWnd::UnsubclassWindow(); 関数を使用します。
汎さま
> ちなみにMFCのサブクラス化は
> CWnd::SubclassWindow(); 関数
> サブクラス化の解除は
> CWnd::UnsubclassWindow(); 関数を使用します。
この方法も試してみましたが、ActiveXコントロールの場合にはできないようです。
サブクラス化しようとすると、MFC内部のASSERTに引っかかります。
BOOL CWnd::Attach(HWND hWndNew)
{
ASSERT(m_hWnd == NULL); // only attach once, detach on destroy
ASSERT(FromHandlePermanent(hWndNew) == NULL);
...
}
ここの、FromHandle...がNULLになってくれません。
一般のコントロールの場合では成功しましたので、手順は正しいと思うのですが、
この辺りは私の理解を超えているため、諦めざるを得ませんでした。
> 一般にグリッドコントロールはこのコントロールの機能を使うために使用します。
> 今回はグリッドコントロールの機能は使わないように受け取りましたので、
> それならViewに直接描画するなり
> Viewの上に子ウィンドウを生成して描画すなりするほうが
> 簡単だと思ったまででした。
部分的にはグリッドの機能も使います。
ですが、グラフ描画の他にもMSFlexGridがサポートしていない機能を色々実装
しなければなりませんので、「Viewの上に子ウィンドウを生成して描画」の方が
良いのかもしれません。
まあ、しばらくはこのまま作り続けてみます。ありがとうございました。
なるほど そういった動作があったのですね
別の意味で興味深かったのでソースを組んで確認してみました。
ラッパ関数でそのまま処理するにはCreate関数を以下のように、
BOOL CMSFlexGrid::Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT&
rect, CWnd* pParentWnd,
UINT nID, CFile* pPersist, BOOL bStorage,
BSTR bstrLicKey)
{
BOOL bRtn = CreateControl(GetClsid(), lpszWindowName, dwStyle, rect,
pParentWnd, nID, pPersist, bStorage, bstrLicKey);
m_pOldProc = (WNDPROC)GetWindowLong(GetSafeHwnd(),GWL_WNDPROC) ;
m_hWnd = Detach() ;
SubclassWindow(m_hWnd);
return bRtn ;
}
一旦ハンドルをデタッチしてからSubclassWindowを発行すれば
メッセージマップが使用できるようになります。
あとはたいちうさんと同じで
void CMSFlexGrid::OnPaint()
{
m_pOldProc(m_hWnd, WM_PAINT, 0, 0) ;
描画処理
}
ですね。
ただ、これでアクティブコントロールがほんとに正しく動作するかは
確認していません。
「ActiveX コントロールってこんなふうに使うもの?」という気持ちもあります。
これだけ苦労するなら自分でグリッドコントロールを作るなり
VS-FlexGridを使うほうが楽ではないでしょうか?
よけいな一言が多いので気分を害されていたら失礼しました。
汎さま
> ラッパ関数でそのまま処理するにはCreate関数を以下のように、
...
...
少し試しましたが、同じASSERTIONが出てしまいます。
いずれまた挑戦して見ます。
> 「ActiveX コントロールってこんなふうに使うもの?」という気持ちもあります。
> これだけ苦労するなら自分でグリッドコントロールを作るなり
> VS-FlexGridを使うほうが楽ではないでしょうか?
そうですね。貼り付けただけで使いたいのが本音です。
スクロール時のグラフの座標計算なども面倒だったので、
グリッドごと作るのも変わらないかもしれません。
今回だいぶ苦労した分、勉強になりました。
> よけいな一言が多いので気分を害されていたら失礼しました。
いえいえ。ありがとうございました。