FlexGridをSDIで使う方法を教えてください – プログラミング – Home

FlexGridをSDIで使う方法を教...
 
通知
すべてクリア

[解決済] FlexGridをSDIで使う方法を教えてください


kkawa
 kkawa
(@kkawa)
ゲスト
結合: 15年前
投稿: 10
Topic starter  

WIN98SE VC++6.0 MFC SDI で CListCtrlを貼付けていたのをFlexGridに入替てみたのですが
うまくいきません。以前このコーナーの質疑回答にありましたコードを参考にやってみましたが
CALLBACK関数のWM_PAINTが無限ループになっているような状態?です。宜しくお願いします。

//CTestView.h
void DrawGraph();
CMSFlexGrid m_myGrid;

//CTestView.cpp
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)
((CTestView*)pGrid)->DrawGraph();
return ret;
}

int CTestView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CTabView::OnCreate(lpCreateStruct) == -1)
return -1;
CRect rect;
GetDisplayRect( &rect);
m_myGrid.Create(grid, WS_CHILD | WS_VISIBLE, rect, this, 1);
OldProc = (WNDPROC)::SetWindowLong(m_myGrid.m_hWnd, GWL_WNDPROC,
(LONG)NewProc);
pGrid = this;
GetTabCtrl().InsertItem( 0, _T(ABC) );
return 0;
}

void CTestView::DrawGraph()
{
m_myGrid.Clear();
m_myGrid.SetRows(5);
m_myGrid.SetCols(3);
}

void CTestView::OnSize(UINT nType, int cx, int cy)
{
CTabView::OnSize(nType, cx, cy);
if( m_myGrid.GetSafeHwnd() != 0){
CRect rect;
GetDisplayRect( &rect);
rect.DeflateRect( 1, 1, 1, 1);
m_myGrid.MoveWindow( &rect);
}
}


引用未解決
トピックタグ
bun
 bun
(@bun)
ゲスト
結合: 24年前
投稿: 761
 

> if (message == WM_PAINT)
> ((CTestView*)pGrid)->DrawGraph();
の呼び出しをやめてみたら、無限ループは収まりますか?


返信引用
kkawa
 kkawa
(@kkawa)
ゲスト
結合: 15年前
投稿: 10
Topic starter  

ありがとうございます。
> if (message == WM_PAINT)
> ((CTestView*)pGrid)->DrawGraph();
の呼び出しをやめてみたら、無限ループは収まりますか?

はい タブビューにグリッドコントロールが左上角に貼付いた状態で収まります。
マウスカーソルも正常に動きます。MSFexGridのポインタを横取するにはここから
どのように展開すればいいのかアドバイスいただければ幸せです。
MFCも初心者マークですが、SDKの混在も初めてなのですみません。


返信引用
kkawa
 kkawa
(@kkawa)
ゲスト
結合: 15年前
投稿: 10
Topic starter  

FlexGridをSDIで使う方法を教えてください。

「解決済み」のチェック間違えてしまいました。
申し訳ありません。


返信引用
bun
 bun
(@bun)
ゲスト
結合: 24年前
投稿: 761
 

そうであれば、WM_PAINTメッセージを受け取った際に、WM_PAINTが
発生するような処理を行っていることが問題です。
DrawGraph()を呼び出すタイミングをよく考えましょう。

CTestView::OnCreate()内で、m_myGrid.Create()を呼び出した直後でも良いのでは?


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

DrawGraphの内容って関数名に合っていない様な気がしますが、
この辺は感覚的なものもあるとは思うので一概には言えませんね。

内容的に表示の初期設定かなと言う気がします。
bunさんが言われているようにクリエイトした後、
初期設定として呼び出した方が良さそうです。
別の場所でも呼び出すと言うような事が無いのなら
クリエイト後に同じコードが書かれていても違和感はないかもしれません。

bunさんも書かれていますが、
WM_PAINTのメッセージを受け取った時の処理で
画面の書き換えを誘発するような処理は御法度です。
例えばですが、WM_PAINTを受け取った時の処理の中で
MessageBoxを出すような処理をすると
MessageBoxが消える時に画面の再描画が必要になる(WM_PAINTが発行される)
ので無限ループになってしまいます。
WM_PAINTを受け取った時の処理は基本的にDCへの描画処理だけに
限定した方が良いと思います。


返信引用
kkawa
 kkawa
(@kkawa)
ゲスト
結合: 15年前
投稿: 10
Topic starter  

bunさん PATIOさん ありがとうございます。
FlexGridはサブクラス化して使うものと勘違いしておりました。
まあ、サブクラス化自体がよくわからんのですが <o_o">
FlexGridの解説がなかなか見当たらないので無限迷路に落ちていましたが
弄くり廻しておりましたら、とりあえず以下のコードで動き始めました。
ただ、このスケルトンが正解ではないとは思いますので、今後ともよろしく
お願いいたします。
TabViewとGridの組み合わせ(Excelもどき)をやってみたつもりです。

CMSFlexGrid m_Grid;

int C**View::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CTabView::OnCreate(lpCreateStruct) == -1)
return -1;
//MSFlexGridのライセンスキー
WCHAR pwchLicenseKey[] =
{

};
CRect rect;
GetDisplayRect( &rect);
BSTR bstrLicense = ::SysAllocStringLen(
pwchLicenseKey, sizeof(pwchLicenseKey)/sizeof(WCHAR));
if (m_Grid.Create(NULL, WS_VISIBLE|WS_CHILD, rect, this,
IDC_MSFLEXGRID, NULL, FALSE, bstrLicense) == 0) {
AfxMessageBox(Can't create MSFlexGrid);
}
::SysFreeString(bstrLicense);

COleFont oleFont = m_Grid.GetFont();
oleFont.SetName(MS Pゴシック); // フォントを設定
//oleFont.SetBold(TRUE); // ボールドに
CY cy;
cy.int64 = 10 * 10000;
oleFont.SetSize(cy); // フォントサイズを 10ポイントに

//グリッドは最初に全部表示しておく
m_Grid.Clear();
// 行列の設定(タイトル行、見出し列含む)
m_Grid.SetRows(10); // 行
m_Grid.SetCols(5); // 列
//タブ文字サイズをメニューバーサイズと同じにする
SendMessage(WM_SETFONT, (WPARAM)::GetStockObject(DEFAULT_GUI_FONT),
0);
//文字色変化 TCS_HOTTRACK
//上 TCS_FLATBUTTONS
//下 TCS_BOTTOM
//左 TCS_VERTICAL
GetTabCtrl().ModifyStyle( 0, TCS_BOTTOM);
GetTabCtrl().ModifyStyle( 0,TCS_HOTTRACK);
GetTabCtrl().InsertItem( 0, _T(最初のタブ) );
GetTabCtrl().InsertItem( 1, _T(2番目のタブ) );
return 0;
}

void C**View::OnSize(UINT nType, int cx, int cy)
{
CTabView::OnSize(nType, cx, cy);
if( m_Grid.GetSafeHwnd() != 0){
CRect rect;
GetDisplayRect( &rect);
rect.DeflateRect( 1, 1, 1, 1);
m_Grid.MoveWindow( &rect);
}
}

void C**View::OnInitialUpdate()
{
CTabView::OnInitialUpdate();
m_Grid.Clear();
// 固定行列の文字を設定
CString s$ = < 1列目|< 2列目|< 3列目|< 3列目|< 4列目 ;
m_Grid.SetFormatString (s$);
//セルにデータを書き込む
for(int i=1;i<=5;i++) {
m_Grid.SetCol(i);
for(int j=0;j<=5;j++) {
m_Grid.SetTextMatrix(i,j,A);
m_Grid.SetRow(j);
//m_Grid.SetCellAlignment(7); //文字位置(右中央)
}
}

nTab_No = GetTabCtrl().GetCurSel();
switch(nTab_No){
case 0:
OnTab1(); break;
case 1:
OnTab2(); break;
default:
break;
};

}

void C**View::OnTab1()
{

}

void C**View::OnTab2()
{

}


返信引用
bun
 bun
(@bun)
ゲスト
結合: 24年前
投稿: 761
 

> FlexGridはサブクラス化して使うものと勘違いしておりました。
私はサブクラス化することの方が多いです。
そのやり方が分からないということかな?
VC++6.0を卒業して久しいので、詳しいやり方を忘れてしまったんですが、
リソースにグリッドを貼り付けた上で、クラスウィザードから変数の追加
とかするんじゃなかったかな。
以下のようなコードが吐き出されたら、サブクラス化は完了です。
DDX_Control(pDX, IDC_MSFLEXGRID, m_Grid);

さて、今回のコードは大体動作するのではないでしょうか。
ただ、無駄が多いコードなので、無駄を指摘させていただきますね。

まず、OnInitialUpdate() ですが、
> for(int i=1;i<=5;i++) {
> m_Grid.SetCol(i);
> for(int j=0;j<=5;j++) {
> m_Grid.SetTextMatrix(i,j,A);
> m_Grid.SetRow(j);
> //m_Grid.SetCellAlignment(7); //文字位置(右中央)
> }
> }

m_Grid.SetTextMatrix(i,j,A); とするなら、
m_Grid.SetCol(i); や m_Grid.SetRow(j); は不要です。

m_Grid.SetCellAlignment(7); をやろうとした跡がありますが、
そのための SetCol(i), SetRow(j) なのかな?
全てのセルの文字位置を[右中央]にしたいなら、もっといい手があります。

常に[右中央]固定なら、リソースの設定でやりましょう。それが最速です。
ソースコードからやるなら、m_Grid.SetColAlignment(i, 7); がいいです。

と、ここまで書いてふと思ったんですが、
VC++6.0って、CTabViewクラスありましたっけ?


返信引用
kkawa
 kkawa
(@kkawa)
ゲスト
結合: 15年前
投稿: 10
Topic starter  

bunさん ありがとうございます。
MSFlexGridのコードはまだ調べていないので何が使えるか
やって見ようと思います。以前使っていたListctrlは10000データ位
のアレーでテストしていましたのでGridの移植が出来上がったらご指摘の
部分の時間を比較計測してみようと思います。
TabViewは以下のところから流用させてもらってます。中身がその名のとおりの
クラスなんで、あとはCViewで作ってからこのTabViewに入れ替えて
使ってます。

http://software.nikkeibp.co.jp/software/backno/03vcmook2.html
「タブコントロールを活用する」

何か他人様のコードを貼り付けただけのスケルトンなんですが
まあ、SDIでFlexGridも動くかな という事で納得です。
今後ともよろしくお願い致します。


返信引用
kkawa
 kkawa
(@kkawa)
ゲスト
結合: 15年前
投稿: 10
Topic starter  

MSFlexGridについて、いろいろWebで調べていたのですが私の知識では
理解不能 ~_~):なので、質問させてください。
MFCから作成された?CMSFlexGridのラップクラスなるものの内、
InvokeHelperの第1引数の0x??のDISPIDが解ればなにかいろいろできそうな感じ
がしますが、これって何なんでしょう?
MSFlexGridのV_Tableみたいなのから、引いてきたIDなんでしょうか?
MSFlexGridのCOMなんかで生成してるんでしょうか?
どのような経路でサーバにたどりつくのか概要だけでもご教授いただければ
助かります。


返信引用
bun
 bun
(@bun)
ゲスト
結合: 24年前
投稿: 761
 

詳細な仕組みとなると、とても掲示板で説明しきれるものではありません。
以下をご参照下さい。
http://eternalwindows.jp/#com

簡単に言うと、FlexGridがどこにあろうと、インストール時にレジストリ
に自分の所在パスやプロパティやメソッドなどを記録するわけです。
(regsvr32.exeでネット検索すると山ほど出てきます)
それによって、IIDやDISPID等とFlexGridの実装を関連づけるわけです。

そして、VC++から使用する際は、それらのIIDやDISPIDを用いたラップク
ラスをはき出すわけです。

重要なのは、上記、レジストリ登録、ラップクラス生成を行うための機構
をFlexGridのDLL自身が持っていることにあります。

そのため、FlexGridのDLLがどのフォルダにインストールされようと、環
境に依存せずに利用できるわけです。
また、実装ファイル(C++開発ならCPP,Hんどのファイル)を完全隠蔽する
こともできているわけです。


返信引用
subaru
 subaru
(@subaru)
ゲスト
結合: 19年前
投稿: 381
 

少し補足するとDLL/OCXのパスとタイプライブラリの所在はレジストリに記録されますが
プロパティやメソッドなどについてはタイプライブラリの方に記録されていて、
DISPIDの定義をOLE/COM オブジェクトビューア(oleview.exe)で確認することができます。
#タイプライブラリはDLLのリソースとして含まれていることが多いです。

ちなみにXP以降ではDLL/OCXをローカルに配置してexeのマニフェストリソースに
comClass要素を書いておくことでもインスタンスの作成ができるようになっているので、
必ずしもregsvr32.exeでレジストリに公開しなくてもよくなっています。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました