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

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

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

Re[3]: picturebox 使用されたパラメータが有効で・・・


(過去ログ 130 を表示中)

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

■77153 / inTopicNo.1)  picturebox 使用されたパラメータが有効で・・・
  
□投稿者/ shion (1回)-(2015/09/17(Thu) 18:02:32)

分類:[C#] 

visual studio2010 C#にて開発しています。

pictureboxの画像を更新する際に、dispose()を行わなかったために、処理が重くなる現象が起きました。
このため、画像の更新時にdispose()を行うようにしたのですが、例外が発生するようになりました。

2つの画像を順次張り替えるテストプログラムです。

<ソース>
Image[] img = new Image[2];
private void button1_Click(object sender, EventArgs e)
{
img[0] = Image.FromFile(@"1.png");
img[1] = Image.FromFile(@"2.png");
for (int i = 0; i < 10000; i++)
{
setobbg(ref pictureBox1, img[0]);
pictureBox1.Update();
setobbg(ref pictureBox1, img[1]);
pictureBox1.Update();
}
}
private void setobbg(ref PictureBox ctl, Image img)
{
var oldImg = ctl.BackgroundImage;
ctl.BackgroundImage = img;
if (oldImg != null)
{
oldImg.Dispose();
}
}

<例外>
'System.ArgumentException' のハンドルされていない例外が System.Drawing.dll で発生しました。
追加情報: 使用されたパラメータが有効ではありません。

<発生について>
分かっていることを箇条書きにします。
・ステップ実行した際には、例外は起きません。
・例外で停止する場所は、一定ではありません。
・大抵はiが1の時、つまり2周目で発生します。

何か情報をお持ちでしょうか。
よろしくお願いします。

引用返信 編集キー/
■77154 / inTopicNo.2)  Re[1]: picturebox 使用されたパラメータが有効で・・・
□投稿者/ 魔界の仮面弁士 (500回)-(2015/09/17(Thu) 18:40:55)
2015/09/17(Thu) 18:48:04 編集(投稿者)

No77153 (shion さん) に返信
> setobbg(ref pictureBox1, img[0]);

何故 ref 参照に?


> このため、画像の更新時にdispose()を行うようにしたのですが、例外が発生するようになりました。

実際に試してはいませんが、今回のケースなら、Dispose してはいけないのでは。


提示されたコードを見る限りでは、

(1) 1.png をロードする…これをAと呼ぶ
(2) 2.png をロードする…これをBと呼ぶ
(3) ループ 1 回目(i == 0)
 (3.1) A を表示する。以前に表示されていた画像は無い。
 (3.1) B を表示して、以前に表示されていた A を破棄する。
(4) ループ 2 回目(i == 1)
 (4.1) 破棄した A を再表示して、以前に表示されていた B を破棄する。
 (4.1) 破棄した B を再表示して、以前に表示されていた A を再度破棄する。

という手順になってしまうように見えます。


意図的に破棄したいのであれば、

【案1】事前に読み込んでおくのではなく、表示するたびに読み込ませる

(1) ループ 1 回目(i == 0)
 (1.1) 1.png をロードする…これをAと呼ぶ
 (1.2) それを表示する。以前に表示されていた画像は無い。
 (1.3) 2.png をロードする…これをBと呼ぶ
 (1.4) それを表示して、以前に表示されていた A を破棄する。
(2) ループ 2 回目(i == 1)
 (2.1) 1.png をロードする…これをaと呼ぶ
 (2.2) それを表示して、以前に表示されていた B を破棄する。
 (2.3) 2.png をロードする…これをbと呼ぶ
 (2.4) それを表示して、以前に表示されていた a を破棄する。
(3) ループ 3 回目 … 以下繰り返し


もしくは、

【案2】最初にまとめて読み込んで、最後にまとめて破棄する

(1) 1.png をロードする…これをAと呼ぶ
(2) 2.png をロードする…これをBと呼ぶ
(3) ループ 1 回目(i == 0)
 (3.1) A を表示する。以前に表示されていた画像は無い。
 (3.2) B を表示して、以前に表示されていた A はそのまま放置。
(4) ループ 2 回目(i == 1)
 (4.1) A を再表示して、以前に表示されていた B はそのまま放置。
 (4.2) B を再表示して、以前に表示されていた A はそのまま放置。
(5) 以下繰り返し
(6) Form 終了後に、A と B も破棄する。
 (※)もしくは、.BackgroundImage に null をセットしてから、A と B を破棄する。

のいずれかのパターンにした方が良いと思います。

どちらのパターンが良いのかは、同時にロードする画像数などにもよりますけど。

(これは画像に限らず、Font などにも言えることですね)
引用返信 編集キー/
■77163 / inTopicNo.3)  Re[2]: picturebox 使用されたパラメータが有効で・・・
□投稿者/ shion (1回)-(2015/09/18(Fri) 13:54:55)
魔界の仮面弁士さん
ありがとうございます。

> 何故 ref 参照に?
コントロールにimageを反映させるためです。
refが無いと、メソッド内でimageを更新しても、反映されません。

内容理解しました。
image.dispose()を行うと、このimageをクリアするイメージを持っていたのですが、
imageに読み込まれた画像そのものをクリアすることになるのですね。

このやり方の場合は、画像更新時のdisposeが不要という事で、理解しました。

ありがとうございました。
解決済み
引用返信 編集キー/
■77166 / inTopicNo.4)  Re[3]: picturebox 使用されたパラメータが有効で・・・
□投稿者/ 魔界の仮面弁士 (502回)-(2015/09/18(Fri) 14:47:35)
No77163 (shion さん) に返信
>>何故 ref 参照に?
> コントロールにimageを反映させるためです。
> refが無いと、メソッド内でimageを更新しても、反映されません。

それは違うかと。メソッド定義を
 private void setobbg(PictureBox ctl, Image img)
にした上で、呼び出しを
 setobbg(pictureBox1, img[0]);
にしても、同じ動作になりませんか?


もしもメソッド内で引数を書き換える必要がある場合には、
ref もしくは out パラメータにする必要があるでしょう。具体的には
「ctrl = 別のPictureBox;」や「ctrl = null;」といった場合です。

しかし今回のコードでは、引数を書き換えることは行われていません。
単に pictureBox を「ctl.BackgroundImage = 画像;」と操作しているだけであって、
別の pictureBox に差し替えているわけではありません。故に、ref にする必然性も無いわけで。


> image.dispose()を行うと、このimageをクリアするイメージを持っていたのですが、
そのイメージで合っていますよ。

ただ、「クリア」という表現だと、背景のクリアということで、
「.BackgroundImage = null;」などを想像してしまうので、
解放とか破棄といった表現の方が良いかもしれません。


> imageに読み込まれた画像そのものをクリアすることになるのですね。
Image は、構造体(値型)ではなくクラス(参照型)ですしね。

今回の場合、同じオブジェクトが、複数の場所から参照されている状態になっているため、
oldImg.Dispose(); によって、フィールド変数 img[n] も Dispose されることになります。


細かい点を端折って書くと、画像情報は
 img[0] = Image.FromFile(@"1.png");
で読み込まれ、setobbg メソッドを通じて
 ctl.BackgroundImage = img;
という形で、pictureBox1 に渡されるわけですが、
この際に、下記のような動作が起きているということです。


・Image.FromFile を通じて "1.png" が読み込まれることで、
 Image 型(Bitmap)のインスタンスが生成される。

・その 1 つのインスタンスは、複数の場所から参照されている。

  (1)Form1 のフィールド変数『img[0]』
  (2)setobbg メソッドの引数『img』
  (3)setobbg メソッドのローカル変数『oldImg』
  (4)PictureBox のプロパティ『.BackgroundImage』

※今回の場合、(2)〜(4) は、img[1] すなわち 2.png を参照する場合もあります。
解決済み
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -