2

我有一个 C# 中的 Windows 窗体应用程序,带有绘图面板和一个按钮 - 用于绘制一条线。

单击按钮时,您可以为 2 个随机点绘制一条线。

Pen p = new Pen(Color.Black, 5);
//point for start 
Point ps = new Point();
//point for end 
Point pe = new Point();

private void drawPanel_MouseDown(object sender, MouseEventArgs e)
{
  ps.X = e.X;
  ps.Y = e.Y;
  pe = ps;
}

private void drawPanel_MouseMove(object sender, MouseEventArgs e)
{
  // when button is clicked for drawing draw = true;
  if (draw)
  {
    if (e.Button == MouseButtons.Left)
    { 
      pe = new Point(e.X, e.Y);
    }
  }
}

private void drawPanel_MouseUp(object sender, MouseEventArgs e)
{
  onMouseUpFlag = true;
}

private void drawPanel_Paint(object sender, PaintEventArgs e)
{
  Graphics g = drawPanel.CreateGraphics();
  if (onMouseUpFlag)
  {
    g.DrawLine(p, ps, pe); 
    g.Dispose(); 
  }
} 

该程序有一些缺陷:

  • 当你画一条线时,它会显示它,只有当主窗口移动到某个地方时(通常是当我隐藏它时)
  • 它只能绘制 1 条线。

任何建议如何解决这些错误?

编辑

我已经阅读了您的答案并进行了一些更改:

Pen p = new Pen(Color.Black, 5); 
Point ps = new Point();
Point pe = new Point();

List<Point> linesStart= new List<Point>();
List<Point> linesEnd= new List<Point>();

private void drawPanel_MouseDown(object sender, MouseEventArgs e)
{
  ps.X = e.X;
  ps.Y = e.Y;

  linesStart.Add(ps);

  pe = ps;
}

private void drawPanel_MouseMove(object sender, MouseEventArgs e)
{
  if (e.Button == MouseButtons.Left)
  {
    pe = new Point(e.X, e.Y);

    //adding end point .. actually adds a lot of points 
    linesEnd.Add(pe);
  }
}

bool onMouseUpFlag = false;

private void drawPanel_MouseUp(object sender, MouseEventArgs e)
{
  onMouseUpFlag = true;
  drawPanel.Invalidate();
}

private void drawPanel_Paint(object sender, PaintEventArgs e)
{ 
  if (onMouseUpFlag)
  {
    for (int i = 0; i < linesStart.Count; i++)
    {
      e.Graphics.DrawLine(p, linesStart[i], linesEnd[i]);
    } 
  }
} 

现在我正在尝试为多条线修复 DrawLine。Paint 事件可以做多行,但只有起点是好的。不知何故,终点不是很正确。在哪里可以准确设置 MouseMove 事件的最后一点?

4

3 回答 3

3

您必须调用面板上的 Invalidate 方法:

private void drawPanel_MouseUp(object sender, MouseEventArgs e)
{
  onMouseUpFlag = true;
  drawPanel.Invalidate();
}

此外,使用 PaintEvent 中的 Graphic 对象:

private void drawPanel_Paint(object sender, PaintEventArgs e)
{
  if (onMouseUpFlag)
  {
    e.Graphics.DrawLine(p, ps, pe); 
  }
} 

对于多行,您必须将点保存在集合对象中。

根据您更新的代码,这是一个我认为您正在尝试做的工作示例:

private class Line {
  public Point Starting { get; set; }
  public Point Ending { get; set; }

  public Line(Point starting, Point ending) {
    this.Starting = starting;
    this.Ending = ending;
  }
}
List<Line> lines = new List<Line>();

private Point downPoint = Point.Empty;
private Point movePoint = Point.Empty;
private bool movingLine = false;

public Form1() {
  InitializeComponent();

  panel1.Paint += panel1_Paint;
  panel1.MouseDown += panel1_MouseDown;
  panel1.MouseMove += panel1_MouseMove;
  panel1.MouseUp += panel1_MouseUp;
}

void panel1_MouseDown(object sender, MouseEventArgs e) {
  if (e.Button == MouseButtons.Left) {
    downPoint = e.Location;
  }
}

void panel1_MouseMove(object sender, MouseEventArgs e) {
  if (e.Button == MouseButtons.Left) {
    movingLine = true;
    movePoint = e.Location;
    panel1.Invalidate();
  }
}

void panel1_MouseUp(object sender, MouseEventArgs e) {
  if (e.Button == MouseButtons.Left) {
    movingLine = false;
    lines.Add(new Line(downPoint, e.Location));
    panel1.Invalidate();
  }
}

void panel1_Paint(object sender, PaintEventArgs e) {
  e.Graphics.Clear(Color.White);
  foreach (Line l in lines) {
    e.Graphics.DrawLine(Pens.Black, l.Starting, l.Ending);
  }

  if (movingLine) {
    e.Graphics.DrawLine(Pens.Black, downPoint, movePoint);
  }

}

使用继承的面板打开 DoubleBuffer 属性以避免闪烁。

于 2012-10-29T20:28:36.677 回答
1

每当你想重绘(在你的代码中)你应该调用 panelinvalidate drawPanel.Invalidate()

当您完成鼠标移动并释放按钮时

private void drawPanel_MouseUp(object sender, MouseEventArgs e)
{
            onMouseUpFlag = true;
            drawPanel.Invalidate();
}

最后,我建议在您的 drawPanel_Paint 中使用此代码而不是您的代码。您应该使用 EventArgs 提供的图形,而不是创建新图形。

private void drawPanel_Paint(object sender, PaintEventArgs e)
{
            if (onMouseUpFlag)
            {
                  e.Graphics.DrawLine(p, ps, pe); 
            }
}
于 2012-10-29T20:29:25.727 回答
1
  1. 放开鼠标后需要触发重绘事件。只需调用drawPanel.Invalidate()即可重新绘制表单。

  2. 要绘制多条线,您必须将每条线的信息存储在列表或其他内容中,并在重绘中绘制每条线。Paint 方法基本上每次都以空格开头,因此它只会按照您当前设置的方式绘制最新的。

于 2012-10-29T20:32:00.423 回答