Я играю с System.Drawing
и у меня это работает так, как я хотел, кроме одного. Когда я отпускаю кнопку мыши, линия исчезает.
Как я могу гарантировать, что строка останется именно там, где я ее оставил?
using System;
using System.Drawing;
using System.Windows.Forms;
namespace DrawingSample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.DoubleBuffered = true;
}
Graphics graphics;
Random
color = new Random(1);
Int32
penThickness = 1;
Point
currentCursorLocation, initialTouchLocation, touchOffset;
Boolean
mouseDown;
protected override void OnPaint(PaintEventArgs e)
{
graphics = e.Graphics;
if (mouseDown)
{
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
//DrawRectangle(graphics);
//DrawEllipse(graphics);
DrawLine(graphics);
}
}
private void DrawRectangle(Graphics graphics)
{
graphics.DrawRectangle(new Pen(
Color.FromArgb((color.Next(1,
255)),
(color.Next(1,
255)),
(color.Next(1,
255)))
,
penThickness),
currentCursorLocation.X,
currentCursorLocation.Y,
(this.Width / 2),
(this.Height / 2)
);
}
private void DrawEllipse(Graphics graphics)
{
graphics.DrawEllipse(new Pen(
Color.FromArgb((color.Next(1, 255)),
(color.Next(1, 255)),
(color.Next(1, 255))), penThickness),
new RectangleF(currentCursorLocation, new Size(100, 100)));
}
private void DrawLine(Graphics graphics)
{
graphics.DrawLine(new Pen(
Color.FromArgb((color.Next(1, 255)),
(color.Next(1, 255)),
(color.Next(1, 255))), penThickness),
currentCursorLocation.X,
currentCursorLocation.Y,
touchOffset.X,
touchOffset.Y
);
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
currentCursorLocation = e.Location;
this.Refresh();
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (!mouseDown)
{
touchOffset = e.Location;
mouseDown = true;
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
mouseDown = false;
}
}
}
Вы просите код вести себя так. Так оно делает то же самое.
Вы устанавливаете mouseDown
в false в событии Form1_MouseUp
.
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
mouseDown = false; //<--Here
}
Затем вы проверяете, есть if (mouseDown)
прежде чем рисовать линию.
protected override void OnPaint(PaintEventArgs e)
{
graphics = e.Graphics;
if (mouseDown)//<--Here
{
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
//DrawRectangle(graphics);
//DrawEllipse(graphics);
DrawLine(graphics);
}
}
Я думаю, вам не нужно, if (mouseDown)
проверяет метод OnPaint
.
Не знаете, каковы ваши намерения. Если вам нужна дополнительная помощь, напишите комментарий ниже ответа.
Вероятно, вы хотите сохранить список всех рисованных линий в отдельном поле, чтобы иметь возможность их перерисовывать по мере необходимости. Другими словами, если вы определяете класс следующим образом:
class Line
{
public Point Start { get; set; }
public Point End { get; set; }
}
Это позволяет вам иметь как список уже нарисованных линий, так и текущую линию (пока мышь удерживается):
// this is the line currently being drawn (i.e. a temporary line)
private Line _currentLine = null;
// this is the list of all finished lines
private readonly List<Line> _lines = new List<Line>();
Обработчики мыши теперь просты:
protected override void OnMouseDown(MouseEventArgs e)
{
// when button is pressed, create a new _currentLine instance
_currentLine = new Line() { Start = e.Location, End = e.Location };
Invalidate();
base.OnMouseDown(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
// when mouse is moved, update the End position
if (_currentLine != null)
{
_currentLine.End = e.Location;
Invalidate();
}
base.OnMouseMove(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
// when button is released, add the line to the list
if (_currentLine != null)
{
_lines.Add(_currentLine);
_currentLine = null;
Invalidate();
}
base.OnMouseUp(e);
}
И метод OnPaint
будет выглядеть примерно так:
protected override void OnPaint(PaintEventArgs e)
{
// if you want smoother (anti-aliased) graphics, set these props
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
// draw all existing lines from the list
using (var p = new Pen(Color.Black, 2f))
foreach (var line in _lines)
e.Graphics.DrawLine(p, line.Start, line.End);
// if mouse is down, draw the dashed line also
if (_currentLine != null)
using (var p = new Pen(Color.Salmon, 2f))
{
p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
e.Graphics.DrawLine(p, _currentLine.Start, _currentLine.End);
}
base.OnPaint(e);
}
Кроме того, гораздо меньше мерцания, если вы используете метод Form.SetStyles
в конструкторе, чтобы указать, что вы будете делать все рисование самостоятельно и не хотите, чтобы Windows Form.SetStyles
форму самостоятельно. Это означает, что ваш конструктор формы должен выглядеть примерно так:
public Form1()
{
InitializeComponent();
SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.ResizeRedraw |
ControlStyles.UserPaint,
true);
}
Сохранение списка строк намного лучше, чем просто рисование их на поверхности, поскольку оно позволяет:
Shape
(или интерфейс IShape
), который будет представлять его метод Draw(Graphics g)
и рисовать сам. Это означает, что вместо линии будет список фигур и текущая фигура, и вы, вероятно, выберете тип фигуры из меню.
Nullable<T>
проверяете лиnullable.HasValue
и рисуете ли вы его. Вам не нужно проверятьif (mouseDown)
.