Создание сетки с изменяемыми размерами для наложения на изображение с помощью C # - PullRequest
0 голосов
/ 27 августа 2018

Я пытаюсь выяснить метод, в котором пользователь может перетаскивать сетку поверх изображения, а затем изменять размеры столбцов и строк, чтобы соответствовать изображению. Как мне создать что-то подобное? Я не смог найти ничего похожего в Интернете.

Я хочу, чтобы пользователь перетянул сетку на изображение и изменил его размер, чтобы он соответствовал изображению.

Они перетаскивают нижнюю сетку на изображение (будучи числами) Before

и в конечном итоге, после изменения размера таблицы After

По сути, у нас есть изображение в форме, а затем перетаскиваемая и изменяемая в размерах сетка для использования поверх изображения.

В конце я хочу, чтобы пользователь перетаскивал сетку поверх данных на изображении, а затем я хотел бы использовать OCR для считывания данных в каждой области, соответствующей ячейке на изображении. Таким образом, я могу затем выбрать, скажем, столбец 2 в строке 2 и прочитать только эти данные.

1 Ответ

0 голосов
/ 27 августа 2018

Вот класс сетки, который может быть наложен на любой Control и нарисует N x M сетку линий.

Вы можете перемещать линии мышью и перемещать сетку правой кнопкой мыши. Вы можете получить доступ к текущим значениям x и y в двух List<int> Xs и Ys.

Это подкласс Panel, и вы должны убедиться, что он имеет правильный размер и количество строк и столбцов.

Давайте посмотрим на это в действии:

enter image description here

Для настройки используйте функцию 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();
        }
    }
}

Это был просто быстрый выстрел, поэтому многие вещи можно и, вероятно, следует улучшить, например, добавление и удаление столбцов и строк, проверку и т. Д.

Я настроил наложение 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();

Чтобы позволить пользователю разместить его в нужном месте, вы можете использовать обычные события мыши вместо этого.

Обновление: При повторном чтении я увидел, что вы хотите позволить пользователю также изменять размер сетки. Вот пример того, как расширить код, чтобы разрешить изменение размера с левого или правого края ..:

        {   // 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
            }

Верхний и нижний края будут работать точно так же. Как и при пересечении линий, изменение размера также будет работать с углов.


Обновление: Вместо Panel, который является Container элементом управления и на самом деле не предназначен для рисования, вы можете использовать Picturebox или LabelAutosize=false) ; оба имеют свойство DoubleBuffered, включенное из коробки, и поддерживают рисование лучше, чем Panels do.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...