CreateSolidBrushによるブラシの作成に関して、過去スレでいくらか議論されています
が、いまいち解決できません。
私の場合、OnCtlColorで状態をチェックし、色を変更します。
そのいろの変更は任意に変更できなければならないので、HBRUSHのメンバ変数をもち、
ダイアログ等のコンストラクタでCreateSolidBrushを一度のみににする、という方法が
とれません。CreateSolidBrushを必要とするタイミングが無限あるわけです。
そのような場合、DeleteObjectする必要があるのですが、OnCtlColorの段階ではまだ消
せません。
そうなるとどのタイミングでDeleteObjectすればよいのでしょうか?
どなたかご教授願います。
> そのような場合、DeleteObjectする必要があるのですが、OnCtlColorの段階ではまだ
消
> せません。
OnCtlColorでCreateSolidBrushしているが、そのブラシを使用するのは別の所なので、
CreateSolidBrushしている場所ではDeleteObjectできないということでしょうか?
それでしたら、OnCtlColorではフラグを立てるだけにして、ブラシを使用する前にその
フラグを検査して、フラグが立っていたら、ブラシを作ればよろしいのでは。
すみません。
OnCtlColorが描画前というのはわかるのですが、それ以降、どのようにMFCで処理がなさ
れていくのかがわかりません。
ブラシが使われるタイミングというのはどのタイミングなのでしょうか?
その関数かなにかをオーバーライドかなにかすればできるのでしょうか?
もし、引き渡したbrushがセレクト状態で削除できないと言うのであれば、
ポインタ変数を二つ用意しておいて以下のようにしてはいかがでしょう。
どちらが使用中なのかわかるステータス変数を用意します。
最初はどちらも使っていない状態にしておきます。
どちらも使っていない時は、ポインタ変数1でbrushを作成して
そのハンドルを返します。この時、ステータスをポインタ1使用中にします。
次に色を変更する時にポインタ変数2でbrushをnew。
そのbrushでCreateし、こちらのbrushのハンドルを
返します。この時、ステータスをポインタ2使用中にします。
以降は、色の変更が行われる度にステータスをチェックして使われていない方の
ポインタ変数をDeleteObjectしてCreate。ハンドル返却とステータスの更新を
行ないます。
利用されていない方のポインタ変数のNULLチェックで処理を分ければ、
同じ流れで二回目の変更とそれ以降は処理できるはず。
最終的に終了時に使用中のポインタ変数の方をDeleteObjectして
両方のポインタ変数をdeleteで開放する。
ポインタ変数を使わなくても実体にしておいてCreateしたかどうかフラグで
管理しても良いかもしれません。
次のブラシが設定された後なら前のブラシは非選択状態になっていると
思われるのでDeleteObjectできるのではないかと思います。
基、
> 最終的に終了時に使用中のポインタ変数の方をDeleteObjectして
> 両方のポインタ変数をdeleteで開放する。
これ間違ってました。
終了時は両方のポインタに対してNULLチェックを行ない、
NULLでなければ、DeleteObjectした後にdeleteしてNULLクリアですね。
まあ、両方とも非選択状態ならいきなりdeleteしても開放されるとは
思いますけれど、この辺は気持ちの問題になるかなぁ。
初心者ですみません、
>ポインタ変数1でbrushを作成して
とは
CBrush* m_hbr1; // エディット コントロールの背景色用メンバ変数
m_hbr1 = new CBrush(m_color);
のようでいいでしょうか?
また、この場合、DeleteでNULLとならないのですが、どのようにすればNULL判定できま
すか?
以下、ステータスで切り替えてやってみたソースです。
おかしいところが多々あると思いますが、ご指摘いただけると助かります。
HBRUSH w_hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
switch (b_sts){
case 0:
case 1:
if(m_hbr1 == NULL){
m_hbr1 = new CBrush(m_color);
SelectObject((HDC)pDC->GetSafeHdc(), (HBRUSH)m_hbr1);
w_hbr = (HBRUSH)m_hbr1->GetSafeHandle();
DeleteObject(m_hbr2);
m_hbr2 = NULL;
b_sts = 2;
}
break;
case 2:
if(m_hbr2 == NULL){
m_hbr2 = new CBrush(m_color);
SelectObject((HDC)pDC->GetSafeHdc(), (HBRUSH)m_hbr2->GetSafeHandle
());
w_hbr = (HBRUSH)m_hbr2;
DeleteObject(m_hbr1);
m_hbr1 = NULL;
b_sts = 1;
}
break;
default:
b_sts = 0;
break;
}
return w_hbr;
ん?
「OnCtlColor」の処理で困っているのは、エディット コントロールだけですか?
リッチエディットは使ったことないですか?
使ったことがあるのならリッチエディットを薦めます。
すみません。
STATICコントロールでした。
記述忘れてました。I/Oチェックのランプのような感じで使用したいと思っていました。
>STATICコントロールでした。
>記述忘れてました。I/Oチェックのランプのような感じで使用したいと思っていまし
た。
うーーん、
となると、ピクチャーコントロールを使って直接描くぐらいしか
今は思いつかないですね。
または、ボタンをその数だけ並べてすべてオーナードロー?
それもかなりしんどいですよね。
OnCtlColor()で背景に設定するHBRUSHのSelectObject()必要ですか?
Win32SDKでプロパティシートで使ったものを組んだことがありますが…
WM_CTLCOLOR(実際はスタティックコントロールでしたのでWM_CTLCOLORSTATIC)の戻り値に
HBRUSHを返却しています。
次回WM_CTLCOLORが通知された際にDeleteObject()していますが、TRUEが返却されていま
すので成功している…かと。
# ちなみに、スタティックコントロールで文字も表示しているので…SetBkColor()も実行
してます。
ちなみに、作成したHBRUSHはグローバル変数で持たせています。
# プロパティシートを閉じるとき(ダイアログを閉じるとき)にDeleteObject()しています。
え~と…
>記述忘れてました。I/Oチェックのランプのような感じで使用したいと思っていました。
この状態が変わるのはどこ…でしょう?
状態が変わった際に、スタティックコントロールが再描画されるようにしていますか?
# CStatic::Invalidate()とかCStatic::RedrawWindow()とかCStatic::UpdateWindow()とか…
# CStatic::Invalidate()かCStatic::RedrawWindow()から背景の再描画フラグも必要で
しょう。
ダイアログにはそのスタティックコントロール用の背景ブラシとしてメンバ変数を作成、
初期化しておきます。
状態変更がダイアログ内のコントロールの操作(ボタン押すとか何か選択した等)ならば、
その時にCreateSolidBrush()でメンバ変数のCBrushを更新する。
ダイアログの操作ではなく、外部で状態変更されるのならばOnCtlColor()内で状態を参照
してCreateSolidBrush()で作成することになるかと。
# CBrush::DeeteObject()で削除してからCBrush::CreateSolidBrush()で作成。
OnCtlColor()では作成済みの背景ブラシを戻り値として渡す。
メンバ変数ならばダイアログクラスのデストラクタ実行時にCBrushのデストラクタで
DeleteObject()されるかと。
回答いただいた方ありがとうございます。
>記述忘れてました。I/Oチェックのランプのような感じで使用したいと思っていまし
た。
のタイミングですが、100msタイマーでI/Oをチェックし、ONならON色を、OFFならOFF色
を返却する仕組みにしています。
CBrush* m_hbr1;
CBrush* m_hbr2;//メンバ変数
m_hbr1 = NULL;
m_hbr2 = NULL;
I/Oチェックでフラグを立てるのとInvalidate(FALSE)は、OnTimer内でやっています。
あとはOnCtlClrでフラグをみてブラシの切り替えをおこなっています。
上記のようにやると100k/1sぐらいでメモリが増えていきます。
すみません、
CBrush* m_hbr1;
CBrush* m_hbr2;//メンバ変数
はダイアログクラスのヘッダー内、
m_hbr1 = NULL;
m_hbr2 = NULL;
はコンストラクタ内です。
えーと、まずはDeleteObjectをやっている所で失敗しているかどうかを
ちゃんと確認する必要があると思いますよ。
今の書き込みの内容だとちゃんと裏づけが取られていないような感じです。
状況だけを見て判断してはいけないと思います。
DeleteObjectで成功しているのであれば、
他に原因があると言う事になると思います。
あと、ポインタ変数に関しては自分で管理し無いと駄目ですよ。
まず、クラスの初期化時にNULLクリアしておくのは基本として
deleteしたら、プログラマの責任でNULLクリアします。
これによって開放済みの領域の二重開放等を防ぎます。
ブラシのインスタンス作成に関しては、
new CBrush();して、その後でCreateSolidBrushしても良いし、
この辺は目的がきちんと達成できるならそれでよろしいかと。
私があげているのはあくまでもDeleteObjectしようとした時に
開放したいブラシオブジェクトがまだ選択状態になっていて
DeleteObjectに失敗している状況を想定しています。
そもそもDeleteObjectに失敗している事が確認できていないなら
方法論も何も無いので、失敗している事の確認がまず第一です。