StringGridに描画したボタンのキャプションを設定するには?


山田  2014-01-10 19:52:21  No: 45821

こんにちは。

いつもお世話になっています。
開発環境は、delphiXE3 enterprise(update2適用)、win7(sp1)です。

StringGridのDrawCellイベントにStringGridにボタンを描画するようにプログラムしています。

使っている関数は、DrawFrameControlで以下のように書いています。

DrawFrameControl(Canvas.Handle,Rect,DFC_BUTTON,DFCS_BUTTONPUSH);

やりたいことは、ボタンのキャプションを設定したいということです。

現在、DrawFrameControlの関数しか書いていないので、ボタンのキャプションは空白になっています。

描画したボタンにキャプションを設定するにはどうすれば良いのでしょうか。

教えてください。

よろしくお願いします。


igy  2014-01-10 20:04:23  No: 45822

ボタンを描画した後、CanvasのTextOutとか、Windows APIのDrawTextを使うのは、いかがですか?


山田  2014-01-10 22:35:34  No: 45823

DrawTextを使ってみたら上手く書けました。

ただStringGrid自体、行選択して選択行は青色反転しているんですが、それが描画したボタンにも反映してて。

文字の背景色が青色になっているんです。

そのため変な感じになっていて。

ボタンは灰色なんですが、ボタンのキャプションの背景色が青色なんです。

描画したボタンの背景色も灰色(?ボタン色)にする方法はあるのでしょうか?

教えてください。

よろしくお願いします。


deldel  2014-01-10 23:59:44  No: 45824

DrawCellイベントの中でRectを用いてCanvasの一部に色を塗ればできそうですが、
以下のようにボタンを直に貼り付けるほうが楽チンかなぁとも思いますが、
どうでしょ?

  Button1.Parent := StringGrid1;
  Button1.Left := (StringGrid1.ColWidths[0] + 1) * 2;
  Button1.Top := (StringGrid1.RowHeights[0] + 1) * 2;
  Button1.Width := StringGrid1.ColWidths[1] div 2;
  Button1.Height := StringGrid1.RowHeights[1];


Mr.XRAY  2014-01-11 04:37:59  No: 45825

>ただStringGrid自体、行選択して選択行は青色反転しているんですが、それが描画したボタンにも反映してて。

>文字の背景色が青色になっているんです。

どういうコードかは分かりませんが,そうなるようなコードになっているんだと思いますよ.
したがって,

>そのため変な感じになっていて。

別に「変な感じ」じゃないと思いますけど.
セルにボタンを描画しているのですから,そのセルを判定して

Canvas.Font.Color := clRed;

のようにすれば,指定の色になると思いますよ.
このことは,どんな Canvas に描画する時も同じです.
前の設定のままであればその設定で描画されます.
部分的に設定を変えたいのであれば,その部分を判定して設定を変更しなければ前のままです.

例えば,以下の図では,チェックボックスを配置しているセルの文字列の色を変えています.
http://mrxray.on.coocan.jp/Delphi/plSamples/050_TStringGrid_OnDrawCell.htm#fig58


igy  2014-01-11 07:14:12  No: 45826

効果ないかもしれませんが、
DrawTextの前に、
StringGrid1.Canvas.Brush.Style := bsClear;
DrawTextの後に、
StringGrid1.Canvas.Brush.Style := bsSolid;
と記載したらどうなりますか?


Mr.XRAY  2014-01-11 07:57:33  No: 45827

>と記載したらどうなりますか?

文字の背景がどうのこうのと書いてありましたから,
これかも知れませんね.


DEKO  2014-01-12 08:22:06  No: 45828

SetBkMode() を使って背景色を TRANSPARENT にしてみては?
http://ht-deko.minim.ne.jp/tech001.html#tech001

# 外していたらゴメンナサイ。


山田  2014-01-13 04:16:55  No: 45829

こんにちは。

StringGrid1.Canvas.Brush.Style := bsClear;
StringGrid1.Canvas.Brush.Style := bsSolid
Canvas.Font.Color := clRed;

を参考にやってみたら上手く表示できました。

ありがとうございました。

実はdeldelさんから教えていただいた方法も試してはいたんです。
でも、何か非常に不安定で。

Stringgridの選択行を変えると、ボタンが消えたりしてたんです。
そこでselectcellにrefreshを書いたらパラパラとはなりますが表示は出来ていました。

でも、stringgridの上に抽出条件をpagecontrolを貼って指定できるように指定できるようにしているんですが、pagecontrolのタブ切り替えでpagecontrolに貼っているラベルが消えたりしていました。

もっと酷いのは、pagecontrolに貼った項目指定ボタン押下で、サブ画面を表示して抽出条件の項目に値を入れることが出来るようにしてるんですが、初回に抽出してStringgridにデータを表示した後再度項目指定ボタンを押してもサブ画面が表示できなくなっていました。

ちなみにサブ画面もボタンをcreateしてボタンを表示しています。

stringgridに動的にcreateしたボタンを表示していた場合上記のような不安定な動きになります。

タブを切り替えるときとボタンを押したとき、stringgridをクリアすれば動きが安定はするんですが、タブのときはともかく、項目指定のボタンを押したときstringgridはクリアしたくありません。

ちなみにcreateしたボタンはstringgridクリアのとき破棄しています。
もちろん、画面終了時も破棄しています。

僕は、ボタンをcreateしているため不安定になっているんだろうと思っています。

これって解消できるんでしょうか。

上司に相談したら、なるべくならdeldelさんがお話しされていた方法が良いと言っていたんですが。

僕は不安定なんで、ボタンを描画の方を選択したいと考えています。

よろしくお願いします。


igy  2014-01-13 20:12:31  No: 45830

>実はdeldelさんから教えていただいた方法も試してはいたんです。
>でも、何か非常に不安定で。
>(中略)
>僕は、ボタンをcreateしているため不安定になっているんだろうと思っています。
>
>これって解消できるんでしょうか。

対象部分のソースコードが書かれていないため、どの部分が悪いのでは?などと言えないですが、
問題を切り分け、原因を特定していくのがよいと思います。


deldel  2014-01-14 19:08:12  No: 45831

設計時に設けたButtonを移動させていますが、
同じようにボタンが消えたようになりますね・・・
グリッドのRefreshを行うと現れますが、
スクロールだけだとだめですね。
DrawCellイベントでボタンのRefreshをやってみると
ソフトが固まりますし・・・
こういうやり方はだめなのかも知れません・・・。


山田  2014-01-14 20:00:21  No: 45832

こんにちは。

ソースは非常に多いので書き込むことは出来ないですが、おおまかに言うと以下のような感じです。

画面1(親画面)

private宣言
objButton:array of Tbitbtn;

抽出ボタンクリックイベント
stringgridにデータをセットしつつ、stringgridの6列目と7列目に、ボタンをcreateして配列objButtonにセットして、表示

formcloseイベント
objButtonを全件ループして、destroy

画面2(子画面)

private宣言
objButton1:array of Tbitbtn;

showイベント
ボタンをcreateして配列objButton1にセットして、表示

formcloseイベント
objButtonを全件ループして、destroy

親画面から子画面をshowmodal表示させているんですが、子画面を1回目表示させて閉じて、再度子画面を表示させようとすると子画面が表示できません。

このことは、stringgridにデータセットされているとき、この現象が現れます。

stringgridにデータセットされていないときは起こりません。

で、アプリ起動時に各画面のボタンcreateして画面終了時はdestroyせず、アプリ終了時destroyさせようと考えています。

他に思いつかないのですが、他に打開策はあるでしょうか。

よろしくお願いします。


Mr.XRAY  2014-01-16 23:25:33  No: 45833

>deldel 2014/01/10(金) 14:59:44

>以下のようにボタンを直に貼り付けるほうが楽チンかなぁとも思いますが、
>どうでしょ?

へのレスです.
これはグッドアイディアですね.
ただし,最初の質問の文章では不明ですが,この後の 2014/01/14(火) 11:00:21 で

>...6列目と7列目....

と書いています.つまり列全体ということになります.
すると,その例の行全体にボタンを生成して表示というか,配置することになります.
これは,結構面倒です.
というのは,TStringGrid をスクロールさせると,その表示ボタンも,行に応じたボタンを
表示しなければなりません.

しかし,TStringGrid はコンテナコントロールではありません.
コンテナコントロールとは,TPanel のように,そのコントロール上に他のコントロールを配置
できるコントロールです.
TStringGrid 上に表示したボタンは,正確には「TStringGrid の上に乗っている」わけではありません.
したがって,スクロールしても,ボタンの再描画は行われません.
OnDrawCell イベントは発生しません.

おそらく,TStringGrid の継承クラスを作成して,それを利用する方法しかないような気がします.
あるいは,サブクラス化でしょうか.
今回のケースでは,素直に,セルにボタンを表示して配置するのではなく,
セルにボタンを描画する方法がいいのではないかと思っています.

質問された方は,他にもいろいろやっているようですし.

>ソースは非常に多いので書き込むことは出来ないですが、

と書いていますので,具体的な対応策を考えることはできませんね.
もっとも,何千行も何万行もある(?)コードを示されても読み気はしませんが(笑)


igy  2014-01-17 05:35:07  No: 45834

>ソースは非常に多いので書き込むことは出来ないですが、おおまかに言うと以下のような感じです。

ここに書かれたような仕様の単体のプログラムを作ってみて、
同じ現象が出るか、試してみるのもよいかもしれません。

現象が出れば、問題の切り分けがしやすいかと・・・


山田  2014-01-30 19:52:27  No: 45835

遅くなりまして申し訳ございません。

やっと問題の切り分けができました!

結局ボタンはcreateしたものを表示しているのではなく、OnDrawCellでボタンを描画して対応しました。

現在showmodalしている子画面が出なかったり、メッセージボックスが出なかったりしています。

これはcreateしたボタンのせいではなかったです。
Application.ProcessMessagesのような気がしています。

「データ読み込み関数」

(データがある場合)
showmodal
(データがない場合)
メッセージボックス

データ読み込み関数は、DBをselectしている関数で、読み込み中プログレスバーを表示している画面を表示しているため、データ読み込みのループ中Application.ProcessMessagesを使っています。
プログレスバーを表示している画面に「中止」ボタンを貼り付けているんですが、この「中止」ボタンを機能させるため、Application.ProcessMessagesを使っています。

このApplication.ProcessMessagesが問題のように思えて、これを書いているため、showmodalしている子画面が出なかったり、メッセージボックスが出なかったりするのではと思っています。

そもそもこのような事例はあるのでしょうか?

あるのであれば回避法を教えていただけないでしょうか?

よろしくお願いします。


igy  2014-01-30 21:44:08  No: 45836

>このApplication.ProcessMessagesが問題のように思えて、これを書いているため、showmodalしている子画面が出なかったり、メッセージボックスが出なかったりするのではと思っています。

ちなみに、Application.ProcessMessagesを使わない場合、問題は出でませんか?


山田  2014-01-30 22:29:44  No: 45837

問題はなくなりますが、プログレスバーを表示している画面の「中止」ボタンが機能しなくなります。


Mr.XRAY  2014-01-30 23:04:05  No: 45838

そのプログレスバーの処理に相当する部分,
またはプログレスバーの処理部分をスレッドにしてみたらどうでしょうか.
Delphi XE3 であれば,CreateAnonymousThread と無名メソッドを使用すると便利です.

本当は

>ここに書かれたような仕様の単体のプログラムを作ってみて、
>同じ現象が出るか、試してみるのもよいかもしれません。

のように,そのテスト用のコードがあれば,もっと早く解決への道が開かれたかも知れません.


山田  2014-01-31 01:48:35  No: 45839

こんにちは。

スレッドですか。
僕はvb出身で、スレッドとは遠ざかっていて苦手意識があったんですが、
教えていただいた無名スレッドは簡単そうで、僕にも何とかなりそうです。

実は他にもスレッドが必要かもと思う箇所があったので、この部分にも
適用できるような気がしてきました。

いろいろ教えていただき有難うございました。

結果は後日になるかもですが報告します。

ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加