2

大きな円を「周回」する小さな円を示す「PictureBox」を開発しようとしています。重要な側面は、この小さな円の位置 (したがって全体像) が、私が毎秒行うやや高価なハードウェア呼び出しに基づいて変化する可能性があることです。説明のために「AngleValueTextBox」呼び出しを代用しています。

このトピックに関するいくつかの記事を調べたところ、これが適切な方法のようです。

public partial class Form1 : Form
{
  public Form1()
  {
    InitializeComponent();

    AngleValueTextBox_TextChanged(null, null); // Why doesn't this make the box appear on program start?
    PictureBox.Invalidate();  // Or this?
  }

  public class CircleCenterClass { public double X; public double Y; 
    public CircleCenterClass(double X, double Y) { this.X = X; this.Y = Y; }
  }

  CircleCenterClass GetCenterOfOrbitCircle(CircleCenterClass OrbitCenter, double OrbitRadius, double Angle)
  {
    CircleCenterClass Result = new CircleCenterClass(0, 0);
    Result.X = OrbitCenter.X + OrbitRadius * Math.Sin(Angle * (3.141592654 / 180));
    Result.Y = OrbitCenter.Y - OrbitRadius * Math.Cos(Angle * (3.141592654 / 180));
    return Result;
  }

  private void drawPictureBox(Graphics graphics, bool ownGraphics)
  {
    double Angle= 0; 
    // Normally this is an expensive hardware call which I don't want to make more than 
    // once a second.
    try {
      Double.TryParse(AngleValueTextBox.Text, out Angle);
    } catch (Exception e) {
      MessageBox.Show("Could not parse Angle " + 
                       AngleValueTextBox.Text);
    }

    using (Bitmap bitmap = new Bitmap(PictureBox.Width, PictureBox.Height))
    {
      using (Graphics gx = Graphics.FromImage(bitmap))
      {
        double OrbitedCircleRadius = 40;
        CircleCenterClass OrbitedCircleCenter = new CircleCenterClass(60, 60);
        double OrbitingCircleRadius = 7;
        Pen MyRedPen = new Pen(Color.Red, 2f);
        Brush MyBlackBrush = new SolidBrush(Color.Black);

        gx.DrawEllipse(MyRedPen, (Int32)(OrbitedCircleCenter.X - OrbitedCircleRadius),
                                        (Int32)(OrbitedCircleCenter.Y - OrbitedCircleRadius),
                                        (Int32)(2 * OrbitedCircleRadius),
                                        (Int32)(2 * OrbitedCircleRadius));

        CircleCenterClass CircleCenter = GetCenterOfOrbitCircle(
                            OrbitedCircleCenter, OrbitedCircleRadius,
                            Angle);

        gx.FillEllipse(MyBlackBrush, (Int32)(CircleCenter.X - OrbitingCircleRadius),
                                     (Int32)(CircleCenter.Y - OrbitingCircleRadius),
                                     (Int32)(2 * OrbitingCircleRadius),
                                     (Int32)(2 * OrbitingCircleRadius));

        // Draw Electronics box. 
        Graphics g = PictureBox.CreateGraphics();
        g.Clear(BackColor);
        g.DrawImage(bitmap, 0, 0);  
      }
    }
  }

  private void PictureBox_Paint(object sender, PaintEventArgs e)
  {
    drawPictureBox(e.Graphics,false);
  }

  private void AngleValueTextBox_TextChanged(object sender, EventArgs e)
  {
    drawPictureBox(PictureBox.CreateGraphics(), true);
  }
}

主な質問:

  1. 最初に画像を表示できません (つまり、GUI の起動時)。Form コンストラクターにイベントを追加しようとしましたが (ご覧のとおり)、うまくいきませんでした。「正しい」方法は何ですか?

  2. 絶えず変化するグラフィックを描画するより良い方法はありますか?

4

3 に答える 3

0
  1. CreateGraphics を使用することが、表示を更新する正しい方法になることはめったにありません。ペイント メソッドですべてのペイントを行い、コントロールの Invalidate() メソッドを呼び出して画面を更新するだけです。

  2. ペイント イベントが接続されていることを確認します (念のため)。デザイナーで接続されていない場合は、これがフォームのコンストラクターにあることを確認してください。

    PictureBox.Paint += PictureBox_Paint;

    また、コントロールに名前を付けます。PictureBox はあまり説明的ではありません。

  3. UI がフリーズしないように、「やや高価なハードウェア呼び出し」は BackgroundWorker で行う必要があります。

  4. 新しい描画で画面を継続的に更新しようとする場合は、タイマーを使用します。

  5. ペイント呼び出しごとに新しいビットマップを作成する必要はありません。指定されたグラフィック オブジェクトを使用するか、コントロールのサイズが変更されたときにのみ作成される 1 つのビットマップを使用します。

于 2013-04-10T14:16:47.577 に答える
0

描画メソッド呼び出しを Form のLoadイベントに追加します。

于 2013-04-10T14:07:50.397 に答える
0

PictureBoxControl をPanel呼び出された PictureBoxに置き換えます

または、Picture Box のImageプロパティを作成したビットマップに設定します。

これは特に効率的な方法ではないことに注意してください。

画像が毎秒のみ更新される場合、値が変更された場合にのみ画像に描画できます。ビットマップをフォームのプライベート プロパティとして保持し、ビットマップをペイントにコピーするだけです (あなたが行うのと同じですが、すべてを取り出します)。コードを描画し、値が変更されたときにのみ実行します)

ここに画像の説明を入力

    Bitmap bitmap;
    public Form1()
    {
        InitializeComponent();
        bitmap = new Bitmap(PictureBox.Width, PictureBox.Height);
        AngleValueTextBox_TextChanged(null, null); // Why doesn't this make the box appear on program start?
        PictureBox.Invalidate();  // Or this?
    }

    public class CircleCenterClass
    {
        public double X; public double Y;
        public CircleCenterClass(double X, double Y) { this.X = X; this.Y = Y; }
    }

    CircleCenterClass GetCenterOfOrbitCircle(CircleCenterClass OrbitCenter, double OrbitRadius, double Angle)
    {
        CircleCenterClass Result = new CircleCenterClass(0, 0);
        Result.X = OrbitCenter.X + OrbitRadius * Math.Sin(Angle * (3.141592654 / 180));
        Result.Y = OrbitCenter.Y - OrbitRadius * Math.Cos(Angle * (3.141592654 / 180));
        return Result;
    }

    private void drawPictureBox(Graphics graphics, bool ownGraphics)
    {



    }

    private void DrawImage()
    {
        double Angle = 0;
        // Normally this is an expensive hardware call which I don't want to make more than 
        // once a second.
        try
        {
            Double.TryParse(AngleValueTextBox.Text, out Angle);
        }
        catch (Exception e)
        {
            MessageBox.Show("Could not parse Angle " +
                             AngleValueTextBox.Text);
        }

        using (Graphics gx = Graphics.FromImage(bitmap))
        {
            gx.Clear(BackColor);
            double OrbitedCircleRadius = 40;
            CircleCenterClass OrbitedCircleCenter = new CircleCenterClass(60, 60);
            double OrbitingCircleRadius = 7;
            Pen MyRedPen = new Pen(Color.Red, 2f);
            Brush MyBlackBrush = new SolidBrush(Color.Black);

            gx.DrawEllipse(MyRedPen, (Int32)(OrbitedCircleCenter.X - OrbitedCircleRadius),
                                            (Int32)(OrbitedCircleCenter.Y - OrbitedCircleRadius),
                                            (Int32)(2 * OrbitedCircleRadius),
                                            (Int32)(2 * OrbitedCircleRadius));

            CircleCenterClass CircleCenter = GetCenterOfOrbitCircle(
                                OrbitedCircleCenter, OrbitedCircleRadius,
                                Angle);

            gx.FillEllipse(MyBlackBrush, (Int32)(CircleCenter.X - OrbitingCircleRadius),
                                         (Int32)(CircleCenter.Y - OrbitingCircleRadius),
                                         (Int32)(2 * OrbitingCircleRadius),
                                         (Int32)(2 * OrbitingCircleRadius));
        }
    }

    private void PictureBox_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.DrawImage(bitmap, 0, 0);
    }

    private void AngleValueTextBox_TextChanged(object sender, EventArgs e)
    {
        DrawImage();
        PictureBox.Invalidate();
    }
于 2013-04-10T14:33:47.657 に答える