我试图找出一种方法,在该方法中,用户可以在图像上拖动网格,然后调整列和行的大小以适合图像。我将如何去创造这样的东西?我在网上找不到类似的东西。
我想让用户在图像上拖动一个网格并调整其大小以适合图像。
所以本质上,我们在表单中有一个图像,然后在图像上使用一个可拖动和可调整大小的网格。
最后,我想让用户在图像中的数据上拖动一个网格,然后我想使用 OCR 读取与图像上的单元格相对应的每个区域中的数据。这样我就可以在第 2 行中选择 col 2 并专门读取该数据。
这是一个网格类,可以覆盖在任何网格上Control,并将绘制一个N x M网格线。
您可以使用鼠标移动线条并使用鼠标右键移动网格。您可以访问两个List<int> Xs和 中的当前 x 和 y 值Ys。
它是一个Panel子类,您应该确保它具有正确的大小和行列数。
让我们看看它的实际效果:
要设置它使用该Init功能..
这是代码:
public partial class Grid : Panel
{
public Grid()
{
InitializeComponent();
GridColor = Color.DarkMagenta;
HandleSize = 4;
BackColor = Color.Transparent;
DoubleBuffered = true;
}
int RowCount { get; set; }
int ColCount { get; set; }
Color GridColor { get; set; }
int HandleSize { get; set; }
List<int> Xs { get; set; }
List<int> Ys { get; set; }
public void Init(int cols, int rows)
{
RowCount = rows;
ColCount = cols;
Xs = new List<int>();
Ys = new List<int>();
float w = 1f * Width / cols;
float h = 1f * Height / rows;
for (int i = 0; i <= cols; i++) Xs.Add((int)(i * w));
for (int i = 0; i <= rows; i++) Ys.Add((int)(i * h));
// draw inside the panel only
if (Xs[cols] == Width) Xs[cols]--;
if (Ys[rows] == Height) Ys[cols]--;
}
public void Init(int cols, int rows, Size sz)
{
Size = sz;
Init(cols, rows);
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
using (Pen pen = new Pen(GridColor))
{
foreach (int x in Xs) pe.Graphics.DrawLine(pen, x, 0, x, Height);
foreach (int y in Ys) pe.Graphics.DrawLine(pen, 0, y, Width, y);
}
}
private Point mDown = Point.Empty;
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (Cursor != Cursors.Default) mDown = e.Location;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
// distances
var dx = Xs.Select(x => Math.Abs(x - e.X));
var dy = Ys.Select(y => Math.Abs(y - e.Y));
// smallest distance
int mx = dx.Min();
int my = dy.Min();
// grid index
int ix = dx.ToList().IndexOf(mx);
int iy = dy.ToList().IndexOf(my);
if (e.Button.HasFlag(MouseButtons.Right))
{ // move the grid with the right mouse button
Location = new Point(Left + e.X - mDown.X, Top + e.Y - mDown.Y);
}
else if (!e.Button.HasFlag(MouseButtons.Left))
{ // if we are close enough set cursor
Cursor = Cursors.Default;
if (mx < HandleSize) Cursor = Cursors.SizeWE;
if (my < HandleSize) Cursor = Cursors.SizeNS;
if (mx < HandleSize && my < HandleSize) Cursor = Cursors.SizeAll;
}
else
{ // else move grid line(s)
if (Cursor == Cursors.SizeWE || Cursor == Cursors.SizeAll)
Xs[ix] += e.X - mDown.X;
if (Cursor == Cursors.SizeNS || Cursor == Cursors.SizeAll)
Ys[iy] += e.Y - mDown.Y;
Invalidate();
mDown = e.Location;
// restore order in case we overshot
Xs = Xs.OrderBy(x => x).ToList();
Ys = Ys.OrderBy(x => x).ToList();
}
}
}
Run Code Online (Sandbox Code Playgroud)
这只是一个快速的镜头,很多事情都可以而且可能应该改进,比如添加和删除列和行、验证等。
我将它设置为覆盖Panel panel1这样的:
Grid grid1 = new Grid();
panel1.Controls.Add(grid1);
//grid1.Size = panel1.ClientSize; // overlay full area..or..
grid1.Init(4, 3, new Size(99, 44)); // .. use the overload with size
grid1.Invalidate();
Run Code Online (Sandbox Code Playgroud)
要让用户将其放置并调整到他想要的位置,您可以改用通常的鼠标事件。
更新:在重新阅读时,我看到您还想让用户调整网格的大小。以下是如何扩展代码以允许从左边缘或右边缘调整大小的示例:
{ // else move gridline or size grid
if (Cursor == Cursors.SizeWE || Cursor == Cursors.SizeAll)
{
int delta = mDown.X - e.X;
if (ix == 0) // left edge: resize
{
Width += delta;
Left -= delta;
Xs[Xs.Count - 1] = Width - 1;
}
else if (ix == Xs.Count - 1) // right edge resize
{
Width -= delta;
Xs[Xs.Count - 1] = Width - 1;
}
else Xs[ix] -= delta; // move gridline
}
Run Code Online (Sandbox Code Playgroud)
顶部和底部边缘将以相同的方式工作。与线交叉点一样,调整大小也适用于角落。
更新:代替 a Panel,它是一个Container控件,并不真正打算绘制到您可以使用 aPicturebox或 a Label(with Autosize=false); 两者都有DoubleBuffered开箱即用的属性,并且比做更好地支持绘图Panels。
| 归档时间: |
|
| 查看次数: |
704 次 |
| 最近记录: |