エディットボックスの表示がうまくいかない – プログラミング – Home

エディットボックスの表示がうまくいかな...
 
通知
すべてクリア

[解決済] エディットボックスの表示がうまくいかない

固定ページ 1 / 2

まに
 まに
(@まに)
ゲスト
結合: 18年前
投稿: 78
Topic starter  

お世話になります。
VC++2005で、ダイアログ形式のソフトを作成しています。
ダイアログ全体に画像が表示され、その画像と重なるようにして、
エディットボックスが表示されたり、消えたりする。
そんなソフトを作成しています。
そこで、現在困っていることが、2つあります。

●その1
エディットボックスに全角文字を入力すると、
入力した文字以外、エディットボックスが消えてしまう。

「消えてしまう」というより、描画した画像で隠されてしまうのだと思います。
入力中の文字だけが、画面に表示されるような状態で、
変換確定した文字や、エディットボックスの周囲も、隠されてしまいます。

OnPaintでエディットボックスの再描画を行えば解決するかと思いますが、
再描画の方法が分かりません。
以下、OnPaintの抜粋です。

void CTest1Dlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 描画のデバイス コンテキスト

SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>
(dc.GetSafeHdc()), 0);

// クライアントの四角形領域内の中央
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;

// アイコンの描画
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
CClientDC myDC(this);
ViewPaint(&myDC); // ダイアログ全体へ画像を表示

// ここでエディットボックスを再描画すればいいはず?
}
}

●その2
エディットボックスをいったん非表示にすると、キャレットが表示されなくなる。

エディットボックスの表示/非表示を、
「ShowWindow(SW_SHOW)」、
「ShowWindow(SW_HIDE)」
を使って切り替えているのですが、
一度非表示にして、再度表示させると、以降、
エディットボックスのキャレットが表示されなくなってしまいます。

上記2点の解決方法をご存知でしたら、
ご教授いただけましたら幸いです。


引用未解決
トピックタグ
ISLe
 ISLe
(@ISLe)
ゲスト
結合: 18年前
投稿: 38
 

●その1
OnEraseBkgnd
で画像を描画してやればいいかもしれない。


返信引用
金魚ちゃん
 金魚ちゃん
(@金魚ちゃん)
ゲスト
結合: 16年前
投稿: 52
 

>一度非表示にして、再度表示させると、以降、
>エディットボックスのキャレットが表示されなくなってしまいます。
キーボードのフォーカスが外れるからじゃないの。
だから SW_SHOW したときに、エディットボックスにフォーカスを設定。


返信引用
まに
 まに
(@まに)
ゲスト
結合: 18年前
投稿: 78
Topic starter  

追加情報です。
その1、その2ともに、いったん別のソフトのウィンドウで隠してから、
再度表示させると、ちゃんとした表示になります。

> OnEraseBkgndで画像を描画してやればいいかもしれない。
以下のような使い方で会ってますでしょうか…?
やってみましたが、うまくいきませんでした。
OnPaintやViewPaintとの順番も、いろいろと変えてみたのですが…

void CTest1Dlg::OnPaint()
{
if (IsIconic())
{
…中略…
}
else
{
CDialog::OnPaint();
CClientDC myDC(this);
ViewPaint(&myDC); // ダイアログ全体へ画像を表示
OnEraseBkgnd(&myDC);

// ここでエディットボックスを再描画すればいいはず?
}
}

> キーボードのフォーカスが外れるからじゃないの。
フォーカスの設定は、もちろんしています。
それでもキャレットが表示されませんでした。

「その2」ですが、一応、解決しました。

ダイアログには、エディットボックス以外のコントロールを
一つも配置してなかったのですが、
ダミーのボタンコントロールを追加したら、
「その2」は再現されなくなりました。

推測ですが、エディットボックスしかコントロールがないため、
そのエディットボックスを非表示にしたことで、
フォーカスのやり場が失われてしまい、
そのために再現していたのでは…と考えています。

昨日、書き込みした時点では気付かなかったのですが、
エディットボックスを再表示させた後、
「エディットボックス内の文字列が勝手に選択状態になる」
という現象も起こってたようです。

また、ダミーのボタンコントロールも、TabStopプロパティやVisibleプロパティを
FALSEにすると、再現するようになります。
その場合は、コード上でフォーカスをセットすることで、再現されなくなりました。
(以下のソースの①の部分)

BOOL CTestDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_KEYDOWN) {

CEdit* myEdit1 = (CEdit*)GetDlgItem(IDC_EDIT1);
CButton* myButton1 = (CButton*)GetDlgItem(IDC_BUTTON3);
static bool VisibleFlg = TRUE;
short c = (short)pMsg->wParam;

// F2キーでエディットボックスの表示/非表示を切り替え
if (c == VK_F2) {
VisibleFlg = !VisibleFlg;
if (!VisibleFlg) {
myButton1->SetFocus(); // ←①
myEdit1->ShowWindow(SW_HIDE);
}
else {
myEdit1->ShowWindow(SW_SHOW);
myEdit1->SetFocus();
}
}

}

return CDialog::PreTranslateMessage(pMsg);
}

ただ、「一応、解決した」と書いたのは、
できればダミーのボタンコントロールを追加しないで解決させたいからです。
(そんなふうに考えるのは自分だけでしょうか…?)


返信引用
まに
 まに
(@まに)
ゲスト
結合: 18年前
投稿: 78
Topic starter  

「その2」に関する質問です。
ダイアログ上に、コントロールが一つもない状態の時って、
フォーカスはどこに設定されているのでしょうか?

「a) どこにもフォーカスされてない」のか、
「b) ダイアログ自体が、フォーカスを持っている」かの、
どちらかだと思いますが………

ちなみに、PreTranslateMessage関数内で、
this->GetFocus()で取得したアドレスを調べたところ、
NULLではありませんでした。

フォーカスを、その状態(aまたはbの状態)にすれば、
ダミーのボタンコントロールを配置しなくて済むと思っているのですが、
そのようなことって、出来ないものでしょうか?


返信引用
ISLe
 ISLe
(@ISLe)
ゲスト
結合: 18年前
投稿: 38
 

OnEraseBkgndを呼び出すんじゃなくて、void CTest1Dlg::OnEraseBkgnd()をオーバーラ
イドしてその中で画像を描画したらどうかということです。
OnEraseBkgndというのはウィンドウメッセージWM_ERACEBKGNDのメッセージハンドラのこ
とです。
#ダイアログだと呼ばれなかったっけ…?

エディットボックスにフォーカスが移動したときテキストが全選択状態になるのはデフ
ォルトの動作なのでこれもコントロールをオーバーライドしてフォーカスを取得したと
きSetSelメソッドを使うとかEM_SETSELメッセージを投げるとかして選択状態を解除すれ
ばキャレットが表示されるのではないでしょうか。


返信引用
ISLe
 ISLe
(@ISLe)
ゲスト
結合: 18年前
投稿: 38
 

間違えた
WM_ERASEBKGND
です。


返信引用
まに
 まに
(@まに)
ゲスト
結合: 18年前
投稿: 78
Topic starter  

お世話になります。

> OnEraseBkgndを呼び出すんじゃなくて、void CTest1Dlg::OnEraseBkgnd()を
> オーバーライドしてその中で画像を描画したらどうかということです。

すみません、あまり詳しくないもので…
↓こんな感じってことですね?

BOOL CTest1Dlg::OnEraseBkgnd(CDC* pDC)
{
CClientDC myDC(this);
myDC.BitBlt(0,0,500,500,&DcView,0,0,SRCCOPY);
return CDialog::OnEraseBkgnd(pDC);
}

OnPaintの中で描画した時と、微妙に
挙動(入力済みの文字が消えるタイミング)が変化しましたが、
現象は改善されませんでした。
また、プログラム起動時に画像が描画されなくなりました。

なお、エディットボックスの周囲だけでなく、
「他のコントロールも、描画した画像に隠されてしまう」
ということが新たに判明しました。

VC++2005に、VBのRefreshメソッドみたいなのがあれば
いいんだけどな~って、思っているのですが………
ありませんか………?

> コントロールをオーバーライドしてフォーカスを取得したと
> きSetSelメソッドを使うとかEM_SETSELメッセージを投げるとかして
> 選択状態を解除すればキャレットが表示されるのではないでしょうか。

以下のように、いろんなタイミングでSetSelを実行してみました。
「エディットボックス内の文字列が勝手に選択状態になる」
という現象は回避できるようになりましたが、
「キャレットが表示されなくなる」という現象は、改善できませんでした。
「EM_SETSELメッセージを投げる」については、詳しくないのでまだ試していません。
必要でしたら、調査して試してみるつもりでいます。

BOOL CTest1Dlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_KEYDOWN) {
static bool VisibleFlg = TRUE;
short c = (short)pMsg->wParam;

if (c == VK_F2) {
VisibleFlg = !VisibleFlg;
if (!VisibleFlg) {
m_Edit1.SetSel(0,0);
m_Edit1.ShowWindow(SW_HIDE);
}
else {
m_Edit1.ShowWindow(SW_SHOW);
m_Edit1.SetSel(0,0);
m_Edit1.SetFocus();
}
}

}
return CDialog::PreTranslateMessage(pMsg);
}

void CTest1Dlg::OnEnSetfocusEdit1()
{
m_Edit1.SetSel(0,0);
}

エディットボックスコントロールのDisableを、
プログラム上で切り替えできれば改善されるかも…?
と考えているのですが、そんなことって、できないものでしょうか…?

以上、報告でした。


返信引用
ISLe
 ISLe
(@ISLe)
ゲスト
結合: 18年前
投稿: 38
 

> VC++2005に、VBのRefreshメソッドみたいなのがあれば

UpdateWindowというのがそのまんまですが、メッセージハンドラの実装ができていない
現状で期待する結果は得られないでしょう。

根本的にウィンドウメッセージやデバイスコンテキストについての理解が足りていない
と思います。
ClientDC myDC(this);
ではなくハンドラの引数として与えられたデバイスコンテキストを使ってください。
最初の投稿を見直したらOnPaintでBeginPaint/EndPaintを使ってなかったですね。

エディットコントロールはオリジナルの挙動を変えたいならCEditを継承して独自のエデ
ィットコントロールにカスタマイズしたほうが良いと思います。
外からメソッドを呼び出して戻ったとき状態が変化しているとは限らないです。
特にフォーカスに関してはややこしいことが多いですから。


返信引用
まに
 まに
(@まに)
ゲスト
結合: 18年前
投稿: 78
Topic starter  

ISLeさん、ありがとうございます。

「その1」ですが、解決しました。
解決前と解決後のコードを、以下に記載します。

void CTest1Dlg::OnPaint()
{
if (IsIconic())
{
…中略…
}
else
{
// 解決前
// CDialog::OnPaint();
// CClientDC myDC(this);
// ViewPaint(&myDC); // ダイアログ全体へ画像を表示

// 解決後
CPaintDC myDC(this);
main.ViewPaint(&myDC); // ダイアログ全体へ画像を表示
CDialog::OnPaint();
}
}

「CClientDC」を、「CPaintDC」へ変更しました。
また、「CDialog::OnPaint();」を呼ぶ順番も、変更しました。
そうしないと、エディットボックスの横幅を超えて全角文字を入力したために
入力文字がエディットボックスの左下にはみ出て表示された時、
はみ出た部分に、画像が描画されなくなる現象が発生するようです。

> 最初の投稿を見直したらOnPaintでBeginPaint/EndPaintを使ってなかったですね。
BeginPaint/EndPaintは、手持ちの参考書にも載ってなかったのですが、
使わないとマズイのでしょうか…?
すみませんが、そこだけでもご教授ください。<(_ _)>

他のスレで、勉強方法についてデカい口を叩いてはおりますが、
「自分自身、きちんと理解しているのか?」と問われると、
ご指摘のように、自信のない部分があります。
現状、それでもそれなりのものは作れてる自負はあるので、
「まっいっか」で通しちゃってますが…。

なので、一応解決したとはいえ、「CPaintDC」と「CClientDC」の違いさえ、
分かってなかったりします。(「CDC」クラスの派生クラスなんだ~」ぐらいしか…)
というか、ヘルプの活用方法自体、分かってない状態なんです。

そんなわけで、「本に書いてあることはできるけど、
それ以上のことはなかなか出来ない」というのが、現状です。
本当は、きっちり勉強した方がいいのかも…と、不安に思っているのですが、
「とにかく作るのが先決!マズい部分は後で直そう!」という方針で、
勉強を後回しにしちゃっている状態です。(もしかして、危険でしょうか…?)

とりあえず、「その1」が年内に解決できて本当によかったです。
ISLeさん、本当にありがとうございました。

「その2」は、できればダミーのボタンコントロールを配置しないで
解決させたいので、引き続きアドバイスをお待ちします。
「勉強しろ!」と言われれば、それまでですが…


返信引用
ISLe
 ISLe
(@ISLe)
ゲスト
結合: 18年前
投稿: 38
 

MSDNライブラリでCPaintDCの解説を見ると

> 構築時に CWnd::BeginPaint 関数を実行し、破棄時に CWnd::EndPaint 関数を実行し
ます。

とあります。
http://msdn.microsoft.com/ja-jp/library/a48eab8d.aspx

わたしはMFCを使わないのでCPaintDCまでは行き着かなかったです。
が、効用を見る限りOnPaintの中ではCPaintDCを使うのが必須でしょう。

> また、「CDialog::OnPaint();」を呼ぶ順番も、変更しました。

OnEraseBkgndで背景を描画すれば諸々問題にならないはずなんですが。
BOOL CTest1Dlg::OnEraseBkgnd(CDC* pDC)のpDCに描画してもダメですか?

> 「その2」は、できればダミーのボタンコントロールを配置しないで
> 解決させたいので、引き続きアドバイスをお待ちします。

とりあえずで良ければ、リードオンリーにしてメインダイアログの外(見えないところ)
に移動するというのはいかがでしょう?


返信引用
maru
 maru
(@maru)
ゲスト
結合: 17年前
投稿: 358
 

> 「その2」は、できればダミーのボタンコントロールを配置しないで
> 解決させたいので、引き続きアドバイスをお待ちします。

だ~か~ら~、金魚ちゃん さんのいう通り
> キーボードのフォーカスが外れるからじゃないの。
> だから SW_SHOW したときに、エディットボックスにフォーカスを設定。
だけじゃないの。


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

> 本当は、きっちり勉強した方がいいのかも…と、不安に思っているのですが、
> 「とにかく作るのが先決!マズい部分は後で直そう!」という方針で、
> 勉強を後回しにしちゃっている状態です。(もしかして、危険でしょうか…?)

他の所は皆さんが書かれているので上記の所に反応しておきます。
後回しというのはいつか勉強すると言う意味なので、
いつまで後回しにするの?と言う話になります。
ある程度、形になる物が出来るまではやり方を覚える方法で
やった方が退屈しないので長続きすると言うのは確かなんですが、
やり方が大体わかったのであれば、今度はなんでこうすると動くのか?
とか、このコードは実際にはこう言うことをしているんだとか、
コードのパターンではなくて細かい動作の仕組みとかを覚えた方が良いです。
やり方をパターンで覚えても応用が利きませんからそこで止まってしまいます。
今後のことを考えるのであれば、Windowsの仕組み(どういう流れで動いて
いるのか)をきちんと理解した上でMFCのクラスやメソッドとの関連を
理解するようにした方が良いと思いますよ。
MFCはWindowsの仕組みをうまく使う為のフレームワーク(雛形)を提供して
くれています。このフレームワークを理解して使いこなせるようになると
色々と処理の幅が広がりますよ。


返信引用
たいちう
 たいちう
(@たいちう)
ゲスト
結合: 23年前
投稿: 662
 

> 現状、それでもそれなりのものは作れてる自負はあるので、
> 「まっいっか」で通しちゃってますが…。

作れていないから質問したのでは?
それとも、この質問で作ろうとしているのは、
それなり以上のものに該当するのですか?

PATIOさんがMFCについて触れています。
SDKのプログラムもかじっておくと、MFCの理解も深まりますよ。

# 見下されているように感じたら御容赦を。私も大した実力ではありません。
# 妙な自信を持つよりも、自分に何が欠けているのか冷徹に分析し、
# それを強化することが上達の最良の方法ではないか、という意図です。
#
# 何となく書いてみて「やった動いた!」というレベルは、
# 卒業しているんでしょ?


返信引用
まに
 まに
(@まに)
ゲスト
結合: 18年前
投稿: 78
Topic starter  

> 効用を見る限りOnPaintの中ではCPaintDCを使うのが必須でしょう。

そうなんですね。
実はISLeさんに言われて参考書をもう一度見直したら、
OnPaintの中では「CPaintDC」を使っていたので、
それをマネしたらうまくいった…って感じなんです。

参考書をもう一度よく見直したら、
「CPaintDCはBeginPaint/EndPaintがカプセル化されている」
ということが分かりました。
ただ、それ以上の記述がないので、
「BeginPaint/EndPaintはどんな時にどう使うのか?」とか、
「なんで他の関数内で描画するときはCClientDCを使うのに、
OnPaintの中ではCPaintDCを使うのか?」とか、
疑問に思うことが出てきてしまいました。

「CDialog::OnPaint();」を呼ぶ順番についても、
参考書の中で、OnPaintの最初の方で呼んでたり、
最後の方で呼んでたりと記述がマチマチで、
「いったいどっちが正しい順番なんだろう?」って、疑問に思っています。
なんでこんなにややこしいんでしょう…?

> BOOL CTest1Dlg::OnEraseBkgnd(CDC* pDC)のpDCに描画してもダメですか?

「OnEraseBkgnd」のpDCに描画しても、うまくいきました。
ただし、その場合はデフォルトのコードの「return CDialog::OnEraseBkgnd(pDC);」を
コメントアウトして「return TRUE;」としないと、描画しても消えてしまうようです。

> とりあえずで良ければ、リードオンリーにしてメインダイアログの外
> (見えないところ)に移動するというのはいかがでしょう?

この方法は思いつきませんでした!この方法でしのぎます。
ありがとうございます。

> だ~か~ら~、金魚ちゃん さんのいう通り
> > キーボードのフォーカスが外れるからじゃないの。
> > だから SW_SHOW したときに、エディットボックスにフォーカスを設定。
> だけじゃないの。

いえ、そんな汎ミスじゃありません。(><)
入力だってちゃんとできますから。
なのにキャレットだけが表示されなかったんです。

> 作れていないから質問したのでは?
> それとも、この質問で作ろうとしているのは、
> それなり以上のものに該当するのですか?

自分としては、今回質問させていただいたことは、
「それなり」の範疇に含まれるつもりでいました。
「画像表示」も「エディットボックスの操作」も「コントロールの表示/非表示」も、
すべて手持ちの参考書に載っていることで、
自分としては、(しくみは理解してないけど)「できるはず」だと思っていました。
にもかかわらず、これらを組み合わせると、なぜかできない。
なので助けを求めさせていただきました。
「でも、実際、作れてないってことなんだろ?」と言われれば、
返す言葉がないのですが………

> コードのパターンではなくて細かい動作の仕組みとかを覚えた方が良いです。

> # 妙な自信を持つよりも、自分に何が欠けているのか冷徹に分析し、
> # それを強化することが上達の最良の方法ではないか、という意図です。

はい、そうですね。
参考書に書かれていることは一通りマスターした気でいましたが、
「それだけでは足りない」「しくみをきちんと理解してない」という点は、
つくづく実感しました。

今は、自分の中の優先度的に勉強を後回しにしてますが、
「いよいよ勉強が必要!」と感じた時は、勉強を始めます。
その時には、お勧めの本などをお聞きするかもしれませんが、
よろしくお願いします。


返信引用
固定ページ 1 / 2

返信する

投稿者名

投稿者メールアドレス

タイトル *

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