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

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

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

Re[6]: 画像のフェードイン、フェードアウト表示


(過去ログ 86 を表示中)

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

■50887 / inTopicNo.1)  画像のフェードイン、フェードアウト表示
  
□投稿者/ たぐぅ* (6回)-(2010/06/21(Mon) 18:02:14)

分類:[C#] 

度々、失礼いたします。
よろしくお願いいたします。

とあるサイト様のサンプルで以下のような「画像をフェードイン、フェードアウト」させるプログラムのソースがありました。(長くてすみません)

//PictureBox1をクリックすることにより、開始される
private void PictureBox1_Click(object sender, System.EventArgs e)
{

//PictureBox1のGraphicsオブジェクトを取得
Graphics g = PictureBox1.CreateGraphics();

//画像を読み込む
Image img = Image.FromFile(@"C:\サンプル.jpg");

//フェードイン
for (int i = 1; i <= 10; i++)
{
//半透明で画像を描画
Console.WriteLine(i * 0.1F);
DrawFadedImage(g, img, i * 0.1F);
//一時停止
System.Threading.Thread.Sleep(500);
}

//フェードアウト
for (int i = 9; i >= 0; i--)
{
//半透明で画像を描画
Console.WriteLine(i * 0.1F);
DrawFadedImage(g, img, i * 0.1F);
//一時停止
System.Threading.Thread.Sleep(500);
}

//リソースを開放する
img.Dispose();
g.Dispose();
}

public static void DrawFadedImage(Graphics g, Image img, float alpha)
{
//背景を用意する
Bitmap back = new Bitmap(img.Width, img.Height);
//backのGraphicsオブジェクトを取得
Graphics bg = Graphics.FromImage(back);
//白で塗りつぶす
bg.Clear(Color.White);

//ColorMatrixオブジェクトの作成
System.Drawing.Imaging.ColorMatrix cm =
new System.Drawing.Imaging.ColorMatrix();
//ColorMatrixの行列の値を変更して、アルファ値がalphaに変更されるようにする
cm.Matrix00 = 1;
cm.Matrix11 = 1;
cm.Matrix22 = 1;
cm.Matrix33 = alpha;
cm.Matrix44 = 1;

//ImageAttributesオブジェクトの作成
System.Drawing.Imaging.ImageAttributes ia =
new System.Drawing.Imaging.ImageAttributes();
//ColorMatrixを設定する
ia.SetColorMatrix(cm);

//ImageAttributesを使用して背景に描画
bg.DrawImage(img, new Rectangle(0, 0, img.Width, img.Height),
0, 0, img.Width, img.Height, GraphicsUnit.Pixel, ia);
//合成された画像を表示
g.DrawImage(back, 0, 0);

//リソースを開放する
bg.Dispose();
back.Dispose();
}

このDrawFadedImageメソッドの中でグラフィックスの色指定のところがありますが、

//白で塗りつぶす
bg.Clear(Color.White);

ここを透明に書き換えました。

bg.Clear(Color.Transparent);

この状態で実行をするとフェードインはうまくいくのですが、フェードアウトはされずに、表示された状態のまま残ってしまいます。

どうしてでしょうか?
理由を教えていただきたいです。
よろしくお願いします。

引用返信 編集キー/
■50896 / inTopicNo.2)  Re[1]: 画像のフェードイン、フェードアウト表示
□投稿者/ 魔界の仮面弁士 (1680回)-(2010/06/21(Mon) 20:46:08)
No50887 (たぐぅ* さん) に返信
> とあるサイト様のサンプルで以下のような「画像をフェードイン、フェードアウト」させるプログラムのソースがありました。

どのサイトか明示しないと、無断転載として扱われてしまうかもしれません。

ところで、そのサンプルというのは、どぼん!さんのサイトの物でしょうか?
http://dobon.net/vb/dotnet/graphics/hadeinimage.html

だとすれば、そのサイトの「注意事項」を守って利用しましょう。
『このサイトにある文章等を別のサイトで引用する際は、
 必ずこのサイト(DOBON.NET)から引用したことと、
 引用元のURLを明記してください。 』
http://dobon.net/vb/dotnet/index.html#attention


> //PictureBox1のGraphicsオブジェクトを取得
> Graphics g = PictureBox1.CreateGraphics();
CreateGraphics メソッドではなく、Paint イベントの e.Graphics を使うか、
あるいは、Graphics.FromImage から得たほうが良いかと思います。


> System.Threading.Thread.Sleep(500);
本来は、UI スレッドから Sleep を呼び出すべきではありません。

処理の間は再描画が行われませんし、フォームの移動等を含む一切の操作が行えません。
場合によってはフォーム全体が真っ白になり、応答無し状態になることもあります。



> どうしてでしょうか?
実環境での動作を見ないとはっきりした事は言えませんが、恐らくは
先に描画した内容が消されずに、次の画像が重ねて描画されているのでは無いでしょうか。

DrawFadedImage を呼び出す直前に、pictureBox1.Refresh(); を呼び出して、
前回の描画結果をリセットして描き直してやれば、Transparent が指定されても
正しくフェードアウトする「かも」知れません。


> 理由を教えていただきたいです。
サンプル.jpg の代わりに、「透明な背景を持った png ファイル」を指定した上で、
「完全透明色」ではなく「透明度の高い色」で塗りつぶしてみた場合はどうなりますか?

たとえば、塗りつぶし色を
 bg.Clear(Color.FromArgb(15, Color.Red));
で試してみてください。0 で完全透明、255 で完全不透明の赤です。

この場合、png画像の透過背景部分は、何色に見えますか?
再描画が正しく行われていれば、背景色は薄い赤のまま変化しないはずです。

途中で背景部が真っ白になったり、背景部の赤がどんどん濃くなっていくようであれば、
再描画処理が適切に処理されていない可能性があります。
引用返信 編集キー/
■50917 / inTopicNo.3)  Re[2]: 画像のフェードイン、フェードアウト表示
□投稿者/ たぐぅ* (7回)-(2010/06/22(Tue) 04:01:20)
No50896 (魔界の仮面弁士 さん) に返信
> どのサイトか明示しないと、無断転載として扱われてしまうかもしれません。
おっしゃる通りです、次からは気をつけます。


> ところで、そのサンプルというのは、どぼん!さんのサイトの物でしょうか?
> http://dobon.net/vb/dotnet/graphics/hadeinimage.html
はい、そうです。
次からは「注意事項」をよく読みたいと思います。。


> 先に描画した内容が消されずに、次の画像が重ねて描画されているのでは無いでしょうか。
その通りでした・・・


> たとえば、塗りつぶし色を
>  bg.Clear(Color.FromArgb(15, Color.Red));
> で試してみてください。0 で完全透明、255 で完全不透明の赤です。
>
> この場合、png画像の透過背景部分は、何色に見えますか?
> 再描画が正しく行われていれば、背景色は薄い赤のまま変化しないはずです。
>
> 途中で背景部が真っ白になったり、背景部の赤がどんどん濃くなっていくようであれば、
> 再描画処理が適切に処理されていない可能性があります。
どんどん濃くなりましたので、前の描画が残っていることになりますね・・・


> DrawFadedImage を呼び出す直前に、pictureBox1.Refresh(); を呼び出して、
> 前回の描画結果をリセットして描き直してやれば、Transparent が指定されても
> 正しくフェードアウトする「かも」知れません。
試してみましたが、効果なしでした。


現在、模索中です。
他にも何かありましたら、よろしくお願いします。

一つ思いつきましたのが、「画像の透明で無い部分だけ、白く塗りつぶす」
ということなのですが、これは不可能なのでしょうか?

引用返信 編集キー/
■50925 / inTopicNo.4)  Re[3]: 画像のフェードイン、フェードアウト表示
□投稿者/ 魔界の仮面弁士 (1682回)-(2010/06/22(Tue) 09:43:13)
2010/06/22(Tue) 09:45:08 編集(投稿者)

No50917 (たぐぅ* さん) に返信
> 現在、模索中です。
Sleep を使わないようにしましょう。
ループ + Sleep(500) で CreateGraphics に対して描画するのは避けるべきです。

方法は幾つかありますが、Timer の Tick イベントで定期的(0.5秒間隔)に
PictureBox の Invalidate か Refresh を呼ぶようにして、描画処理も
PictureBox の Paint イベントで、e.Graphics に描画してやれば解決できるかと。
引用返信 編集キー/
■50927 / inTopicNo.5)  Re[4]: 画像のフェードイン、フェードアウト表示
□投稿者/ 魔界の仮面弁士 (1684回)-(2010/06/22(Tue) 13:01:22)
No50925 (魔界の仮面弁士) に追記
> 方法は幾つかありますが、Timer の Tick イベントで定期的(0.5秒間隔)に
> PictureBox の Invalidate か Refresh を呼ぶようにして、描画処理も
> PictureBox の Paint イベントで、e.Graphics に描画してやれば解決できるかと。

以下、実装例です。

Image img;
int offset, count;
private void Form1_Load(object sender, EventArgs e)
{
    img = Image.FromFile(@"C:\サンプル.jpg");
    timer1.Interval = 250;
}

private void pictureBox1_Click(object sender, EventArgs e)
{
    offset = +1;
    count = 0;
    timer1.Start();
}

private void timer1_Tick(object sender, EventArgs e)
{
    count += offset;

    pictureBox1.Refresh();

    if (count >= 10)
    {
        offset = -1;
    }
    else if (count <= 0)
    {
        timer1.Stop();
    }
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    if (img != null)
    {
        DrawFadedImage(e.Graphics, img, count * 0.1F);
    }
}

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
    if (img != null)
    {
        img.Dispose();
    }
}

引用返信 編集キー/
■50928 / inTopicNo.6)  Re[5]: 画像のフェードイン、フェードアウト表示
□投稿者/ 魔界の仮面弁士 (1685回)-(2010/06/22(Tue) 13:22:22)
No50927 (魔界の仮面弁士) に追記
> 以下、実装例です。

別案。

private void Form1_Load(object sender, EventArgs e)
{
    backgroundWorker1.WorkerReportsProgress = true;
}

private void pictureBox1_Click(object sender, EventArgs e)
{
    if (!backgroundWorker1.IsBusy)
    {
        Bitmap canvas = new Bitmap(pictureBox1.Width, pictureBox1.Height);
        backgroundWorker1.RunWorkerAsync(canvas);
    }
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    pictureBox1.Image = (Image)e.UserState;
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker bgw = (BackgroundWorker)sender;
    Bitmap canvas = (Bitmap)e.Argument;

    using (Image img = Image.FromFile(@"C:\サンプル.jpg"))
    using (Graphics g = Graphics.FromImage(canvas))
    {
        for (int i = 1; i <= 10; i++)
        {
            g.Clear(Color.Transparent);
            DrawFadedImage(g, img, i * 0.1F);
            bgw.ReportProgress(0, canvas);
            System.Threading.Thread.Sleep(250);
        }
        for (int i = 9; i >= 0; i--)
        {
            g.Clear(Color.Transparent);
            DrawFadedImage(g, img, i * 0.1F);
            bgw.ReportProgress(0, canvas);
            System.Threading.Thread.Sleep(250);
        }
    }
}

引用返信 編集キー/
■51228 / inTopicNo.7)  Re[6]: 画像のフェードイン、フェードアウト表示
□投稿者/ たぐぅ* (8回)-(2010/06/28(Mon) 15:51:58)
No50928 (魔界の仮面弁士 さん) に返信
> ■No50927 (魔界の仮面弁士) に追記
>>以下、実装例です。

細かいサンプルまで示していただき、ありがとうございました。
あれから、頑張ってみましたが解決には至りませんでした。

しかし、魔界の仮面弁士さんのサンプルを参考に、代替案を見つけることができましたので感謝しております!


この度は、ありがとうございました。

解決済み
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -