ページ 1 / 1
MFC タブコントロールのOwner Draw Fixedについて
Posted: 2013年9月12日(木) 15:09
by かなたん
Windows7 Visual Studio 2008で、MFCのSDIでダイアログを作成しています。
MFC編 - タブコントロールの基本1を参考にタブコントロールを使っています。
表示は問題なくでき、タブコントロールのプロパティーの表示部分をいじってどうなるのか試してみました。
Owner Draw Fixedをtureにしたときのデザインがいいと思い、そのまま実行させてみました。
[album]698[/album]
すると、そのダイアログを表示させようとするとDebug Assertion Faildが出てしまいました。
[album]700[/album]
ダイアログのほうを見てみると、中身は表示されていますがタブが表示されていませんでした。
[album]699[/album]
そもそもOwner Draw Fixedの説明にある「親ウィンドウがタブを表示するようにします」の意味はわかっておらず、ただデザインが気に入っただけです。
ネットで調べてみようと思いましたが、読んでもよくわかりませんでした。
falseのままにすれば問題はないのですが、Owner Draw Fixedはtrueにすべきではないのでしょうか?
どのようにすればあのようなデザインが使えるようになるでしょうか?
Re: MFC タブコントロールのOwner Draw Fixedについて
Posted: 2013年9月12日(木) 15:28
by softya(ソフト屋)
画像が小さすぎて見えませんので、お願いします。
Owner Draw FixedはtrueはOSやMFCに任せずに自分で親ウィンドウが描画を担当するという意味です。
デザインが気に入られたみたいですが、あれは何もしていない状態ですね。
ただ、Owner Draw FixedはtrueにしただけだとDebug Assertion Faildしないので原因は別にあるのでは?
Re: MFC タブコントロールのOwner Draw Fixedについて
Posted: 2013年9月12日(木) 22:50
by かなたん
softya(ソフト屋) さんが書きました:画像が小さすぎて見えませんので、お願いします。
確かに画像小さいですね・・・すいません。
画像はフォーラムのアルバムにアップロードしたものです。
「File: f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\winctrl2.cpp
Line: 1219」
などと書かれていました。
softya(ソフト屋) さんが書きました:Owner Draw FixedはtrueはOSやMFCに任せずに自分で親ウィンドウが描画を担当するという意味です。
デザインが気に入られたみたいですが、あれは何もしていない状態ですね。
そうだったんですか。
VBAのユーザフォームにあるタブみたいでいいと思いました。
softya(ソフト屋) さんが書きました:ただ、Owner Draw FixedはtrueにしただけだとDebug Assertion Faildしないので原因は別にあるのでは?
無事タブコントロールを表示できることを確認した後、あれこれプロパティーの表示部分をいじったりしましたが、どれも変えては戻しの繰り返しです。
なので、今回はうまくいっていた状態からOwner Draw Fixedをtrueにしただけです。
本当はあったけど隠れていたバグがOwner Draw Fixedをtrueにしたのをきっかけに出てきたのでしょうか?
Re: MFC タブコントロールのOwner Draw Fixedについて
Posted: 2013年9月12日(木) 22:54
by softya(ソフト屋)
かなたん さんが書きました:画像が小さすぎて見えませんので、お願いします。
確かに画像小さいですね・・・すいません。
画像はフォーラムのアルバムにアップロードしたものです。
「File: f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\winctrl2.cpp
Line: 1219」
などと書かれていました。
その行にはどういう命令が有るんでしょうか?
かなたん さんが書きました:
softya(ソフト屋) さんが書きました:ただ、Owner Draw FixedはtrueにしただけだとDebug Assertion Faildしないので原因は別にあるのでは?
無事タブコントロールを表示できることを確認した後、あれこれプロパティーの表示部分をいじったりしましたが、どれも変えては戻しの繰り返しです。
なので、今回はうまくいっていた状態からOwner Draw Fixedをtrueにしただけです。
本当はあったけど隠れていたバグがOwner Draw Fixedをtrueにしたのをきっかけに出てきたのでしょうか?
これだけの情報だとなんとも言えないんですが、試しに新規でダイアログを作ってタブコントロールを置いてOwner Draw Fixedをtrueとして見ましたが問題は発生しませんでした。
【補足】
トラブルが合った場合、問題を切り分けるために私はよく新規でプロジェクトを作って、その機能だけを実験します。
その上でトラブルを潰して本来のプロジェクトに反映させれば他のバグが原因で悩まされる心配がないからです。
Re: MFC タブコントロールのOwner Draw Fixedについて
Posted: 2013年9月13日(金) 10:01
by かなたん
softya(ソフト屋) さんが書きました:その行にはどういう命令が有るんでしょうか?
コード:
void CTabCtrl::DrawItem(LPDRAWITEMSTRUCT)
{
ASSERT(FALSE); // must override for self draw tab controls
}
のASSERT部分です。
ということは、タブコントロールの描画部分が原因なのでしょうか?
softya(ソフト屋) さんが書きました:これだけの情報だとなんとも言えないんですが、試しに新規でダイアログを作ってタブコントロールを置いてOwner Draw Fixedをtrueとして見ましたが問題は発生しませんでした。
【補足】
トラブルが合った場合、問題を切り分けるために私はよく新規でプロジェクトを作って、その機能だけを実験します。
その上でトラブルを潰して本来のプロジェクトに反映させれば他のバグが原因で悩まされる心配がないからです。
マインスイーパー.rcにあるダイアログ部分とメニューの一部・Resorce.hにある#defineの一部を新規プロジェクトにコピペしてみました。
クラスウィザードでコピーしてきたダイアログのクラスを作り、中身は元のプロジェクトからコピペしました。
そして、新規プロジェクトのview.cppにメニューのメッセージハンドラを作り実行させてみると、なぜかダイアログが出ませんでした。
コード:
void CダイアログテストView::OnShowRecord()
{
// TODO: ここにコマンド ハンドラ コードを追加します。
CShowRecord ShowRecord_dlg;
INT_PTR ShowRecord_Show;
ShowRecord_Show = ShowRecord_dlg.DoModal();
if(ShowRecord_Show==IDOK){
}
}
なにかコピペなどに問題があったのでしょうか?
リソースビューでダイアログなどを開いてみると元の通り表示されますし、Owner Draw Fixedなどの設定も元のままですが・・・
Owner Draw Fixedをfalseにしても変わりませんでした。
ShowRecord.cpp
コード:
// ShowRecord.cpp : 実装ファイル
//
#include "stdafx.h"
#include "ダイアログテスト.h"
#include "ShowRecord.h"
// ShowRecord ダイアログ
IMPLEMENT_DYNAMIC(CShowRecord, CDialog)
CShowRecord::CShowRecord(CWnd* pParent /*=NULL*/)
: CDialog(CShowRecord::IDD, pParent)
{
}
CShowRecord::~CShowRecord()
{
}
void CShowRecord::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_Record, record_tab);
}
BEGIN_MESSAGE_MAP(CShowRecord, CDialog)
ON_NOTIFY(TCN_SELCHANGE, IDC_Record, &CShowRecord::OnTcnSelchangeRecord)
END_MESSAGE_MAP()
// ShowRecord メッセージ ハンドラ
BOOL CShowRecord::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: ここに初期化を追加してください
CRect rect;
record.Create(CRecord::IDD, this);
record.GetClientRect(&rect);
rect.OffsetRect(1, 21);
record.MoveWindow(&rect, FALSE);
record_tab.InsertItem(0, _T("初級"));
record_tab.InsertItem(1, _T("中級"));
record_tab.InsertItem(2, _T("上級"));
OnTcnSelchangeRecord(0, 0);
record.ShowWindow(SW_SHOW);
return TRUE; // return TRUE unless you set the focus to a control
// 例外 : OCX プロパティ ページは必ず FALSE を返します。
}
void CShowRecord::OnTcnSelchangeRecord(NMHDR *pNMHDR, LRESULT *pResult)
{
// TODO: ここにコントロール通知ハンドラ コードを追加します。
int select = record_tab.GetCurSel();
//*pResult = 0; //こっちだと「動作を停止しました」といわれるので、
if (pResult) *pResult = 0; //参考にしているサイトのようにこのようにするとエラーは出なかった。
}
Record.cpp
コード:
// First.cpp : 実装ファイル
//
#include "stdafx.h"
#include "ダイアログテスト.h"
#include "Record.h"
// First ダイアログ
IMPLEMENT_DYNAMIC(CRecord, CDialog)
CRecord::CRecord(CWnd* pParent /*=NULL*/)
: CDialog(CRecord::IDD, pParent)
{
}
CRecord::~CRecord()
{
}
void CRecord::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CRecord, CDialog)
ON_BN_CLICKED(IDC_Reset, &CRecord::OnBnClickedReset)
ON_NOTIFY(TCN_SELCHANGE, IDC_Record, &CRecord::OnTcnSelchangeRecord)
END_MESSAGE_MAP()
// First メッセージ ハンドラ
void CRecord::OnBnClickedReset()
{
// TODO: ここにコントロール通知ハンドラ コードを追加します。
}
void CRecord::OnTcnSelchangeRecord(NMHDR *pNMHDR, LRESULT *pResult)
{
// TODO: ここにコントロール通知ハンドラ コードを追加します。
*pResult = 0;
}
なぜかタブコントロールの中身用のクラスにもタブ変更の通知ハンドラを作っていた(今コピペしてみて気が付きました)ので、いらないと思いとりあえずコメントアウトして試してみました。
それでも元のプロジェクトではDebug Assertion Faildですし、新しいプロジェクトではダイアログが出ませんでした。
Re: MFC タブコントロールのOwner Draw Fixedについて
Posted: 2013年9月13日(金) 10:39
by usao
>ASSERT(FALSE);
本当にあなたのコードにこれが書かれているのであれば,
Debug実行した際には,ここに到達した時点で
Debug Assertion Failed と言われるのは当たり前です.そうしろと書いたのだから.
Re: MFC タブコントロールのOwner Draw Fixedについて
Posted: 2013年9月13日(金) 10:48
by softya(ソフト屋)
>ASSERT(FALSE);
これはウィザードが自動生成したコードである可能性が高いですね。自動生成時のコメントが有るはずです。
オーナードローを選択したのだから自分で描画コードを書くはずだから、書いてないのは忘れているミスって解釈なのでしょう。
【補足】
// must override for self draw tab controls
ってウィザードのコメントこれだけ?
まぁ、mustなので書け!って事だけど。
Re: MFC タブコントロールのOwner Draw Fixedについて
Posted: 2013年9月13日(金) 11:13
by softya(ソフト屋)
あっ、クラスのコピペですがリソース問題とか色々ややこしいので詳しくないうちは止めたほうが良いです。
※ これだけの情報だと何とも言えないので。
Re: MFC タブコントロールのOwner Draw Fixedについて
Posted: 2013年9月13日(金) 15:52
by ISLe
CTabCtrl::DrawItemというのはMFCのソースコードなのでは?
クラスウィザードで新規にクラスを作るとそのクラスにオーバーライドされたメンバ関数が自動生成されるのではないかと。
Re: MFC タブコントロールのOwner Draw Fixedについて
Posted: 2013年9月13日(金) 16:07
by かなたん
usao さんが書きました:>ASSERT(FALSE);
本当にあなたのコードにこれが書かれているのであれば,
Debug実行した際には,ここに到達した時点で
Debug Assertion Failed と言われるのは当たり前です.そうしろと書いたのだから.
softya(ソフト屋) さんが書きました:>ASSERT(FALSE);
これはウィザードが自動生成したコードである可能性が高いですね。自動生成時のコメントが有るはずです。
オーナードローを選択したのだから自分で描画コードを書くはずだから、書いてないのは忘れているミスって解釈なのでしょう。
【補足】
// must override for self draw tab controls
ってウィザードのコメントこれだけ?
まぁ、mustなので書け!って事だけど。
Assertionに書かれていたファイルは私が作ったものではなく、ファイルパスもf:\から始まっていることからどこにあるのかさえわかっていませんでした。
ですが、デバッグ中に出たときに中止でなく再試行をしてみると、winctrl2.cppというファイルが開かれ矢印があの位置にありました。
なのでそこのことなんだろうなと思いそのまま引用しました。
自分で描画コードを書く―今回はあのデザインのままにしたいからクラスをオーバーライドして描画用関数の中身は何も書かないようにするのだと思い、とりあえずCShowRecordクラスにCTabCtrlクラスも継承させるようにしてみました。
コード:
class CShowRecord : public CDialog , public CTabCtrl
すると、以下のようなエラーが出てきてしまいました。
コード:
1>省略\showrecord.cpp(31) : error C2594: 'static_cast' : 'void (__thiscall CShowRecord::* )(NMHDR *,LRESULT *)' から 'void (__thiscall CCmdTarget::* )(NMHDR *,LRESULT *)' への変換はあいまいです。
1>省略\showrecord.cpp(43) : error C2594: '引数' : 'CShowRecord *const ' から 'CWnd *' への変換はあいまいです。
ISLe さんが書きました:CTabCtrl::DrawItemというのはMFCのソースコードで、クラスウィザードで新規にクラスを作るとオーバーライドしたコードが自動生成されるのでは?
改めてクラスを作れば自動でオーバーライドされるのでしょうか?
そもそもC++やMFCでクラスのオーバーライドをしたことがなく、どのようにすればいいのかよくわかっていません。
softya(ソフト屋) さんが書きました:あっ、クラスのコピペですがリソース問題とか色々ややこしいので詳しくないうちは止めたほうが良いです。
※ これだけの情報だと何とも言えないので。
中身を同じにさせるためにコピペでいいかななんて思っていました。
それによって何か問題が起こることは考えていませんでした。
その可能性を知らなかったので。
名前さえ合わせればエラーにならないからいいかななんて思っていましたが、そういう問題ではないようですね。
せめて全部ではなく関数の中身などの必要最小限にすることにします。
Re: MFC タブコントロールのOwner Draw Fixedについて
Posted: 2013年9月13日(金) 21:34
by softya(ソフト屋)
なるほどMFC側の基礎クラスのDrawItem()でアサートしていたんですね。
詳しくないと分からないと思いますが、MFCは基本的に継承してクラスを利用しています。
なので、いつの間にかオーバーライドを使っている所が多数あります。
Assertionに書かれていたファイルは私が作ったものではなく、ファイルパスもf:\から始まっていることからどこにあるのかさえわかっていませんでした。
ですが、デバッグ中に出たときに中止でなく再試行をしてみると、winctrl2.cppというファイルが開かれ矢印があの位置にありました。
なのでそこのことなんだろうなと思いそのまま引用しました。
自分で描画コードを書く―今回はあのデザインのままにしたいからクラスをオーバーライドして描画用関数の中身は何も書かないようにするのだと思い、とりあえずCShowRecordクラスにCTabCtrlクラスも継承させるようにしてみました。
それと適当に継承しても上手く行かなって当たり前です。
なんだろう、C++の勉強も必要ですが、各クラスの継承関係も把握しないと多重継承なんてしてはいけません。
「MFC 階層図」
http://msdn.microsoft.com/ja-jp/library ... x#feedback
階層的に違う物は「混ぜるな危険!」です。
詳しくない人がやるべきことでは無いですね。
管理しているコントロールリソースも違うので、混ぜられる筈がないのです。
とりあえず、変な事はせず(高度なオーナードローは使わない)普通にタブコントロールを実装してみてください。
それが出来たらステップアップとして将来的に挑戦スべきだと思います。
Re: MFC タブコントロールのOwner Draw Fixedについて
Posted: 2013年9月13日(金) 23:21
by かなたん
softya(ソフト屋) さんが書きました:なるほどMFC側の基礎クラスのDrawItem()でアサートしていたんですね。
詳しくないと分からないと思いますが、MFCは基本的に継承してクラスを利用しています。
なので、いつの間にかオーバーライドを使っている所が多数あります。
たとえばMFCで自動で作られるC~ViewクラスがCViewクラスを継承して作られているなどというのは知っていました。
C++やMFCで自分でクラスの継承をしたことがないのですが、とりあえずCTabCtrlをオーバーライドしなくてはならないらしいと思って適当にやってしまいました。
とりあえず、CDialogクラスもCTabCtrlクラスもCWndクラスの派生クラスですよね?
「Visual C++6.0[MFC6.0]対応MFCライブラリ標準リファレンス」という本を持っていて、そこでCTabCtrlクラスのメンバであるDrawItemを見て、引数の説明にあるDRAWITEMSTRUCT構造体についても見てみたのですが、その構造体の説明を読んでもあまりよくわかりませんでした。
softya(ソフト屋) さんが書きました:とりあえず、変な事はせず(高度なオーナードローは使わない)普通にタブコントロールを実装してみてください。
それが出来たらステップアップとして将来的に挑戦スべきだと思います。
デフォルト設定のままでタブコントロールを使用することはできてます。

ただ、デフォルトのタブコントロールの右側に白い線が出ているのが気になっていました。
あと、選択されたタブが白くなるのも気に入っていません。
そこでプロパティーの表示をあれこれいじったりしてみると、あのOwner Draw Fixedのデザインがいいと思ったのです。
でも、今の私の知識ではこのままのほうがよさそうですかね。
Re: MFC タブコントロールのOwner Draw Fixedについて
Posted: 2013年9月13日(金) 23:42
by softya(ソフト屋)
Vista以降の描画スタイルとかも関係ありそうですね。
ここ直すのはかなり知識を必要とするので、知識を増やしてからのほうがよさそうです。
CTalCtrlは使ったことがないのでサンプル出せなくて申し訳ないです。
※ いつもは私は設定メニューなどでプロパティシートのタブを使っているのですが仕組みが違いすぎて例にならないのです。
Re: MFC タブコントロールのOwner Draw Fixedについて
Posted: 2013年9月14日(土) 00:08
by かなたん
softya(ソフト屋) さんが書きました:Vista以降の描画スタイルとかも関係ありそうですね。
ここ直すのはかなり知識を必要とするので、知識を増やしてからのほうがよさそうです。
CTalCtrlは使ったことがないのでサンプル出せなくて申し訳ないです。
※ いつもは私は設定メニューなどでプロパティシートのタブを使っているのですが仕組みが違いすぎて例にならないのです。
プロパティーシートとタブコントロールが全くの別物であるのはどこかのサイトで見ました。
今回いろいろと質問してみて私にはわからないことだらけだったので、今回はOwner Draw Fixedについてはあきらめることにします。
いつか継承のこととかしっかり勉強してから改めて試すことにします。
ありがとうございました。