13

私は一種の描画プログラムに取り組んでいますが、ラバーバンドの線を描画しているときにマウスカーソルを移動するとちらつくという問題があります。その線のちらつきを取り除くのを手伝ってくれることを願っています。コードは次のとおりです。

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

namespace GraphicsTest
{
    public partial class Form1 : Form
    {
        int xFirst, yFirst;
        Bitmap bm = new Bitmap(1000, 1000);
        Graphics bmG;
        Graphics xG;
        Pen pen = new Pen(Color.Black, 1);
        bool draw = false;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            bmG = Graphics.FromImage(bm);
            xG = this.CreateGraphics();
            bmG.Clear(Color.White);
        }

        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            xFirst = e.X;
            yFirst = e.Y;
            draw = true;
        }

        private void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            bmG.DrawLine(pen, xFirst, yFirst, e.X, e.Y);
            draw = false;
            xG.DrawImage(bm, 0, 0);
        }

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if (draw)
            {
                xG.DrawImage(bm, 0, 0);
                xG.DrawLine(pen, xFirst, yFirst, e.X, e.Y);
            }
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            xG.DrawImage(bm, 0, 0);
        }
    }
}
4

4 に答える 4

32

CreateGraphics()絶対に必要でない限り、まず使用しないでください。イベント ハンドラーを にバインドし、サーフェスを更新するときにOnPaint呼び出します。Invalidate()

ちらつきを防ぎたい場合は、描画面をダブル バッファリングする必要があります。これを行う最も簡単な方法は、フォームのDoubleBufferedプロパティを True に設定することです。

これを拡張して PictureBox コントロールへの描画を行うことを計画している場合は、強くお勧めします。PictureBox はデフォルトでダブル バッファリングされており、描画領域をより簡単に制御できます。

コード内:

public partial class Form1 : Form
    {
    int xFirst, yFirst;
    Bitmap bm = new Bitmap(1000, 1000);
    Graphics bmG;
    Pen pen = new Pen(Color.Black, 1);
    bool draw = false;

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        bmG = Graphics.FromImage(bm);
        bmG.Clear(Color.White);
    }

    private void Form1_MouseDown(object sender, MouseEventArgs e)
    {
        xFirst = e.X;
        yFirst = e.Y;
        draw = true;
    }

    private void Form1_MouseUp(object sender, MouseEventArgs e)
    {
        bmG.DrawLine(pen, xFirst, yFirst, e.X, e.Y);
        draw = false;
        Invalidate();
    }

    private void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        if (draw)
        {
            Invalidate();
        }
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        if (draw) {
            e.Graphics.DrawImage(bm, 0, 0);
            e.Graphics.DrawLine(pen, xFirst, yFirst, e.X, e.Y);
        } else {
            e.Graphics.DrawImage(bm, 0, 0);
        }
    }
}

編集:

別の問題として、プライベートPenメンバーを作成しています。ペン (およびブラシ、および多くの GDI+ オブジェクト) は、破棄する必要があるアンマネージ オブジェクトへのハンドルを表します。そうしないと、プログラムがリークします。それらをステートメントでラップするusing(推奨される例外セーフな方法) か、フォームのDisposeメソッドで明示的に破棄します。

別の方法として、System.Drawing では、破棄する必要のない (そしてすべきではない) 事前構築済みのペンとブラシにアクセスできます。次のように使用します。

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        if (draw) {
            e.Graphics.DrawImage(bm, 0, 0);
            e.Graphics.DrawLine(Pens.Black, xFirst, yFirst, e.X, e.Y);
        } else {
            e.Graphics.DrawImage(bm, 0, 0);
        }
    }
于 2010-04-09T16:02:12.780 に答える
9

ちらつく理由は、背景を描いて(すぐに画面に表示され、線を一掃する)、線を重ねるためです。したがって、線が消えたり現れたりし続け、ちらつき表示になります。

これに対する最善の解決策は、ダブル バッファリングと呼ばれます。画像全体を「オフスクリーン」ビットマップに描画し、完成したときにのみ画面に表示します。完成した画像のみを表示するため、ちらつき効果はありません。this.DoubleBuffered = true を設定して、WinForms にすべてのハードワークを実行させることができるはずです。

注意: 実際には、ペイント ハンドラーの外で描画す​​るべきではありません。理想的には、再描画が必要な領域を Invalidate() する必要があります。そうすれば、ペイント ハンドラーはその領域だけを再描画します (必要に応じてオーバーレイされた線などを使用)。

于 2010-04-09T16:03:43.947 に答える
2

修正済みの作業コード。

public partial class Form1 : Form
{
    int x1, y1, x2, y2;
    bool drag = false;

    Bitmap bm = new Bitmap(1000, 1000);
    Graphics bmg;


    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        bmg = Graphics.FromImage(bm);
    }

    private void pictureBox_MouseDown(object sender, MouseEventArgs e)
    {
        drag = true;
        x1 = e.X;
        y1 = e.Y;
    }

    private void pictureBox_MouseUp(object sender, MouseEventArgs e)
    {
        drag = false;

        bmg.DrawLine(Pens.Black, x1, y1, e.X, e.Y);
        pictureBox.Invalidate();
    }

    private void pictureBox_MouseMove(object sender, MouseEventArgs e)
    {
        if (drag)
        {
            x2 = e.X;
            y2 = e.Y;
            pictureBox.Invalidate();
        }
    }

    private void pictureBox_Paint(object sender, PaintEventArgs e)
    {
        if (drag) {
            e.Graphics.DrawImage(bm, 0, 0);
            e.Graphics.DrawLine(Pens.Black, x1, y1, x2, y2);            
        }
        else {
            e.Graphics.DrawImage(bm, 0, 0);
        }
    }
}
于 2010-04-09T17:19:39.147 に答える
0

これを使用して、パネルへのダブルバッファリングを管理します。

myPanel.GetType().GetMethod("SetStyle",
    System.Reflection.BindingFlags.Instance |
    System.Reflection.BindingFlags.NonPublic).Invoke(myPanel,
        new object[]
        {
            System.Windows.Forms.ControlStyles.UserPaint | 
            System.Windows.Forms.ControlStyles.AllPaintingInWmPaint |
            System.Windows.Forms.ControlStyles.DoubleBuffer, true
        });
于 2020-08-28T10:50:14.810 に答える