#c# #winforms #graphics
#c# #winforms #графика
Вопрос:
У меня есть задача: построить фигуру из пары строк и сделать к ней аффинные преобразования. Также мне нужно выполнить эти преобразования самостоятельно: вычислить новые координаты и переместить фигуру с помощью преобразования матрицы. Но у меня ошибка «недопустимый параметр», когда я пытаюсь вызвать свой метод DrawLine. Вы можете мне помочь?
Матричный класс
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Smile
{
class Matrix
{
double[,] matrix;
public Matrix(double[,] matrix)
{
this.matrix = matrix;
}
public int cols
{
get
{
return this.matrix.GetUpperBound(1) 1;
}
}
public int rows
{
get
{
return this.matrix.Length / this.cols;
}
}
public double getElement(int row, int col)
{
return this.matrix[row, col];
}
}
}
Класс Arrow(это фигура, которую я построил из строк), где у меня проблема с Drawar Row(), затем пытаюсь перевести стрелку в новые координаты.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
namespace Smile
{
class Arrow
{
Pen p = new Pen(Color.Blue, 5);// цвет линии и ширина
//Graphics graphics;
Matrix affine, dots;
public Arrow(Graphics graphics)
{
//this.graphics = graphics;
this.DrawArrow(5, 10, 40, 100, 40, 60, 10, 70, graphics);
}
private void DrawArrow(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, Graphics graphics)
{
graphics.DrawLine(this.p, new Point(x1, y1), new Point(x2, y2));
graphics.DrawLine(this.p, new Point(x2, y2), new Point(x3, y3));
graphics.DrawLine(this.p, new Point(x2, y2), new Point(x4, y4));
initializeDotMatrix(x1, y1, x2, y2, x3, y3, x4, y4);
}
public void createAffine(double a, double b, double c, double d)
{
double[,] affine = { { a, b }, { c, d } };
this.affine = new Matrix(affine);
}
private void initializeDotMatrix(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)
{
double[,] dots = { { x1, y1 }, { x2, y2 }, { x3, y3 }, { x4, y4 } };
this.dots = new Matrix(dots);
}
private void reInitializeLines(int[,] coordinates, Graphics graphics)
{
DrawArrow(coordinates[0, 0],
coordinates[0, 1],
coordinates[1, 0],
coordinates[1, 1],
coordinates[2, 0],
coordinates[2, 1],
coordinates[3, 0],
coordinates[3, 1], graphics);
}
public void moveRight(int step, Graphics graphics)
{
createAffine(1, step, 0, 1);
reInitializeLines(this.multiply(), graphics);
}
public int[,] multiply()
{
int[,] result = new int[dots.rows, affine.cols];
for (int resultRow = 0; resultRow < dots.rows; resultRow )
{
for (int resultCol = 0; resultCol < affine.cols; resultCol )
{
double value = 0;
for (int i = 0; i < affine.cols; i )
{
value = dots.getElement(resultRow, i) * affine.getElement(i, resultCol);
}
result[resultRow, resultCol] = Convert.ToInt32(value);
}
}
return resu<
}
}
}
Класс формы
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Smile
{
public partial class Form1 : Form
{
Arrow arrow;
Graphics gr;
bool changed = true;
bool isExist = false;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
this.gr = e.Graphics;
arrow = new Arrow(gr);
}
protected override void OnPaint(PaintEventArgs e)
{
if (!isExist)
{
isExist = false;
this.gr = e.Graphics;
arrow = new Arrow(gr);
}
/*if (changed)
{
changed = false;
//gr.Invalidate();
gr.Clear(Color.White);
base.OnPaint(e);
}*/
}
private void Right_Click(object sender, EventArgs e)
{
changed = true;
arrow.moveRight(200, gr);
}
}
}
Комментарии:
1. Первое, что вам нужно удалить, это это поле :
Graphics gr;
.Right_Click()
предполагаетсяInvalidate()
, что холст (ваша форма, здесь) рисует движение. Решите, хотите ли вы переопределитьOnPaint
событие или подписаться наPaint
него (выберите одно). Затем передайтеnew Arrow(e.Graphics);
.isExist
всегдаfalse
, по крайней мере, из того, что вы здесь показываете: это подразумевает, что…2. Код выглядит немного запутанным. Обратите внимание, что вы не должны пытаться кэшировать графический объект. Что отладчик сообщает вам о каждом из элементов в вызовах DrawLine??
3. Вы должны использовать индексатор вместо
getElement
метода4. @Jimi Я новичок, не могли бы вы рассказать мне, как проверить OnPaint или подписаться на Paint. Если вы можете использовать мой код в качестве примера
Ответ №1:
Я нашел ответ. Посмотрите на мой новый код. Код формы
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Smile
{
public partial class Form1 : Form
{
Arrow arrow;
Graphics gr;
public Form1()
{
InitializeComponent();
gr = pictureBox1.CreateGraphics();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.White);
arrow = new Arrow(e.Graphics);
}
private void Right_Click(object sender, EventArgs e)
{
gr.Clear(Color.White);
arrow.moveX(100,gr);
}
private void Left_Click(object sender, EventArgs e)
{
gr.Clear(Color.White);
arrow.moveX(-100, gr);
}
private void Up_Click(object sender, EventArgs e)
{
gr.Clear(Color.White);
arrow.moveY(-100, gr);
}
private void Down_Click(object sender, EventArgs e)
{
gr.Clear(Color.White);
arrow.moveY(100, gr);
}
private void ScaleX_Click(object sender, EventArgs e)
{
gr.Clear(Color.White);
arrow.scaleX(2, gr);
}
private void ScaleY_Click(object sender, EventArgs e)
{
gr.Clear(Color.White);
arrow.scaleY(2, gr);
}
private void Rotate_Click(object sender, EventArgs e)
{
gr.Clear(Color.White);
arrow.rotate(1,gr);
}
private void ReflectX_Click(object sender, EventArgs e)
{
gr.Clear(Color.White);
arrow.reflectX(1, gr);
}
private void ReflectY_Click(object sender, EventArgs e)
{
gr.Clear(Color.White);
arrow.reflectY(1, gr);
}
}
}
Код матричного класса (необязательно)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Smile
{
class Matrix
{
double[,] matrix;
public Matrix(double[,] matrix)
{
this.matrix = matrix;
}
public int cols
{
get
{
return this.matrix.GetUpperBound(1) 1;
}
}
public int rows
{
get
{
return this.matrix.Length / this.cols;
}
}
public double getElement(int row, int col)
{
return this.matrix[row, col];
}
}
}
Класс стрелки
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
namespace Smile
{
class Arrow
{
Pen p = new Pen(Color.Blue, 5);
Matrix affine, dots;
public Arrow(Graphics graphics)
{
this.DrawArrow(755, 60, 790, 150, 790, 110, 760, 120, graphics);
}
private void DrawArrow(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, Graphics graphics)
{
graphics.DrawLine(this.p, new Point(x1, y1), new Point(x2, y2));
graphics.DrawLine(this.p, new Point(x2, y2), new Point(x3, y3));
graphics.DrawLine(this.p, new Point(x2, y2), new Point(x4, y4));
initializeDotMatrix(x1, y1, x2, y2, x3, y3, x4, y4);
}
public void createAffine(double a, double b, double b1, double c, double d, double d1, double e0, double e1, double e2)
{
double[,] affine = { { a, b, b1 }, { c, d, d1 }, { e0, e1, e2 } };
this.affine = new Matrix(affine);
}
private void initializeDotMatrix(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)
{
double[,] dots = { { x1, y1, 1 }, { x2, y2, 1 }, { x3, y3, 1 }, { x4, y4, 1 } };
this.dots = new Matrix(dots);
}
private void reInitializeLines(int[,] coordinates, Graphics graphics)
{
DrawArrow(coordinates[0, 0],
coordinates[0, 1],
coordinates[1, 0],
coordinates[1, 1],
coordinates[2, 0],
coordinates[2, 1],
coordinates[3, 0],
coordinates[3, 1], graphics);
}
public void scaleX(int step, Graphics graphics)
{
createAffine(step, 0, 0, 0, 1, 0, 0, 0, 1);
reInitializeLines(this.multiply(), graphics);
}
public void scaleY(int step, Graphics graphics)
{
createAffine(1, 0, 0, 0, step, 0, 0, 0, 1);
reInitializeLines(this.multiply(), graphics);
}
public void scaleXY(int step, Graphics graphics)
{
createAffine(step, 0, 0, 0, step, 0, 0, 0, 0);
reInitializeLines(this.multiply(), graphics);
}
public void moveX(int step, Graphics graphics)
{
createAffine(1, 0, 0, 0, 1, 0, step, 0, 1);
reInitializeLines(this.multiply(), graphics);
}
public void moveY(int step, Graphics graphics)
{
createAffine(1, 0, 0, 0, 1, 0, 0, step, 1);
reInitializeLines(this.multiply(), graphics);
}
public void rotate(double step, Graphics graphics)
{
createAffine(Math.Cos(step), Math.Sin(step), 0, -Math.Sin(step), Math.Cos(step), 0, 0, 0, 1);
reInitializeLines(this.multiply(), graphics);
}
public void reflectY(int step, Graphics graphics)
{
createAffine(step, 0, 0, 0, -step, 0, 0, 0, 1);
reInitializeLines(this.multiply(), graphics);
createAffine(1, 0, 0, 0, 1, 0, 0, 500, 1);
reInitializeLines(this.multiply(), graphics);
}
public void reflectX(int step, Graphics graphics)
{
createAffine(-step, 0, 0, 0, step, 0, 0, 0, 1);
reInitializeLines(this.multiply(), graphics);
createAffine(1, 0, 0, 0, 1, 0, 1000, 0, 1);
reInitializeLines(this.multiply(), graphics);
}
public int[,] multiply()
{
int[,] result = new int[dots.rows, affine.cols];
for (int resultRow = 0; resultRow < dots.rows; resultRow )
{
for (int resultCol = 0; resultCol < affine.cols; resultCol )
{
double value = 0;
for (int i = 0; i < affine.cols; i )
{
value = dots.getElement(resultRow, i) * affine.getElement(i, resultCol);
}
result[resultRow, resultCol] = Convert.ToInt32(value);
}
}
return resu<
}
}
}
Итак, моя проблема заключалась в использовании графики из PaintEventArg. Но я могу получить те же параметры из PictureBox.Создайте graphics(), а затем перерисуйте по своему усмотрению) Удачи всем исследователям! Я хочу помочь другим в решении моей проблемы.