none
1つのPrivate Sub -End Subの中で2つの画像を取得し描画するにはどのようにしたらよいか? RRS feed

  • 質問

  • Private SubーEnd Subの中で2つの画像を取得し描画するにはどのようにしたらよいのでしょうか。
    Dim g As Graphics を2回使いたいのですが
    そうすると1つ目でgが宣言されているため
    2つ目の描画ができません。

    ローカル変数'g'は現在のブロックで既に宣言されていますと表示されてしまいます。
    初心者で分からず方法がございましたらご指導お願いいたします。


     Private Sub
           
            Dim bit = New Bitmap(bmp)


            Dim rectSrc As New RectangleF(30, 30, 200, 200)
            Dim rectDst As New RectangleF(0, 0, bit.Width * 2, bit.Height * 2)

            Dim g As Graphics = PictureBox1.CreateGraphics()


            g.DrawImage(bit, rectDst, rectSrc, GraphicsUnit.Pixel)

            bmap.Dispose()
            g.Dispose()

        

            Dim img As New Bitmap(30, 30)
            Dim g As Graphics = Graphics.FromImage(img)
            g.FillRectangle(Brushes.White, g.VisibleClipBounds)

            PictureBox2.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage
            PictureBox2.Image = img

            Refresh()
        End Sub


    (必要なさそうなところは省略させていただきました)
    2010年1月18日 5:15

回答

  • g というのは予約語ではなく任意に変えられます
    たとえば
    Dim g1 As Graphics ・・・
    Dim g2 As Graphics ・・・
    といったように宣言できます
    • 回答としてマーク mei2 2010年1月18日 5:35
    2010年1月18日 5:31
  • 無くていい行があって PictureBox1 の絵が消えてしまうのかな・・・??
    動くサンプルコードを書いてみました
    各PictureBox の Paint イベントを使って書いています

        Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
            Dim bit = New Bitmap("C:\a.bmp")

            Dim rectSrc As New RectangleF(30, 30, 200, 200)
            Dim rectDst As New RectangleF(0, 0, bit.Width * 2, bit.Height * 2)

            e.Graphics.DrawImage(bit, rectDst, rectSrc, GraphicsUnit.Pixel)
            bit.Dispose()
        End Sub

        Private Sub PictureBox2_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox2.Paint
            Dim img As New Bitmap(300, 300)
            Dim g As Graphics = Graphics.FromImage(img)
            e.Graphics.FillRectangle(Brushes.White, g.VisibleClipBounds)

            PictureBox2.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage
            g.Dispose()
        End Sub

    • 回答としてマーク mei2 2010年1月18日 6:41
    2010年1月18日 6:17
  • 外池と申します。

    mei2さんご自身が、PictureBox1とPictureBox2に異なった方法で描画することを試しておられますよね? それが挙動におおきな差を生んでいます。

    **)PictureBox1への描画方法ですが、これは、たとえて言うと、画面上のPictureBox1の場所の上に、パラパラっと色砂を落として絵を描いたようなもので、簡単に「吹き消して」しまえるのです。もう少し正確に言いますと、PictureBox1というControlからCreateGraphicsで得たGraphicsオブジェクト上に描いた画像は永続できません。ユーザーの操作によって例えば別のウィンドウ(別のアプリでも自身のアプリでも)がPictureBox1の上にかぶさってきて、次に取り除かれたら、もともと描いた画像は消えてしまいます。ただ・・・、別のウィンドウが重なるまでは消えないので「一瞬表示されて消えてしまいます。」の意味はよくわかりませんが・・・。

    PictureBox2への描画方法は、一度BitmapのImageオブジェクトに絵を描いて、それをPictureBox2のImageプロパティーにセットしていますよね? これは、Imageオブジェクトという形で描画した画が保存されているわけです。そして、PictureBoxの機能として、ImageプロパティーにセットしたImageオブジェクトの画像は、常に表示するように自動で動作してくれるようになっています。

    以上の違いを踏まえると、

    PictureBox1も、PictureBox2と同じ方法で描けば良いと思うのですが、いかがでしょう? BitmapのImageオブジェクトに表示させておきたい絵を描いておいて、PictureBox1のImageプロパティーにセットしてやればOKと思いますが?

    別の方法もあります。お示し頂いたような方法でPictureBox1に描くと確かに消えてしまうのですが、「消えてしまったから描き直して」という報せを受け取ることはできます。Paintイベントがそれです。そのたびに絵を描きなおしてやれば、消えずに残っているように見えます。

    ----------------------

    **)の部分、少し補足しますね。お示し頂いたプログラムでは、最初にDim bit = New Bitmap(bmp)とされていますが、このbitに対して画を描く操作は全然無いですよね・・・。そこは、まぁ、何か描く操作をやってもらうとして、

    その後、g.DrawImage(bit, rectDst, rectSrc, GraphicsUnit.Pixel)という行がありますが、これは、上述のとおり、色砂をパラパラ落として、bitの模写をしただけのようなものなんです。


    (ホームページを再開しました)
    • 回答としてマーク mei2 2010年1月18日 6:41
    2010年1月18日 6:23
  • > g.DrawImageを画像として保存することはできますでしょうか。

    まず PictureBox1.Image.Save でうまくいかないのは、Image になにも設定していないからです。

    PictureBoxのImageプロパティに関するよくある勘違い
    http://dobon.net/vb/dotnet/graphics/pictureboximageanddrawimage.html
    (抜粋)PictureBoxのGraphicsオブジェクトに何を描画しようが、それがPictureBoxのImageプロパティに反映されることはありません。この2つは全く別の方法です。

    で、どうすればいいかというと、例えば↓こんな感じで、、、

        Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
            'コントロールの外観を描画するBitmapの作成
            Dim bmp As New Bitmap(PictureBox1.Width, PictureBox1.Height)
            'キャプチャする
            PictureBox1.DrawToBitmap(bmp, New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height))
            'ファイルに保存する
            bmp.Save("C:\test3.bmp")
            '後始末
            bmp.Dispose()
        End Sub

    下記ページを参考にさせていただきました(というかまるっとコピー)
    フォーム、コントロールの外観をキャプチャする
    http://dobon.net/vb/dotnet/graphics/invokepaint.html
    (トップページ→ http://dobon.net/

    • 回答としてマーク mei2 2010年1月18日 10:02
    2010年1月18日 7:50

すべての返信

  • g というのは予約語ではなく任意に変えられます
    たとえば
    Dim g1 As Graphics ・・・
    Dim g2 As Graphics ・・・
    といったように宣言できます
    • 回答としてマーク mei2 2010年1月18日 5:35
    2010年1月18日 5:31
  • ご回答ありがとうございます。g1,g2ではすでにやってみたのですがg2はしっかりと描画されるのですがg1は一瞬表示されて消えてしまいます。
    g1だけ、g2だけでデバッグをするとそれぞれ画像はしっかりピクチャーボックスに表示されるのですが。その場合はどのように書けば両方表示させることができますでしょうか。
    質問ばかりで申し訳ございません。
    2010年1月18日 5:39
  • 無くていい行があって PictureBox1 の絵が消えてしまうのかな・・・??
    動くサンプルコードを書いてみました
    各PictureBox の Paint イベントを使って書いています

        Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
            Dim bit = New Bitmap("C:\a.bmp")

            Dim rectSrc As New RectangleF(30, 30, 200, 200)
            Dim rectDst As New RectangleF(0, 0, bit.Width * 2, bit.Height * 2)

            e.Graphics.DrawImage(bit, rectDst, rectSrc, GraphicsUnit.Pixel)
            bit.Dispose()
        End Sub

        Private Sub PictureBox2_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox2.Paint
            Dim img As New Bitmap(300, 300)
            Dim g As Graphics = Graphics.FromImage(img)
            e.Graphics.FillRectangle(Brushes.White, g.VisibleClipBounds)

            PictureBox2.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage
            g.Dispose()
        End Sub

    • 回答としてマーク mei2 2010年1月18日 6:41
    2010年1月18日 6:17
  • 外池と申します。

    mei2さんご自身が、PictureBox1とPictureBox2に異なった方法で描画することを試しておられますよね? それが挙動におおきな差を生んでいます。

    **)PictureBox1への描画方法ですが、これは、たとえて言うと、画面上のPictureBox1の場所の上に、パラパラっと色砂を落として絵を描いたようなもので、簡単に「吹き消して」しまえるのです。もう少し正確に言いますと、PictureBox1というControlからCreateGraphicsで得たGraphicsオブジェクト上に描いた画像は永続できません。ユーザーの操作によって例えば別のウィンドウ(別のアプリでも自身のアプリでも)がPictureBox1の上にかぶさってきて、次に取り除かれたら、もともと描いた画像は消えてしまいます。ただ・・・、別のウィンドウが重なるまでは消えないので「一瞬表示されて消えてしまいます。」の意味はよくわかりませんが・・・。

    PictureBox2への描画方法は、一度BitmapのImageオブジェクトに絵を描いて、それをPictureBox2のImageプロパティーにセットしていますよね? これは、Imageオブジェクトという形で描画した画が保存されているわけです。そして、PictureBoxの機能として、ImageプロパティーにセットしたImageオブジェクトの画像は、常に表示するように自動で動作してくれるようになっています。

    以上の違いを踏まえると、

    PictureBox1も、PictureBox2と同じ方法で描けば良いと思うのですが、いかがでしょう? BitmapのImageオブジェクトに表示させておきたい絵を描いておいて、PictureBox1のImageプロパティーにセットしてやればOKと思いますが?

    別の方法もあります。お示し頂いたような方法でPictureBox1に描くと確かに消えてしまうのですが、「消えてしまったから描き直して」という報せを受け取ることはできます。Paintイベントがそれです。そのたびに絵を描きなおしてやれば、消えずに残っているように見えます。

    ----------------------

    **)の部分、少し補足しますね。お示し頂いたプログラムでは、最初にDim bit = New Bitmap(bmp)とされていますが、このbitに対して画を描く操作は全然無いですよね・・・。そこは、まぁ、何か描く操作をやってもらうとして、

    その後、g.DrawImage(bit, rectDst, rectSrc, GraphicsUnit.Pixel)という行がありますが、これは、上述のとおり、色砂をパラパラ落として、bitの模写をしただけのようなものなんです。


    (ホームページを再開しました)
    • 回答としてマーク mei2 2010年1月18日 6:41
    2010年1月18日 6:23
  • お返事が遅くなってしまい申し訳ございません。
    とても分かりやすい回答ありがとうございます。
     Private Sub の中にいくつか処理があり、中の処理過程の画像を1、処理結果の画像を2として、値を変更するごとにまとめて描画しようとしてエラーが出てしまっていました。
    値を変更したときの処理過程の画像を表示させるだけにし、処理結果画像はコマンドボタンを押すことによって表示させるようにしたところ無事答えがでるようになりました。
    ただそうしたところ処理結果画像の保存ができなくなってしまいまして。

    g.DrawImage(bit, rectDst, rectSrc, GraphicsUnit.Pixel)の画像をbmpで保存したく
     PictureBox1.Image.Save(FileName)で挑戦してみましたがnullを返してしまいました。


    ネットで一生懸命調べたのですがg.DrawImageでは描画をしているだけで保存することはできない、
    g.DrawImage() は元の画像が加工されていない PictureBox に Bitmap を与える必要がある
    というところまでしか分からなく、g.DrawImageを画像として保存することはできますでしょうか。

    要領の得ない文章でしかも重ねて質問で申し訳ございません。


    2010年1月18日 6:58
  • 外池様ご回答ありがとうございます。中途半端で申し訳ございません。Dim bit の前にいくつか処理がありfor文で回してその結果をbmpに入れ加工し切り抜くことをしていました。ひとつの処理の中で値を変えるごとに表途中経過の画 像と処理後の画像を同時に表示させたかったので一緒に記述していたのですがやっぱりできなく、結局コマンドボタンで処理結果画像は別に出力するようにした ところ無事動かすことができるようになりました。色砂を落としただけというご説明、初心者の私でも想像できとても分かりやすく納得できました。ネットで精一杯調べたのですが仰られているとおりg.DrawImage(bit, rectDst, rectSrc, GraphicsUnit.Pixel)は描画しかされていないとのことでこの結果を保存するにはどのようにしたらよいか分かりません。度重なる質問をしてしまい申し訳ございません。もしご存じでしたらご指導お願いいたします。
    2010年1月18日 7:10
  • > g.DrawImageを画像として保存することはできますでしょうか。

    まず PictureBox1.Image.Save でうまくいかないのは、Image になにも設定していないからです。

    PictureBoxのImageプロパティに関するよくある勘違い
    http://dobon.net/vb/dotnet/graphics/pictureboximageanddrawimage.html
    (抜粋)PictureBoxのGraphicsオブジェクトに何を描画しようが、それがPictureBoxのImageプロパティに反映されることはありません。この2つは全く別の方法です。

    で、どうすればいいかというと、例えば↓こんな感じで、、、

        Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
            'コントロールの外観を描画するBitmapの作成
            Dim bmp As New Bitmap(PictureBox1.Width, PictureBox1.Height)
            'キャプチャする
            PictureBox1.DrawToBitmap(bmp, New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height))
            'ファイルに保存する
            bmp.Save("C:\test3.bmp")
            '後始末
            bmp.Dispose()
        End Sub

    下記ページを参考にさせていただきました(というかまるっとコピー)
    フォーム、コントロールの外観をキャプチャする
    http://dobon.net/vb/dotnet/graphics/invokepaint.html
    (トップページ→ http://dobon.net/

    • 回答としてマーク mei2 2010年1月18日 10:02
    2010年1月18日 7:50
  • あまりの理解力のなさに申し訳なさすぎです。これ以上ご迷惑をお掛けできないので
    こちらで最後の質問です。しつこすぎですのでスルーでも大丈夫です。
    そちらのサイトはすでに試して駄目でした。
    無事に動かしてご報告をとおもったのですが粘っても粘っても解決策が見当たらず。

    bmp1から(12,12,231,231)をPictureBox1(256×256)にフィットさせて表示し
    PictureBox1(256×256)を保存するとした場合はどのように書けばよいのでしょうか。



            For Me.l = 12 To (bmp.Height - 1) - 12
                For Me.k = 12 To (bmp.Width - 1) - 12
                    bmp1.SetPixel(k, l, Color.FromArgb(pix2(k, l, 0), pix2(k, l, 1), pix2(k, l, 2)))
                Next k
            Next l

            PictureBox1.Image = bmp1
            PictureBox1.Refresh()
    ですと256×256の画像がpictureBox1に表示できるのですが

         For Me.l = 12 To (bmp.Height - 1) - 12
                For Me.k = 12 To (bmp.Width - 1) - 12
                    bmp1.SetPixel(k, l, Color.FromArgb(pix2(k, l, 0), pix2(k, l, 1), pix2(k, l, 2)))
                Next k
            Next l


    PictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage
    PictureBox1.Image = bmp1(12,12,231,231)は当然無理でした。

    そもそも
         For Me.l = 12 To (bmp.Height - 1) - 12
                For Me.k = 12 To (bmp.Width - 1) - 12

    だけの範囲で行っていたらbmp1は(12,12,231,231)となると思って書いていたのですが淵が出てしまい
    (12,12,231,231)だけ切り取って表示保存をしようとしてもうまくいきません。



    PictureBox1.Image = ******** (bmp1,12,12,231,231)
    PictureBox1.Refresh()

    その後picturebox1の画像を保存する********の処理ができるようなものはありますでしょうか。
         
    ネットや手持ちの参考書を見ても中途半端や違う事例しか見あたらず
    本来なら自力でどうにかしなければならないのに重ねて本当に申し訳ございません。
    またお薦めの参考書などがございましたら教えて頂けると幸いです。
    2010年1月18日 9:58
  • やりたいことは↓こういうことでしょうか?

    (VB.net)画像の一部を切り取って,拡大・縮小したい
    http://okwave.jp/qa/q1262814.html

    # 以下、本題以外のレスです
    #
    # > あまりの理解力のなさに申し訳なさすぎです。これ以上ご迷惑をお掛けできないので
    # > こちらで最後の質問です。しつこすぎですのでスルーでも大丈夫です。
    #
    # そもそもそういう目的(問題を共有し解決策をいっしょに考える)のフォーラムだと思っているので全然迷惑ではないです
    # まあ、タイトルから内容が逸れてしまったら新しいスレッドを作った方がいいとは思います
    # ↑同じことで悩んだひとが検索しやすくするため
    # おすすめの参考書は、、、
    # VB.NET の書籍は読んだことがないので残念ながらおすすめできる本はないのですが
    # ↓こういったサイトで基礎をつかんで、あとはネット検索で調べるといった方法で勉強しました
    # @IT総合トップ > @IT CORE > Insider.NET > カテゴリ別 全記事一覧
    # http://www.atmarkit.co.jp/fdotnet/index/all/category.html#vb
    # とくに川俣様の解説にはたいへんお世話になっていますm(_ _)m
    # 改訂版 プロフェッショナルVB.NETプログラミング
    # http://www.atmarkit.co.jp/fdotnet/vb6tonet2/index/index.html
    # 書籍で順序立てて覚えるのもいい方法だとおもいます
    # オススメ書籍については別スレッドで聞いてみるといいかもしれません
    # 参考スレッド→VC++のWin32アプリケーションの勉強方法 http://social.msdn.microsoft.com/Forums/ja-JP/vcgeneralja/thread/64238a5c-43ff-4109-ab89-1d9767647d2a
    • 編集済み anningo 2010年1月18日 11:13 誤字訂正
    2010年1月18日 11:02
  • 外池です。たぶん、Graphicsオブジェクトがどんな働きをするものか、うまく理解できていないんだと思います。

    Graphicsオブジェクトは、描画をするための「作業机」のようなものだと思ってください。実際に何に描かれるか、描かれた結果が「はかない」「吹いたら消える」ようなものか、それとも、キッチリ永続したり、ファイルに保存できるかは、また別問題です。

    ControlのCreateGraphicsメソッドで作り出したGraphicsオブジェクトで描画作業はできますが、先ほどご説明したようにControlの位置に「はかない」絵を描くだけです。これは、Controlというオブジェクトの機能がその程度の機能しかない、ということです。PictureBoxにはImageというプロパティーがありますが、anninngoさんがご指摘のとおり、CreateGraphicsメソッドで作り出したGraphicsオブジェクトとは無関係です。これも、PictureBoxがそういう機能にしかなっていないからです。

    まずBitmapオブジェクトを作っておいて(Bitmapオブジェクトは画像を永続させる、保存する機能があります)、Graphics.FromImage(bit)でGraphicsオブジェクトを作ってやれば、この「作業机」のGraphicsオブジェクトで描いた絵はBitmapオブジェクトに保存されます。これは、Bitmapオブジェクトがそのような機能を備えているからで、Controlの機能とは根本的に違うところです。

    Bitmapオブジェクトを2つ用意すれば、例えば、256×256ピクセルのbmp1と、512×512ピクセルのbmp2を用意すれば、
    g=Graphics.FromImage(bmp1)で、bmp1に描画するためのGraphicsオブジェクトgを作れます。
    g.DrawImage(bmp2,.......)とやれば、bmp2の内容をbmp1に描きこむことができますが・・・、

    そろそろ正解が見えてきませんか?




    (ホームページを再開しました)
    2010年1月18日 12:43