我正在尝试开发一个“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);
}
}
关键问题:
我无法让图片最初显示(即GUI启动时)。我已经尝试将事件添加到我的Form构造函数中(如您所见),但没有运气。什么是“正确”的方式?
有没有更好的方法来绘制不断变化的图形?
答案 0 :(得分:0)
将draw方法调用添加到Form的Load事件。
答案 1 :(得分:0)
使用CreateGraphics很少是更新显示的正确方法。只需让你的paint方法完成所有绘画并调用控件Invalidate()方法来更新屏幕。
确保绘制事件已连线(只是为了确保)。如果没有在设计器中连接,请确保它在表单的构造函数中:
PictureBox.Paint += PictureBox_Paint;
另外,为控件命名。 PictureBox不是很具描述性。
任何“半昂贵的硬件调用”都应该在BackgroundWorker中进行,这样就不会冻结用户界面。
如果只是不断尝试使用新图纸更新屏幕,请使用计时器。
您不需要在每次绘制调用时都创建新的位图。使用给定的图形对象或使用仅在控件调整大小时创建的一个位图。
答案 2 :(得分:0)
将PictureBox
控件替换为名为PictureBox的Panel
或将图片框的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();
}