現在、VC++2010・MFC環境でMFCのタブコントロールのウィンドウ部(?)をグラデーション描画にしたいと考えています。
完成予想としては、Excelのメニュー(?)みたいな感じでグラデーションがかかるような感じにしたいのですが、現在、グラデーションの描画は何とか(たぶん無理やり)できましたが、タブを切替たり、ダイアログ自体が非アクティブ/アクティブを繰り返すとちらついてしまいます。
ソースは以下のようになっています。
-----------------------------------------------------------------
void CTabGradDlg::OnTcnSelchangeTab(NMHDR *pNMHDR, LRESULT *pResult)
{
// TODO: ここにコントロール通知ハンドラー コードを追加します。
int sel = m_xcTab.GetCurSel();
m_edit1.ShowWindow(SW_HIDE);
m_edit2.ShowWindow(SW_HIDE);
m_button1.ShowWindow(SW_HIDE);
m_button2.ShowWindow(SW_HIDE);
switch(sel)
{
case 0:
m_edit1.ShowWindow(SW_SHOW);
m_button1.ShowWindow(SW_SHOW);
break;
case 1:
m_edit2.ShowWindow(SW_SHOW);
m_button2.ShowWindow(SW_SHOW);
break;
}
Invalidate();
*pResult = 0;
}
void CTabGradDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
{
CDialogEx::OnActivate(nState, pWndOther, bMinimized);
// TODO: ここにメッセージ ハンドラー コードを追加します。
switch( nState )
{
case WA_INACTIVE :// 非アクティブ
break;
case WA_ACTIVE :// (マウスをクリックする以外の方法) アクティブ
case WA_CLICKACTIVE :// (マウス クリック)アクティブ
Invalidate();
break;
}
}
-----------------------------------------------------------------
Invalidate();が原因でちらついていることまでは分かっているのですが、
なぜちらつくのか?ということと、対処方法もしくは別の方法はないのか?
別の方法があればどういったことなのか?ということが知りたいです。
初心者(小学生並み)にもわかるように教えていただければ幸いです。
宜しくお願いします。
No.7ベストアンサー
- 回答日時:
クラスビューでCTabXxxCtrlを選んでプロパティを開きます。
プロパティにアイコンでメッセージというのがあるので、そこでWM_PAINTを選べばOnPaint()が作成されます。
どういう事に成るかは作って見れば分かりますが、ここで描画すればチラつくことはなくなると思いますが以前に書いた通りすごく面倒です。
>この場合はタブ・ボタンも全て自分で書く必要があります。
書くではなく正確に言うと描くですね。失礼しました。
OnPaint()を作ってみれば分かります。
どうやって描くかというとCDCクラスのメンバ関数を駆使して下さいとしか言えません。すごく面倒ですけどね。
なお、C++の勉強はMFCをやる以上は避けられないので入門書を購入して勉強してくださいとしか言えません。
ありがとうございます。
>クラスビューでCTabXxxCtrlを選んでプロパティを開きます。
>プロパティにアイコンでメッセージというのがあるので、そこでWM_PAINTを選べばOnPaint()が作成されます。
>どういう事に成るかは作って見れば分かりますが、ここで描画すればチラつくことはなくなると思いますが以前に書いた通りすごく面倒です。
上記手順で作成したら、作成できました。ありがとうございます。
OnPaintに何もコードを書かずにデバッグ確認したら、タブすらも表示されませんでした。
それが
>>この場合はタブ・ボタンも全て自分で書く必要があります。
ということですね?
>なお、C++の勉強はMFCをやる以上は避けられないので入門書を購入して勉強してくださいとしか言えません
ネットに転がっているものを参考に勉強するだけでは、不十分なのでしょうか?
当初の目的はグラデーション描画についてのことでしたので、ベストアンサーを付けさせていただきます。
No.6
- 回答日時:
見てみたところ問題点はCTabGradDlg::OnDrawItemで強引に描画している所の様です。
m_xcTabの宣言が
CTabCtrl m_xcTab;
に成っていると思いますが、CTabCtrlを継承したクラスを新規に作成してそのクラス名としてください。
CTabXxxCtrl m_xcTab;
と宣言に書き換えます。CTabXxxCtrlはCTabCtrlを継承した新規のクラスです。
その新たなクラスであるCTabXxxCtrlクラスのOnPaint()でオーナードローします。この場合はタブ・ボタンも全て自分で書く必要があります。これは実に面倒なので私としては前に書いたタブボタンだけを使う方法をお勧めします。
継承が分からない事言うことでしたらC++をちゃんと勉強して下さい。C言語の知識だけではMFCを扱えません。
ありがとうございます。
>CTabCtrlを継承したクラスを新規に作成してそのクラス名としてください。
>CTabXxxCtrl m_xcTab;
>と宣言に書き換えます。CTabXxxCtrlはCTabCtrlを継承した新規のクラスです。
>その新たなクラスであるCTabXxxCtrlクラスのOnPaint()でオーナードローします。
CTabCtrlのクラスを作成し、宣言の書き換えはできました。
しかし、『CTabXxxCtrlクラスのOnPaint()でオーナードローします。』がよくわかりません。
クラスを作成しただけではOnPaint()は存在しませんよね?
メッセージマップ(?)にも何も書いてないし。。。自分でOnPaint()作ればいいのでしょうか?
また、『OnPaint()でオーナードローする。』とはどういうことでしょうか?
>この場合はタブ・ボタンも全て自分で書く必要があります。
タブ・ボタンも全て自分で書くというのは、どういうことでしょうか?
自力で調べたりしましたが、未だに『書く』といったことが何を指しているのかよくわかりません。。。
>継承が分からない事言うことでしたらC++をちゃんと勉強して下さい。C言語の知識だけではMFCを扱えません。
そうですね、その通りです。ご不便をおかけしてすみません。
以前に少しだけ習ったのですが、習ってからだいぶ期間が開いていたので、ほとんど忘れてしまいました。
No.5
- 回答日時:
次々新事実が出てくるのでソースコードを添付した貰った方が良いと思います。
勘だけで答えるのは限度があります。
ありがとうございます。
>次々新事実が出てくるのでソースコードを添付した貰った方が良いと思います。
そうですね。何分、初めて質問投稿させていただいたので、何をどう伝えたらいいかわかりませんでした。すみません。
以下、最初の質問以外のソースコードです。(OnPaintとオーナードローの描画についてのみ)
void CTabGradDlg::OnPaint()
{
CDialog::OnPaint();
CTabCtrl *pTabCtrl =(CTabCtrl *)GetDlgItem(IDC_TAB);
//---------------------------------
// デバイスコンテキスト(DC)作成
//---------------------------------
CWnd* pWnd = GetDlgItem(IDC_TAB);
CDC* dc = pWnd->GetDC();
//---------------------------------
// ダミーデバイスコンテキスト(DC)作成
// ビットマップ作成
//---------------------------------
CDC dcDmy;
dcDmy.CreateCompatibleDC(dc);
CBitmap bmpDmy;
//---------------------------------
// クライアント領域取得
//---------------------------------
CRect rect;
GetClientRect(&rect);// クライアント領域の座標取得
pTabCtrl->AdjustRect(FALSE, &rect);
//---------------------------------
// 裏描画画面作成
//---------------------------------
bmpDmy.CreateCompatibleBitmap(dc, rect.Width(), rect.Height());
dcDmy.SelectObject(&bmpDmy);
//---------------------------------
// 256色の配列レコード作成
//---------------------------------
int segments = 255;
DWORD* dwBits = new DWORD[segments];
for(int i = 0; i < segments; ++i)
{
dwBits[i] = (DWORD)RGB(0xFF - i, 0xFF - i, 0xFF - i);
};
//---------------------------------
// 32ビットの1ピクセル幅ビットマップ
// と255ピクセル作成
//---------------------------------
HBITMAP hBitmap = ::CreateBitmap(1, segments, 1, 32, dwBits);
delete [] dwBits;
//---------------------------------
// パターンブラシ作成(グラデーション)
//---------------------------------
CBrush brush;
brush.CreatePatternBrush(CBitmap::FromHandle(hBitmap));
CBrush* oldbrush = (CBrush*)dcDummy.SelectObject(&brush);
//---------------------------------
// パターンブラシ作成(フレーム)
//---------------------------------
CBrush frmbrush;
frmbrush.CreateSolidBrush(RGB(255, 255, 255));
//---------------------------------
// パターンブラシで四角形描画
//---------------------------------
CRect frmrect;
frmrect = rect;
frmrect.top = 0;
frmrect.left = 0;
dcDummy.Rectangle(frmrect);
dcDummy.FrameRect(frmrect, &frmbrush);
dcDummy.SelectObject(oldbrush);
//---------------------------------
// ブラシの破棄
//---------------------------------
frmbrush.DeleteObject();// ブラシの破棄
brush.DeleteObject();// ブラシの破棄
//---------------------------------
// 貼り付け
//---------------------------------
dc->BitBlt(rect.left , rect.top , rect.Width(),
rect.Height(), &dcDmy, 0, 0, SRCCOPY);
//---------------------------------
// メモリの解放
//---------------------------------
dcDmy.DeleteDC();
bmpDmy.DeleteObject();
pWnd->ReleaseDC(dc);//CDCを解放
}
//**************************************************************
//TabGradDlgのオーナードロー
//**************************************************************
void CTabGradDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpdis)
{
if(lpdis->CtlType == ODT_TAB)
{
CTabCtrl *pTabCtrl = (CTabCtrl *)GetDlgItem(IDC_TAB);
//---------------------------------
// デバイスコンテキスト(DC)作成
//---------------------------------
CDC *dc = CDC::FromHandle(lpdis->hDC);
・・・・
// 以下、OnPaint()と同様
・・・・
//---------------------------------
// タブの文字列表示(ブラシ破棄後実装)
//---------------------------------
TC_ITEMtcItemGet;
TCHAR buffer[256] = {0};
tcItemGet.pszText = buffer;
tcItemGet.mask = TCIF_TEXT;
tcItemGet.cchTextMax = 256;
m_xcTab.GetItem(lpdis->itemID, &tcItemGet);
CRect Rect = lpdis->rcItem;
Rect.left += 3;
Rect.top += 3;
dc->DrawText(tcItemGet.pszText, -1, Rect, DT_END_ELLIPSIS);
・・・
// 貼りつけ、メモリ解放
}
}
あと、他のソースコードは、質問に添付してあったOnActivateとOnTcnSelchaneTabです。
それ以外は、特にコードを書いていません。
宜しくお願いします。
No.4
- 回答日時:
試して見ましたが、CDialogを継承したCXXXDlg上でOnPaint()で描画したものはチラつきません。
タブコントロールは、CXXXDlgのダイアログ上に有るものとします。普通にやるとタブコントロールがタブ以外の部分も白く描画してしまうので、タブボタンを残してリソースエディタ上でサイズを縮めてやりました。
こういう状態では無いんですよね?
あとの方法は、CTabCtrlクラスを継承して継承クラスのOnPaint()でオーナードローする方法ですがタブボタンまで自分で書かなくてはいけないので面倒です。
ありがとうございます。
>普通にやるとタブコントロールがタブ以外の部分も白く描画してしまうので、タブボタンを残してリソースエディタ上でサイズを縮めてやりました。
>こういう状態では無いんですよね?
『タブボタンを残して』の意が読み取れませんでした。
リソースエディタ上でタブコントロールのサイズを小さくするといったことでいいんですかね?
そうだとすると、そういう状態ではないです。
>あとの方法は、CTabCtrlクラスを継承して継承クラスのOnPaint()でオーナードローする方法ですがタブボタンまで自分で書かなくてはいけないので面倒です。
『CTabCtrlクラスを継承して継承クラスのOnPaint()でオーナードロー』とはどういった方法なのでしょうか?
記述し忘れていましたが、現在、タブコントロールはオーナードローにしていて、オーナードロー内でもグラデーションの描画をしています。
なので、《オーナードローで描画》・《OnPaintで描画》するようになっています。
No.3
- 回答日時:
すいません状況を整理させて下さい。
まとめると
・タブコントロールは使っているが、各タブ用の子ダイアログは用意していない。
・OnPaintでグラデーション背景を描いている。
・OnActiveでInvalidate();して再描画を行わないと再描画されずにウィンドウ画像が崩れる場合がある。
ってことですよね?
このOnPaintとOnActiveがあるのはCTabGradDlgですか?で、このCTabGradDlgは何を継承したクラスなのでしょうか?プログラムの作りそのものに問題がある気がしてきました。
各タブ用の子ダイアログを作って各子ダイアログでグラデ背景を描画すれば解決する気がします。
ありがとうございます。
>・タブコントロールは使っているが、各タブ用の子ダイアログは用意していない。
その通りです。
>・OnPaintでグラデーション背景を描いている。
OnPaintの他にタブコントロールをオーナードローしているので、そこでもグラデーション描画をしています。
また、背景というより、DCに描画しているような感じです。
>・OnActiveでInvalidate();して再描画を行わないと再描画されずにウィンドウ画像が崩れる場合がある。
『ウィンドウ画面が』というより、『タブコントロールの一部のが』といった感じです。(同じですかね?)
>このOnPaintとOnActiveがあるのはCTabGradDlgですか?
はい、同じCTabGradDlgです。
>で、このCTabGradDlgは何を継承したクラスなのでしょうか?
CDialogEx(CTabGradDlg::IDD, pParent)だと思います。
(いまいち継承の概念が読み込めていないので曖昧です。すみません。)
>各タブ用の子ダイアログを作って各子ダイアログでグラデ背景を描画すれば解決する気がします。
その方法も考えたのですが、そうすると、子ダイアログの大きさが統一できないのではないかと思いまして。。
また、その方法だと、子ダイアログの背景をグラデーションにし、子ダイアログにそれぞれボタン等のコントロールを表示するという風になるのでしょうか?
No.2
- 回答日時:
失礼しましたOnPaintで書いているんですね。
OnPaintでInvalidate();すると描画が無限ループになるのでやってはいけません。ところでWA_ACTIVEやWA_CLICKACTIVEでInvalidate();は必要なのでしょうか?そもそもOnActivate自体いらないのでは?OnActivateが必要になった事ってあまり無いですよ。
ありがとうございます。
>ところでWA_ACTIVEやWA_CLICKACTIVEでInvalidate();は必要なのでしょうか?
ウィンドウの一部(下記のタブの【*****】部分)が、他のウィンドウの影になって再度ウィンドウをアクティブにした時に、(タブの)影になっていた部分が描画されていなかったので、
ウィンドウがアクティブになったら再度描画しよう。という結果になり、このようなコードになりました。
______
| タブ1 | タブ2|________
| **************|
| **************|
| **************|
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
>そもそもOnActivate自体いらないのでは?OnActivateが必要になった事ってあまり無いですよ。
上記にも説明した理由の為OnActivateを使用していましたが、OnActivateを使用する以外で他の方法があるのでしょうか?
No.1
- 回答日時:
MFCでダイアログ系(タブもダイアログ系)の場合は、OnPaintで描画しないとちらつきますが大丈夫でしょうか?
回答ありがとうございます。
>OnPaintで描画しないとちらつきますが大丈夫でしょうか?
というのは、OnPaintでInvalidateを実装(?)すればいいのでしょうか?
OnPaintでは現在、ダブルバッファリングにてグラデーションの描画をしています。
また、補足としては、タブはダイアログではなく、タブコントロール貼りつけたまま(言い方変?)
の状態で、タブ遷移することで、子ダイアログが表示されるといったものではありません。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・人生のプチ美学を教えてください!!
- ・10秒目をつむったら…
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
WM_PAINT
-
VB6,リストボックスの特定行の...
-
CStaticコントロールの静的イメ...
-
panelのスクロール表示について
-
UpdateData( FALSE); による文...
-
MFCでOnPaintのタイミング
-
OneNote 2010 文字と描画がずれる
-
VB.netでのライン描画方法がわ...
-
FlexGridの一部のみ表示を更新...
-
MFC FormViewの背景色
-
GDI+のDrawStringを使って文字...
-
Labelの文字をスクロールする際...
-
タスクバーを再描画
-
C++にて、塗りつぶされた円を描...
-
InvalidateRectの使い方について
-
pset関数について
-
Minecraft 統合版(PC)の描画距...
-
ダイアログボックスについて。
-
Web上で指定したプロットを基に...
-
word
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
VB6,リストボックスの特定行の...
-
word
-
NVIDIAのシェーダーキャッシュ
-
MFCでOnPaintのタイミング
-
Minecraft 統合版(PC)の描画距...
-
google Colabでmatplotlibの描...
-
TextBoxに文字を書いても表示さ...
-
[VB.net] DataGridViewの列ヘッ...
-
UpdateData( FALSE); による文...
-
OneNote 2010 文字と描画がずれる
-
Labelの文字をスクロールする際...
-
InvalidateRectの使い方について
-
VB.netでのライン描画方法がわ...
-
CStaticコントロールの静的イメ...
-
VC++プログラムをつかったBMP画...
-
WM_SIZEとWM_SIZINGの違い (Win...
-
エクセルでガンチャートを作成...
-
c言語を使いダイアログにbmpを...
-
WM_PAINT
-
MFCのタイマーのつかい方を教え...
おすすめ情報