- PR -

フォーム表示時のピクチャボックス描画

1
投稿者投稿内容
shin2
ベテラン
会議室デビュー日: 2004/03/10
投稿数: 58
投稿日時: 2008-07-17 15:25
非常に初歩的なところの質問でスミマセンが、どなたか教えてください。

フォームにピクチャボックス(picArea)を配置して、フォームロード時にこのピクチャボックスに四角を書きたいと考えています。以下のようなソースでやってみたのですが、四角を書いた直後に、四角が消えてしまいます。どこが悪いのでしょうか?

public class MainForm : Form
{
System.Drawing.Graphics g;
System.Drawing.Pen p;
public MainForm()
{
g = picArea.CreateGraphics();
p = new Pen(Color.Blue, 1);
}
private void MainForm_Load(object sender, EventArgs e)
{
g.DrawRectangle(p, 10, 20, 100, 80);
}
}

このソースだと、フォームの大きさを変えると四角が表示されます。
よろしくお願いします。
くまっち
大ベテラン
会議室デビュー日: 2008/01/18
投稿数: 169
お住まい・勤務地: 茨城県のどこか。
投稿日時: 2008-07-17 19:04
過去ログを探せば、描画関係のスレッドが幾つも見つかります。
似たような質問もあったはず・・・。

描画はOnPaintをオーバーライドして
その中で描画しましょう。

画面の描画(再描画)が必要な時にはOnPaintが呼ばれます。

[追記]
ぁ・・・。継承しないなら、Paintイベントにハンドラを登録して
そのイベントハンドラ内で描画すれば良いかと。

[ メッセージ編集済み 編集者: くまっち 編集日時 2008-07-17 19:11 ]
shin2
ベテラン
会議室デビュー日: 2004/03/10
投稿数: 58
投稿日時: 2008-07-17 21:23
くまっちさん、ありがとうございます
OnPaintのオーバーライドを以下のように組み込んでみました。

public class MainForm : Form
{
System.Drawing.Graphics g;
System.Drawing.Pen p;
public MainForm()
{
g = picArea.CreateGraphics();
p = new Pen(Color.Blue, 1);
}
protected override void OnPaint(PaintEventArgs e)
{
p = new System.Drawing.Pen(System.Drawing.Color.Blue, 1);
g.DrawRectangle(p, 10, 20, 100, 80);
}
}

このコードを実行すると、OnPaintに処理が移ります。確かに何かを書こうとします。
興味深いのは最初にフォームに青い四角を描いて、そのあとにピクチャボックスを書いています。結果何も書いていないという状況に変わりはありませんでした。つまり

四角を描く→ピクチャボックス表示(結果何も書かれていない)

というわけです。そもそもなぜ上記のような処理をするのかわかりません。ピクチャボックスに四角を描くのは

ピクチャボックス表示→四角を描く

となっているはずだと思っているのですが、何か根本的に間違っているのでしょうか?
かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2008-07-17 22:10
OnPaintイベントハンドラに引数である、e.Graphicsに描画を行ってみた?
くまっち
大ベテラン
会議室デビュー日: 2008/01/18
投稿数: 169
お住まい・勤務地: 茨城県のどこか。
投稿日時: 2008-07-17 22:12
私の書き方も、判りにくかったですね。

まず、FormとPictureBoxは各々描画(OnPaint呼出)されます。

Formが描画される際には、Formに含まれる子コントロール(PictureBox等)も
必要があれば描画されます。

つまり描画順を考慮しなければなりません。
Form.OnPaint その後に PictureBox.OnPaintなので
FormのOnPaint段階では上書きされて消されてしまいます。

継承してオーバーライドというのは
PictureBoxを継承してPictureBoxEx(継承したクラス)の
OnPaintで描画するという事です。

で、継承が面倒(わざわざ派生クラスを作りたくない)ならば
PictureBoxのPaintイベントにイベントハンドラを登録して
そのイベントハンドラ内で描画すれば良いという事です。
shin2
ベテラン
会議室デビュー日: 2004/03/10
投稿数: 58
投稿日時: 2008-07-17 22:32
ありがとうございます。

private void picArea_Paint(object sender, PaintEventArgs e)
{
//
}
にイベントハンドラを登録して、そのイベントハンドラ内に描画すればよいとのことですが・・・イベントハンドラをやったことがないので、もう少し教えていただけないでしょうか??
すみませんがよろしくお願いします。
ぴあちゃん
ぬし
会議室デビュー日: 2008/02/07
投稿数: 287
投稿日時: 2008-07-17 22:36
OnPaint はリアルタイムで 10ms で全面書き換えとかゲームでも作らない限り
使わない方が良いです。
PictureBoxには前と後ろの画像データ領域が実装されています。要するに2つの
画像を重ね合わせ表示することが出来るようになっています。利用する側は
前か後ろどちらでもいいからPictureBoxと同じ大きさのBitmapを作成してそれを
プロパティに設定するだけで表示に関する一切の処理はすべてPictureBoxが肩代
わりしてくれます。
OnPaint はどーしても処理が間に合わない場合にだけ実装するようにしましょう。


過去ログやMSDNにもサンプルがあるので見てください。




shin2
ベテラン
会議室デビュー日: 2004/03/10
投稿数: 58
投稿日時: 2008-07-17 22:50
こんな感じでしょうか?
public class MainForm : Form
{
System.Drawing.Graphics g;
System.Drawing.Pen p;
public MainForm()
{
g = picArea.CreateGraphics();
p = new Pen(Color.Blue, 1);
}
private void MainForm_Load(object sender, EventArgs e)
{
MakeGraphics();
}
private void MakeGraphics()
{
picArea.Image = new Bitmap(picArea.Width, picArea.Height);
Graphics gfx = Graphics.FromImage(picArea.Image);
p = new System.Drawing.Pen(System.Drawing.Color.Blue, 1);
gfx.DrawRectangle(p, 10, 20, 100, 80);
}
}

うまくいきました。動作速度も全く問題がありませんでした。
OnPaintについても、私は一つだろうと思っておりましたし、勉強になりました。
ありがとうございました。
1

スキルアップ/キャリアアップ(JOB@IT)