C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[3]: コンポーネントのピクチャーボックス描画について教えてください


(過去ログ 117 を表示中)

[トピック内 10 記事 (1 - 10 表示)]  << 0 >>

■68661 / inTopicNo.1)  コンポーネントのピクチャーボックス描画について教えてください
  
□投稿者/ グロッカー (1回)-(2013/11/05(Tue) 14:56:24)

分類:[C#] 

環境
 Microsoft Visual Studio 2010
 Windows 7

仕様
 UserControl を作成します。
 その上にパネルを配置し(AutoScroll = True, dock = full)
 そのパネルにピクチャーボックスを張り付けます。(BorderStyle = Fixed3D)

コード
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Drawing;
 using System.Data;
 using System.Linq;
 using System.Text;
 using System.Windows.Forms;

 namespace Origin
 {
  public partial class SamplePictureBox : UserControl
  {
   public SamplePictureBox()
   {
    InitializeComponent();
   }

   private void SamplePictureBox_Paint(object sender, PaintEventArgs e)
   {  // 全てのPaintイベントに描画をいれないと表示されない
    SamplePaint();
   }

   private void panel1_Paint(object sender, PaintEventArgs e)
   {  // 全てのPaintイベントに描画をいれないと表示されない
    SamplePaint();
   }

   private void pictureBox1_Paint(object sender, PaintEventArgs e)
   {  // 全てのPaintイベントに描画をいれないと表示されない
    SamplePaint();
   }

   private void SamplePaint()
   {
    Graphics g = pictureBox1.CreateGraphics();
    //全体を黒で塗りつぶす
    g.FillRectangle(Brushes.Black, g.VisibleClipBounds);
    //黄色い扇形を描画する
    g.DrawPie(Pens.Yellow, 60, 10, 80, 80, 30, 300);
    pictureBox1.Update();
   }
  }
 }

問題点
 その1:ピクチャーボックスに描画させるには、上記のサンプルコードのように
     ピクチャーボックスの親になるパネル、ユーザーコントロールのペイントイベントで
     描画(SamplePaint)させる必要があるのでしょうか?と、いうよりできなかった。
     もっとスマート(簡単な)方法がないのでしょうか?
 その2:上記で作成したUserControlをフォームに貼りテストしてみた。
     フォームを移動して、画面モニターの左外にPictureBoxの一部または全てをを出し、
     もとに戻してくるとピクチャーボックスの左の一部が描画されていないことがある
     描画されたままになる方法はあるのでしょうか?
     ちなみにフォームに直接PictureBoxを張り付けて同様のことをしても
     このようになりません。
最後に
 すみません。よろしくお願いします。

     

引用返信 編集キー/
■68662 / inTopicNo.2)  Re[1]: コンポーネントのピクチャーボックス描画について教えてください
□投稿者/ Hongliang (114回)-(2013/11/05(Tue) 15:18:06)
PictureBox1::Paintだけで問題ありません。
ただし、Graphicsオブジェクトを得るのにCreateGraphicsは使ってはいけません。
PaintEventArgs::Graphicsプロパティ(e.Graphics)を使用します。
再描画で問題が発生するのもそのせいです。

// さらにいうと、すべてPaintイベントで描画するならPictureBoxである必然性もなかったり。
引用返信 編集キー/
■68664 / inTopicNo.3)  Re[1]: コンポーネントのピクチャーボックス描画について教えてください
□投稿者/ 魔界の仮面弁士 (404回)-(2013/11/05(Tue) 15:37:38)
No68661 (グロッカー さん) に返信
> // 全てのPaintイベントに描画をいれないと表示されない
SamplePaint 内で CreateGraphics するのではなく、
イベント引数の e.Graphics を SamplePaint に渡す必要があります。



> その1:
> ピクチャーボックスの親になるパネル、ユーザーコントロールのペイントイベントで
本来は PictureBox だけで十分かと思います(親コントロールの Paint にて直描きでも良いですが)。

期待動作していなかった理由は、OS が要求しているキャンバス(e.Graphics)ではなく、
自分で作り上げたキャンバス(CreateGraphics)に描画していたせいでしょう。


> その2:
> ちなみにフォームに直接PictureBoxを張り付けて同様のことをしても
コントロールのコンテナが変わったことで、再描画の通知タイミングに変更が生じた故の
動作の差異とは思いますが、いずれにせよ e.Graphics に対して描画するのであれば、
特に問題は無いと思います。


> 最後に
> すみません。よろしくお願いします。
生成した Graphics は、使用後に破棄せねばなりません。
もしも CreateGraphics を使うのであれば、using ブロックを用いるなどして、
生成した Grapchis を確実に Dispose するようにしましょう。

一方、e.Graphics で得た Graphics の場合、これは自分で生成したものでは
無いので、勝手に Dispose してはいけません。(コントロール側で管理されます)


同様のことは、Pen や Brush や Font に対しても言えます。
static メンバーである Brushes.Black や Pens.Yellow は Dispose してはなりませんが、
Pen や Brush を自分で new して生成したものについては、それらを Dispose する義務が生じます。
引用返信 編集キー/
■68665 / inTopicNo.4)  Re[2]: コンポーネントのピクチャーボックス描画について教えてください
□投稿者/ グロッカー (3回)-(2013/11/05(Tue) 16:28:24)
No68662 (Hongliang さん) に返信

> // さらにいうと、すべてPaintイベントで描画するならPictureBoxである必然性もなかったり。

えっと、意味がちょっとわからないんですけど
やりたかったのは、panel の上にのせてpanel より大きい PictureBox を
panelのスクロール機能をつかって、表示したかったのです。

panelに直接書いてスクロール表示できる方法とかあるのでしょうか?

引用返信 編集キー/
■68667 / inTopicNo.5)  Re[2]: コンポーネントのピクチャーボックス描画について教えてください
□投稿者/ グロッカー (4回)-(2013/11/05(Tue) 16:33:24)
No68664 (魔界の仮面弁士 さん) に返信

> 生成した Graphics は、使用後に破棄せねばなりません。
> もしも CreateGraphics を使うのであれば、using ブロックを用いるなどして、
> 生成した Grapchis を確実に Dispose するようにしましょう。
>
> 一方、e.Graphics で得た Graphics の場合、これは自分で生成したものでは
> 無いので、勝手に Dispose してはいけません。(コントロール側で管理されます)
>
>
> 同様のことは、Pen や Brush や Font に対しても言えます。
> static メンバーである Brushes.Black や Pens.Yellow は Dispose してはなりませんが、
> Pen や Brush を自分で new して生成したものについては、それらを Dispose する義務が生じます。

Dispose するのは Pen や Brush だけ特殊なんでしょうか?
Font も必要ですか?
.Net はメモリの管理は自動でしてくれるわけじゃないんですね

Point p = new Point(0, 0);
こういうのは Dispose しなくてもいいというか、Disposeメソッド(?) がないですよね。
とにかく、Dispose が存在すれば Dispose する・・・ということでいいのでしょうか?

引用返信 編集キー/
■68668 / inTopicNo.6)  Re[3]: コンポーネントのピクチャーボックス描画について教えてください
□投稿者/ Hongliang (115回)-(2013/11/05(Tue) 17:01:30)
> panelに直接書いてスクロール表示できる方法とかあるのでしょうか?

不可能ではないですけども。
PictureBoxは基本的にImageプロパティを使ってImageオブジェクトを表示するためのコントロールであり、そのために最適化されています。
その機能を使わないのなら、PictureBoxではない別のコントロールでも問題ないという意味でした。
// とはいえ、VisualStudioのデザイナはControlオブジェクトを配置できないようなので、PictureBoxよりも好適なコントロールというと思いつきませんが。

> Dispose するのは Pen や Brush だけ特殊なんでしょうか?
> Font も必要ですか?

自分が作成したものであれば、Fontもです。
IDisposableインターフェイスを持っているもの全般。

> .Net はメモリの管理は自動でしてくれるわけじゃないんですね

メモリは自動で管理してくれますが、PenやFontはメモリ以外のリソースを使用しているので。
ファイルをあらわすFileStreamクラスを考えればわかりやすいと思います。
FileStreamはメモリ以外にディスク上のファイルをリソースとして使用しています。
使い終わったらさっさと解放しないと、ファイルをほかのプロセスが削除したりできなくなることになりますよね。
フェイルセーフとして、.NETがメモリ解放時に呼び出されるメソッド(ファイナライザ)で解放する処理を実装しているのでプロセスが死ぬまで確保し続けるってことはありませんが、.NETのメモリ解放は「いつかそのうち」が基本なので、メモリ以外のリソースをさっさと片付ける手段としてIDisposableが存在しています。
なおIDisposable::Disposeはただのメソッドであり、これでメモリ自体は解放されません。あくまでメモリ以外のリソースを解放します。
引用返信 編集キー/
■68671 / inTopicNo.7)  Re[3]: コンポーネントのピクチャーボックス描画について教えてください
□投稿者/ shu (413回)-(2013/11/05(Tue) 17:56:51)
No68667 (グロッカー さん) に返信
> Dispose するのは Pen や Brush だけ特殊なんでしょうか?
> Font も必要ですか?
> .Net はメモリの管理は自動でしてくれるわけじゃないんですね
>
.NetFrameworkはOSの上で動いている物なのでどうしても管理しきれないリソースが
発生します。そういうものは明示的に解放してあげる必要があるのです。OSが管理
しているリソースをすべて管理するにはOSの下に.NetFrameworkがないと無理です。

引用返信 編集キー/
■68672 / inTopicNo.8)  Re[3]: コンポーネントのピクチャーボックス描画について教えてください
□投稿者/ 魔界の仮面弁士 (405回)-(2013/11/05(Tue) 18:21:38)
2013/11/06(Wed) 03:24:06 編集(投稿者)

# 一部、他の方の投稿と被っている所もありますが、そのまま投稿。長文失礼。

No68667 (グロッカー さん) に返信
> Dispose するのは Pen や Brush だけ特殊なんでしょうか?
これらが特殊というわけではありません。少なくとも
 自分で作ったものは自分で破棄するべき。
 使用中のものや他で管理されているものは破棄してはならない。
という点については、他のオブジェクト(Bitmap 等)でも事情は一緒です。

先ほど書いた using ブロックが使えるのは、
  「IDisposable インターフェイスが実装されたオブジェクト」
に限られますので、まずは IDisposable について調べてみてください。


Dispose は、「オブジェクトを破棄可能な状態とする」ための物と捕らえると良いかもしれません。
生成されたオブジェクトをいつ破棄するべきなのか、それをコントロールするのは自分自身です。
そのための手段の一つが、IDisosable.Dispose メソッドと言うことになります。

そして IDisposable は、.NET 管理外のオブジェクト(アンマネージオブジェクト)
――たとえば、ファイル、ネットワーク接続、描画オブジェクトなどといった、
Win32 API のハンドルで管理されるオブジェクトなど――
を管理するクラスに対して実装されていることが多いです。
その他、大量にメモリを消費するマネージリソースに対して利用されることもありますね。


> Font も必要ですか?
はい。下記にも書かれていますので、確認してみてください。
http://msdn.microsoft.com/ja-jp/library/system.drawing.font.dispose.aspx

ただし、コントロールの Font プロパティから返される Font に関しては
不用意に Dispose しない方が無難かと思います。(アンビエントなプロパティなどの
対応のため、この点、それなりに複雑だったりします)

自分の場合、たとえば文字列を描画する際には、
 「コントロール等の Font プロパティをそのまま使って描画し、Font.Dispose は行わない」
 「描画用に自分で new した Font のみを使い、不要になったときに Dispose を行う」
のいずれかで対応するようにしています。


> .Net はメモリの管理は自動でしてくれるわけじゃないんですね
管理はしてくれます。
たとえ破棄し忘れたオブジェクトがあっても、それが「Dispose パターン」で実装されたクラスであれば、
自動回収というかガベージコレクトのタイミングで Dispose されるようにもなっています。
http://msdn.microsoft.com/ja-jp/library/fs2xkftw.aspx


ただし、その実行タイミングは自身のプログラムで制御するものではなく、あくまでも
「自動的に行われる」類のものです。すなわち、いつ処理されるのかは曖昧であるため、
「使い終わったらすぐに破棄する」ことが必要な場合は、明示的に Dispose する必要があります。


描画オブジェクトの代わりに、ファイルを想像してみる分かりやすいかもしれません。
(FileStream クラスもまた、IDispsable インターフェイスを実装しています)

通常、アプリから作成されたファイルは、その後すぐに、他のアプリからもアクセスできるように
なるべきですから、生成(new)したオブジェクトは、自らが責任をもって破棄する必要があります。

自動回収に任せてしまうと、書き込みが終わっても、そのファイルがいつ解放されるのかは分かりません。
それでは困るので、ファイルの読み書きが終わったら、即座に「Close メソッド」で閉じる必要があります。
(FileStream の Close は、内部で Dispose メソッドを呼び出しています)


一方描画オブジェクトは、ファイルほど排他的ではないので、解放し忘れてても体感しにくいかと思います。
Dispose し忘れても直ちに影響はないですが、処理が繰り返し積み重なると、その影響が出てくることが
懸念されますので、やはりキチンと管理されたほうが良いでしょう。


> とにかく、Dispose が存在すれば Dispose する・・・ということでいいのでしょうか?
いいえ、先ほども少し書きましたが、e.Graphics.Dispose() や Pens.Black.Dispose() は厳禁です。
自分で生成したもの、自分のみで管理されているオブジェクトのみが対象です。
他で利用・管理されているものは、勝手に Dispose してはいけません――原則として。


かといって、自分で管理している IDisposable すべてが Dispose すべき対象かと言うと、そうとも限らず…。
たとえば DataSet は IDisposable ですが、これは通常、Dispose を呼び出さずとも問題ありません。

あるいは、Timer や TextBox。これらも IDipsable であり、Dispose 処理が必要なオブジェクトですが、
デザイナで Form に貼って使う分には、明示的な Dispose 呼び出しは不要となっています。
フォームが破棄されるタイミングで、連動して破棄されるようになっているためです。


では Form 自身はどうかというと、これはモーダルかモードレスかで変化します。

「Show メソッド」でモードレスフォームとして呼び出した場合は、Dispose を呼び出す必要はありません。
閉じるボタンや Close メソッドなどによって、自動的に Dispose が呼ばれるようになっています。

一方、「ShowDialog」で Form をモーダルで呼び出した場合は、明示的に Dispose すべきです。

このあたりの事情の一部は、下記に書かれていますね。

http://msdn.microsoft.com/ja-jp/library/c7ykbedk.aspx
[Form.ShowDialog メソッド]
》 フォームがモーダル ダイアログ ボックスとして表示されている場合、
》 閉じる ボタン (フォームの右上隅の X ボタン)をクリックすると、
》 フォームは非表示になり、 DialogResult プロパティが DialogResult.Cancel に設定されます。

》 モーダルでないフォームとは異なり、ユーザーがダイアログ ボックスの閉じるボタンをクリックするか、
》 DialogResult プロパティの値を設定した場合には、Close メソッドは .NET Framework によって呼び出されません。
》 その場合はフォームが非表示になるだけで、ダイアログ ボックスの新しいインスタンスを作成しなくても
》 そのフォームを再表示できます。

》 ダイアログ ボックスとして表示されているフォームは閉じられるのではなく非表示になるため、
》 フォームがアプリケーションで不要になった場合は、そのフォームの Dispose メソッドを呼び出す必要があります。
引用返信 編集キー/
■68673 / inTopicNo.9)  Re[4]: コンポーネントのピクチャーボックス描画について教えてください
□投稿者/ 魔界の仮面弁士 (406回)-(2013/11/05(Tue) 19:47:49)
No68665 (グロッカー さん) に返信
> やりたかったのは、panel の上にのせてpanel より大きい PictureBox を
> panelのスクロール機能をつかって、表示したかったのです。
他の掲示板の過去ログですが、巨大画像のスクロール処理について参考までに。
http://dobon.net/vb/bbs/log3-39/23844.html


No68668 (Hongliang さん) に返信
> // とはいえ、VisualStudioのデザイナはControlオブジェクトを配置できないようなので、
Form 上に Control を貼る事はできますよ(そういう話では無いのかな?)
http://www.vb-user.net/junk/replySamples/2013.11.05.19.39/Control.png

それとも、Control を PictureBox の上に載せることは、デザイナ上からはできない…という意味でしょうか。
引用返信 編集キー/
■68674 / inTopicNo.10)  Re[5]: コンポーネントのピクチャーボックス描画について教えてください
□投稿者/ Hongliang (116回)-(2013/11/05(Tue) 20:46:30)
> Form 上に Control を貼る事はできますよ(そういう話では無いのかな?)
> http://www.vb-user.net/junk/replySamples/2013.11.05.19.39/Control.png

あや、見落としてました。
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -