画像の切り取り への返答

投稿で使用できる特殊コードの説明。(別タブで開きます。)
本名は入力しないようにしましょう。
投稿した後で削除するときに使うパスワードです。返答があった後は削除できません。
返答する人が目安にします。相手が小学生か社会人かで返答の仕方も変わります。
最初の投稿が質問の場合、質問者が解決時にチェックしてください。(以降も追加書き込み・返信は可能です。)
※「過去ログ」について書くときはその過去ログのURLも書いてください。

以下の返答は逆順(新しい順)に並んでいます。

投稿者 トモヤ  (高校生) 投稿日時 2010/8/5 20:34:09
みなさんいろいろありがとうございました。
出来るようになりました!!
投稿者 (削除されました)  () 投稿日時 2010/8/5 19:17:24
(削除されました)
投稿者 るきお  (社会人) 投稿日時 2010/8/5 12:47:44
こんにちは。

試してみましたがエラーにならずにうまく動きます。

よく見たわけではないのですが、CreateGraphicsメソッドには気にしなければいけないタイミングがあって、CreateGraphicsメソッドで生成しておいたGraphicsクラスのインスタンスを後で使用しようとするとうまく行かないことがあります。(あいまいでごめんなさい)
なので、CreateGraphicsメソッドを使用する場合は、その直後に描画処理を行うようにするといいと思っているのですが、今回PictureBox1.Refreshが入ることでなにかが内部的に変わってしまっているのかなと想像しました。

一応、CreateGraphicsメソッドに頼らずに書くとこうなると思います。

元ネタ:http://social.msdn.microsoft.com/Forums/ja-JP/vbgeneralja/thread/91c41bc2-2a23-4b01-ac95-19760d141dd3
※よく検証してません。想定外のことをするとエラーになります。例:クリック。
Public Class Form1

    Dim WithEvents Picturebox1 As New PictureBox

    Private Sub Form1_Load(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles MyBase.Load
        Me.Picturebox1.Dock = DockStyle.Fill
        Me.Picturebox1.Image = New Bitmap("C:\Documents and Settings\All Users\Documents\My Pictures\Sample Pictures\Water lilies.jpg")
        Me.Controls.Add(Picturebox1)
    End Sub

    Dim IsDragging As Boolean
    Dim startPos As Point
    Private Sub PictureBox1_MouseDown(ByVal sender As ObjectByVal e As System.Windows.Forms.MouseEventArgs) Handles Picturebox1.MouseDown
        startPos = e.Location
        IsDragging = True
    End Sub

    Dim currentPos As Point
    Private Sub PictureBox1_MouseMove(ByVal sender As ObjectByVal e As System.Windows.Forms.MouseEventArgs) Handles Picturebox1.MouseMove
        If IsDragging Then
            currentPos = e.Location
            Picturebox1.Invalidate()
        End If
    End Sub

    Dim p As New Pen(Color.Black, 1)
    Dim selectedRect As Rectangle
    Private Sub Picturebox1_Paint(ByVal sender As ObjectByVal e As System.Windows.Forms.PaintEventArgs) Handles Picturebox1.Paint

        selectedRect = New Rectangle(startPos, currentPos - startPos)

        p.DashStyle = Drawing2D.DashStyle.Dash
        e.Graphics.DrawRectangle(p, selectedRect)
    End Sub

    Private Sub PictureBox1_MouseUp(ByVal sender As ObjectByVal e As System.Windows.Forms.MouseEventArgs) Handles Picturebox1.MouseUp
        
        If Not IsDragging Then
            Return
        End If
        IsDragging = False

        Dim img As New Bitmap(selectedRect.Width, selectedRect.Height)
        Using g As Graphics = Graphics.FromImage(img)
            g.DrawImage(Me.Picturebox1.Image, New Rectangle(0, 0, img.Width, img.Height), selectedRect, GraphicsUnit.Pixel)
        End Using
        Dim f As New Form
        f.BackgroundImage = img
        f.BackgroundImageLayout = ImageLayout.None
        f.ClientSize = img.Size
        f.Show()

    End Sub

End Class

投稿者 (削除されました)  () 投稿日時 2010/8/5 12:46:27
(削除されました)
投稿者 Free   (社会人) 投稿日時 2010/8/5 08:47:26
便乗質問失礼します
>オブジェクト参照がオブジェクト インスタンスに設定されていません。
オブジェクト参照とは何でしょう?
投稿者 トモヤ  (高校生) 投稿日時 2010/8/4 22:41:43
VB2010でしましたけど出来ませんでした。
投稿者 ときお  (社会人) 投稿日時 2010/8/4 21:24:40
エラーはでないようですが、トモヤさんが考えたものとは違った動作をします
環境はVB2010です。
投稿者 トモヤ  (高校生) 投稿日時 2010/8/4 20:40:46
画像の切り取りについて質問します。
まずフォームにPictureBox1、PictureBox2、ボタン1を設置します。

ボタン1に開くと書きます。

ボタン1のコードに
Dim dlgOpen As New OpenFileDialog 'フィルターを設定する 

        dlgOpen.Filter = "ビットマップ(*.bmp)|*.bmp|" & _
            "JPEG(*.jpg)|*.jpg|" & _
            "GIF(*.gif)|*.gif|" & _
            "PNG(*.png)|*.png"

        If dlgOpen.ShowDialog() = Windows.Forms.DialogResult.OK Then
            'PictureBoxにイメージを読み込む 
            PictureBox1.Image = Image.FromFile(dlgOpen.FileName)
            PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage

        End If

こう書きます。

それでマウスのドラッグで範囲を選択し画像を取得してPictureBox2 に表示のコードを見つけてやってみたのですが出来ませんでした。

Private sPos As MouseEventArgs  'マウスのドラッグの開始点 
Private ePos As MouseEventArgs  'マウスのドラッグの終了点 

Private Sub PictureBox1_MouseDown(ByVal sender As ObjectByVal e As _
            System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
    If e.Button = MouseButtons.Left Then
        '開始点の取得 
        sPos = e
        ePos = e
    End If
End Sub


Private Sub PictureBox1_MouseMove(ByVal sender As ObjectByVal e As _
            System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
    'マウスのドラッグで線を引く 
    If e.Button = MouseButtons.Left Then
        Dim g As Graphics = PictureBox1.CreateGraphics()
        Dim BPen As New Pen(Color.Black, 1)
        BPen.DashStyle = Drawing2D.DashStyle.Dash
        '描いたの一旦消す(VB6.0の XorPen の代り)   # ここがこのサンプルのミソ 
        PictureBox1.Refresh()
        '消える描画でドラッグ中の四角形を描く 
        g.DrawRectangle(BPen, sPos.X, sPos.Y, ePos.X - sPos.X, ePos.Y - sPos.Y)
        ePos = e    'マウスポインタの移動終了点を取得 
        g.Dispose()
    End If
End Sub


Private Sub PictureBox1_MouseUp(ByVal sender As ObjectByVal e As _
                System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseUp
    If e.Button = MouseButtons.Left Then
        PictureBox1.Refresh()   '最後の四角形を削除 
        Dim g As Graphics = PictureBox1.CreateGraphics()
        Dim BPen As New Pen(Color.Black, 1)
        BPen.DashStyle = Drawing2D.DashStyle.Dash
        '範囲確定の四角形を描く 
        g.DrawRectangle(BPen, sPos.X, sPos.Y, ePos.X - sPos.X, ePos.Y - sPos.Y)
        g.Dispose()

'-------------- 指定範囲の画像取得部分 ----------------- 
        '四角形の範囲の画像を取得 
        Dim rect As New Rectangle(sPos.X, sPos.Y, ePos.X - sPos.X, ePos.Y - sPos.Y)
        '選択範囲が異常の場合表示処理をしない 
        If (ePos.X - sPos.X) < 2 Or (ePos.Y - sPos.Y) < 2 Then
            Exit Sub
        End If
        'PictureBox2 のサイズを切り取った画像のサイズに合せる 
        Dim g2 As Graphics
        'コピー元の PictureBox を指定の事  
        Dim bmp As Bitmap = New Bitmap(PictureBox1.Image)
        With PictureBox2
            .Image = New Bitmap(ePos.X - sPos.X, ePos.Y - sPos.Y)
            .SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize
            g2 = Graphics.FromImage(.Image)
        End With

        '取得した画像を PictureBox2 に表示 
        g2.DrawImage(bmp, 0, 0, rect, GraphicsUnit.Pixel)
        bmp.Dispose()
        g2.Dispose()
    End If
End Sub



こう書いてビルドして開くを押して画像を開いたらエラーが出ます。

ここの部分です。

 g.DrawRectangle(BPen, sPos.X, sPos.Y, ePos.X - sPos.X, ePos.Y - sPos.Y)


オブジェクト参照がオブジェクト インスタンスに設定されていません。

と出ます。どうすればいいでしょうか?