Форум программистов, компьютерный форум, киберфорум
C# Windows Forms
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.89/18: Рейтинг темы: голосов - 18, средняя оценка - 4.89
Keramer82
2 / 1 / 1
Регистрация: 30.07.2019
Сообщений: 63
1

Как сделать так, чтобы линия "тянулась" за мышью?

27.10.2019, 04:34. Просмотров 3518. Ответов 25

Доброго времени суток! При написании графического редактора столкнулся с проблемой, никак не получается решить.
В общем линия у меня рисуется в локальных координатах открытого изображения (нужно именно так), за мышкой тянется, но прорисовывается каждый шаг движения мыши, а мне нужно удалить только что нарисованное и нарисовать линию заново при событии MouseMove. Метод Clear не помогает, так как линия должна идти поверх открытого рисунка, а не на однородном фоне.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
        private void zoomPictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
                {
                    //открытый рисунок
                    canvas = new Bitmap(zoomPictureBox1.Image); 
                    // холст для рисования линии
                    canvas2 = new Bitmap(zoomPictureBox1.Image.Width, zoomPictureBox1.Image.Height);
                    //стртовая точка в локальных координатах открытого изображения
                    StartPositionLassoScreen = new Point(zoomPictureBox1.ClientToImagePoint(e.Location).X,
                        zoomPictureBox1.ClientToImagePoint(e.Location).Y);
                    //признак начала рисования
                    pressedLasso = true;
                }
        }
 
        private void zoomPictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (pressedLasso)
                {
                    canvas2 = canvas;
                    Graphics graph = Graphics.FromImage(canvas2);
                    //-----------------------------------------------------
                    // Здесь нужно удалить только что нарисованное, если оно есть, но не трогать открытый рисунок...
                    //graph.Clear(Color.Empty); //так работает, но открытый рисунок исчезает
                    //-----------------------------------------------------
                    //вторая точка линии (тянется за курсором)
                    NextPositionLassoScreen = zoomPictureBox1.ClientToImagePoint(e.Location);
                    //метод рисования линии попиксельно
                    Bresenham_Line(graph, Color.Violet,
                        (int)(StartPositionLassoScreen.X), (int)(StartPositionLassoScreen.Y),
                        (int)(NextPositionLassoScreen.X), (int)(NextPositionLassoScreen.Y));
                    zoomPictureBox1.UpdateImage(canvas2);
                }
Помогите, пожалуйста, решить данную проблему. Может быть можно как-то очистить графику не цветом, а рисунком? Очень нужно...
0
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
27.10.2019, 04:34
Ответы с готовыми решениями:

Сделать так, чтобы линия "тянулась" за курсором мыши
Делаю маленький граф редактор. По щелчку мыши задаются начальные координаты, по отпусканию...

DGV: сделать так, чтобы в колонке ПОЛ вместо "м" или "ж" были картинки
Есть таблица, которая берется из БД this.hUMANTableAdapter.FillBy(this.dataSet1.HUMAN); Каким...

Как сделать так чтоб если человек вводил текст то когда он ввел слово "hell" оно заменилось на "hello"
Как сделать так чтоб если человек вводил текст,b когда он ввел слово "hell" оно заменилось на...

У меня есть строка "C:\Dan\Bas\image\win7\desktop\1.jpg" как мне сделать так чтобы выводилось начиная от "desktop\1.jpg"?
У меня есть строка "C:\Dan\Bas\image\win7\desktop\1.jpg" как мне сделать так чтобы выводилось...

25
ashsvis
425 / 276 / 127
Регистрация: 08.10.2018
Сообщений: 967
Записей в блоге: 11
27.10.2019, 09:21 2
Лучший ответ Сообщение было отмечено Keramer82 как решение

Решение

Цитата Сообщение от Keramer82 Посмотреть сообщение
Помогите, пожалуйста
Почитайте здесь, возможно, найдёте для себя решение: Создаём рамку выбора для графического редактора.
1
Keramer82
2 / 1 / 1
Регистрация: 30.07.2019
Сообщений: 63
27.10.2019, 10:59  [ТС] 3
Там речь идет совсем о другом. Мне не нужно создавать выделение. Моя задача состоит совсем в другом. Нужно стереть только что нарисованную линию не затрагивая открытую картинку. Через Paint я уже пробовал перерисовывать, но там возникает проблема в передачи правильных координат стартовой точки при увеличении, т.к. используются локальные координаты picturebox а не открытой картинки... В общем нужно рисовать линию именно так, а при движении мышью обновлять нарисованное, а не добавлять к уже нарисованному.
0
ashsvis
425 / 276 / 127
Регистрация: 08.10.2018
Сообщений: 967
Записей в блоге: 11
27.10.2019, 12:16 4
Лучший ответ Сообщение было отмечено Keramer82 как решение

Решение

Цитата Сообщение от Keramer82 Посмотреть сообщение
Там речь идет совсем о другом.
Да, верно, метод создания "резиновой" линии там реализован по-другому и, как мне кажется, проще.
В методе Paint сначала рисуется картинка, а потом сверху неё линия.
1
Keramer82
2 / 1 / 1
Регистрация: 30.07.2019
Сообщений: 63
27.10.2019, 12:34  [ТС] 5
Кажется, нащупал решение. Добавил на событие Paint сложение 2-х картинок в 3-ю.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
    public partial class Form1 : Form
    {
        bool pressedLasso = false;
        Bitmap canvas;
        Bitmap canvas2;
        Bitmap ResultCanvas;
        Point StartPositionLassoScreen;
        Point NextPositionLassoScreen;
 
        private void zoomPictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                 ResultCanvas = new Bitmap(zoomPictureBox1.Image);
                 canvas = new Bitmap(zoomPictureBox1.Image);
                 canvas2 = new Bitmap(zoomPictureBox1.Image.Width, zoomPictureBox1.Image.Height);
                 StartPositionLassoScreen = new Point(zoomPictureBox1.ClientToImagePoint(e.Location).X,
                        zoomPictureBox1.ClientToImagePoint(e.Location).Y);
                 pressedLasso = true;
            }
        }
 
        private void zoomPictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (zoomPictureBox1.Image != null)
            {
                if (pressedLasso)
                {
                    Graphics graph = Graphics.FromImage(canvas2);
                    graph.Clear(Color.Empty);
                    NextPositionLassoScreen = zoomPictureBox1.ClientToImagePoint(e.Location);
                    Bresenham_Line(graph, Color.Violet,
                            (int)(StartPositionLassoScreen.X), (int)(StartPositionLassoScreen.Y),
                            (int)(NextPositionLassoScreen.X), (int)(NextPositionLassoScreen.Y));
 
                }
            }
        }
 
        private void zoomPictureBox1_Paint(object sender, PaintEventArgs e)
        {
            if (pressedLasso)
            {
                Bitmap TargetBitmap = new Bitmap(canvas);
                Graphics graph = Graphics.FromImage(ResultCanvas);
                graph.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
                graph.DrawImage(TargetBitmap, 0, 0);
                graph.DrawImage(canvas2, 0, 0);
                zoomPictureBox1.UpdateImage(ResultCanvas);
                graph.Dispose();
                TargetBitmap.Dispose();
            }
        }
    }
Но теперь увеличилось потребление памяти, не могу отловить где она утекает. ashsvis, подскажите, пожалуйста, где я не освобождаю ресурсы?
0
ashsvis
425 / 276 / 127
Регистрация: 08.10.2018
Сообщений: 967
Записей в блоге: 11
27.10.2019, 12:40 6
Лучший ответ Сообщение было отмечено Keramer82 как решение

Решение

Цитата Сообщение от Keramer82 Посмотреть сообщение
увеличилось потребление памяти
Утекает в строках 15 и 16. Используйте конструкцию using(...) { ... }
1
Keramer82
2 / 1 / 1
Регистрация: 30.07.2019
Сообщений: 63
27.10.2019, 13:13  [ТС] 7
Цитата Сообщение от ashsvis Посмотреть сообщение
Используйте конструкцию using(...) { ... }
Попробовал так
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
                if (e.Button == MouseButtons.Left)
                {
                    ResultCanvas = new Bitmap(zoomPictureBox1.Image);
                    using (canvas = new Bitmap(zoomPictureBox1.Image))
                    {
                        using (canvas2 = new Bitmap(zoomPictureBox1.Image.Width, zoomPictureBox1.Image.Height))
                        {
                            StartPositionLassoScreen = new Point(zoomPictureBox1.ClientToImagePoint(e.Location).X,
                                    zoomPictureBox1.ClientToImagePoint(e.Location).Y);
                            pressedLasso = true;
                        }
                    }
                }
Выбросило в ошибку "Недопустимый параметр" на mouseMove в строку
C#
1
Graphics graph = Graphics.FromImage(canvas2);
Видимо я Вас неправильно понял, как использовать конструкцию using(...) { ... }. Подскажите, пожалуйста, это моя первая программа, и я еще во многом путаюсь.
0
ashsvis
425 / 276 / 127
Регистрация: 08.10.2018
Сообщений: 967
Записей в блоге: 11
27.10.2019, 13:33 8
Цитата Сообщение от Keramer82 Посмотреть сообщение
using (canvas = new Bitmap(zoomPictureBox1.Image))
нужно так:
C#
1
2
3
4
using (var canvas = new Bitmap(zoomPictureBox1.Image))
{
 ...
}
Видите отличие?
1
Keramer82
2 / 1 / 1
Регистрация: 30.07.2019
Сообщений: 63
27.10.2019, 14:04  [ТС] 9
Если при using создавать новые переменные, то потеряется глобальность переменных canvas и canvas2, которые используются и в mouseMove и в Paint. Как же быть?
В общем, я написал так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
                if (e.Button == MouseButtons.Left)
                {
                    ResultCanvas = new Bitmap(zoomPictureBox1.Image);
                    using (var canvas = new Bitmap(zoomPictureBox1.Image))
                    {
                        using (var canvas2 = new Bitmap(zoomPictureBox1.Image.Width, zoomPictureBox1.Image.Height))
                        {
                            StartPositionLassoScreen = new Point(zoomPictureBox1.ClientToImagePoint(e.Location).X,
                            zoomPictureBox1.ClientToImagePoint(e.Location).Y);
                            pressedLasso = true;
                        }
                    }
                }
Выбросило в ошибку "Значение не может быть неопределенным" на mouseMove в строку
C#
1
Graphics graph = Graphics.FromImage(canvas2);
Добавлено через 3 минуты
Цитата Сообщение от ashsvis Посмотреть сообщение
нужно так:
C#
Выделить код
1
2
3
4
using (var canvas = new Bitmap(zoomPictureBox1.Image))
{
...
}
Видите отличие?
Если при using создавать новые переменные, то потеряется глобальность переменных canvas и canvas2, которые используются и в mouseMove и в Paint. Как же быть?
В общем, я написал так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
                if (e.Button == MouseButtons.Left)
                {
                    ResultCanvas = new Bitmap(zoomPictureBox1.Image);
                    using (var canvas = new Bitmap(zoomPictureBox1.Image))
                    {
                        using (var canvas2 = new Bitmap(zoomPictureBox1.Image.Width, zoomPictureBox1.Image.Height))
                        {
                            StartPositionLassoScreen = new Point(zoomPictureBox1.ClientToImagePoint(e.Location).X,
                            zoomPictureBox1.ClientToImagePoint(e.Location).Y);
                            pressedLasso = true;
                        }
                    }
                }
Выбросило в ошибку "Значение не может быть неопределенным" на mouseMove в строку
C#
1
Graphics graph = Graphics.FromImage(canvas2);
0
ashsvis
425 / 276 / 127
Регистрация: 08.10.2018
Сообщений: 967
Записей в блоге: 11
27.10.2019, 14:15 10
Цитата Сообщение от Keramer82 Посмотреть сообщение
потеряется глобальность переменных canvas и canvas2
Если переменные у Вас глобальные, то и незачем без конца пересоздавать их в методе нажатия кнопки "мышки"?
1
Keramer82
2 / 1 / 1
Регистрация: 30.07.2019
Сообщений: 63
27.10.2019, 14:46  [ТС] 11
ashsvis, спасибо. Перекинул строки
C#
1
2
canvas = zoomPictureBox1.Image;
canvas2 = new Bitmap(zoomPictureBox1.Image.Width, zoomPictureBox1.Image.Height);
на включение инструмента.
Стало немного получше. Потребление памяти растет, если часто нажимать на кнопку мыши. Если немного подождать, то потребление памяти падает до уровня, который был перед включением инструмента.
0
ashsvis
425 / 276 / 127
Регистрация: 08.10.2018
Сообщений: 967
Записей в блоге: 11
27.10.2019, 14:54 12
А во второй строке canvas2 = new Bitmap(...) почему осталось?
0
Keramer82
2 / 1 / 1
Регистрация: 30.07.2019
Сообщений: 63
27.10.2019, 16:12  [ТС] 13
Это первое создание пустого Bitmap с размерами открытой картинки. Т.е. в первый раз оно и создается при инициализации инструмента

Добавлено через 9 минут
Дальше этот Bitmap только используется в mouseMove и Paint. Теперь нужно не забыть освободить ресурсы этого Bitmap, например, при закрытии контура, верно?
0
ashsvis
425 / 276 / 127
Регистрация: 08.10.2018
Сообщений: 967
Записей в блоге: 11
27.10.2019, 17:46 14
Цитата Сообщение от Keramer82 Посмотреть сообщение
например, при закрытии контура
Может быть и верно. Нужно весь код смотреть.
0
Keramer82
2 / 1 / 1
Регистрация: 30.07.2019
Сообщений: 63
27.10.2019, 18:25  [ТС] 15
Весь код я выложить пока не готов, т.к. он занимает более 2000 строк... Знаю, нужно шлифовать, сокращать и оптимизировать. Это еще впереди и тут вряд-ли кто мне поможет, никто не будет читать столько чужого кода, особенно новичка.
0
ashsvis
425 / 276 / 127
Регистрация: 08.10.2018
Сообщений: 967
Записей в блоге: 11
27.10.2019, 18:33 16
Цитата Сообщение от Keramer82 Посмотреть сообщение
нужно шлифовать
Удачи!
1
Keramer82
2 / 1 / 1
Регистрация: 30.07.2019
Сообщений: 63
29.10.2019, 13:44  [ТС] 17
Возникла проблема, не могу понять в чем причина, но на событие MouseDown не срабатывает счетчик.
ashsvis, Вам уже знаком этот код, может, если не затруднит, подскажите, что я делаю не так в этом коде?
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
        private void zoomPictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
                if (e.Button == MouseButtons.Left)
                {
                    // Вот это срабатывает только на первый клик
                    //--------------------------------------------------
                    countPointLasso++;
                    label2.Text = "Point_" + countPointLasso.ToString();
                    //--------------------------------------------------
                    if (canvas != null)
                    {
                        canvas.Dispose();
                    }
                    canvas = new Bitmap(zoomPictureBox1.Image);
                    ResultCanvas = new Bitmap(zoomPictureBox1.Image);
                    StartPositionLassoScreen = new Point(zoomPictureBox1.ClientToImagePoint(e.Location).X,
                            zoomPictureBox1.ClientToImagePoint(e.Location).Y);
                    pressedLasso = true;
                }
        }
        private void zoomPictureBox1_Paint(object sender, PaintEventArgs e)
        {
            if (pressedLasso)
            {
                Bitmap TargetBitmap = new Bitmap(canvas);
                Graphics graph = Graphics.FromImage(ResultCanvas);
                graph.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
                graph.DrawImage(TargetBitmap, 0, 0);
                graph.DrawImage(canvas2, 0, 0);
                zoomPictureBox1.UpdateImage(ResultCanvas);
                graph.Dispose();
                TargetBitmap.Dispose();
            }
        }
Я так понимаю, это из-за события zoomPictureBox1_Paint. Но как исправить ситуацию, просто не знаю.

Добавлено через 2 минуты
Забыл добавить MouseMove
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        private void zoomPictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (zoomPictureBox1.Image != null)
            {
                if (pressedLasso)
                {
                    Graphics graph = Graphics.FromImage(canvas2);
                    graph.Clear(Color.Empty);
                    NextPositionLassoScreen = zoomPictureBox1.ClientToImagePoint(e.Location);
                    Bresenham_Line(graph, Color.Violet,
                            (int)(StartPositionLassoScreen.X), (int)(StartPositionLassoScreen.Y),
                            (int)(NextPositionLassoScreen.X), (int)(NextPositionLassoScreen.Y));
 
                }
            }
        }
0
ashsvis
425 / 276 / 127
Регистрация: 08.10.2018
Сообщений: 967
Записей в блоге: 11
29.10.2019, 14:23 18
Цитата Сообщение от Keramer82 Посмотреть сообщение
не срабатывает счетчик
Не выполняется countPointLasso++;?
А где в коде у Вас countPointLasso = 0;? В приведённом примере не весь код.
Возможно где-то в коде есть обнуление и поэтому счётчик всегда показывает единицу.
Цитата Сообщение от Keramer82 Посмотреть сообщение
код я выложить пока не готов, т.к. он занимает более 2000 строк...
Выкладывайте на github, а сюда ссылку, иначе не разобраться.
1
Keramer82
2 / 1 / 1
Регистрация: 30.07.2019
Сообщений: 63
29.10.2019, 15:32  [ТС] 19
ashsvis, переменная countPointLasso встречается в программе всего 3 раза (я ее только что завел и раньше ее не было). А завел я эту переменную до конструктора.
0
Миниатюры
Как сделать так, чтобы линия "тянулась" за мышью?   Как сделать так, чтобы линия "тянулась" за мышью?  
Keramer82
2 / 1 / 1
Регистрация: 30.07.2019
Сообщений: 63
29.10.2019, 16:22  [ТС] 20
Попытался обойтись без события zoomPictureBox1_Paint. Закинул код, который там был в событие MouseMove.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
        private void zoomPictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (zoomPictureBox1.Image != null)
            {
                if (pressedLasso)
                {
                    Graphics graph = Graphics.FromImage(canvas2);
                    graph.Clear(Color.Empty);
                    NextPositionLassoScreen = zoomPictureBox1.ClientToImagePoint(e.Location);
                    Bresenham_Line(graph, Color.Violet,
                        (int)(StartPositionLassoScreen.X), (int)(StartPositionLassoScreen.Y),
                        (int)(NextPositionLassoScreen.X), (int)(NextPositionLassoScreen.Y));
 
                    Bitmap TargetBitmap = new Bitmap(canvas);
                    Graphics graph2 = Graphics.FromImage(ResultCanvas);
                    graph2.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
                    graph2.DrawImage(TargetBitmap, 0, 0);
                    graph2.DrawImage(canvas2, 0, 0);
                    zoomPictureBox1.UpdateImage(ResultCanvas);
                    graph2.Dispose();
                    TargetBitmap.Dispose();
 
                }
            }
        }
и тогда переменная из MouseDown стала нормально прибавляться.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        private void zoomPictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
                if (e.Button == MouseButtons.Left)
                {
                    // Вот это стало срабатывать
                    //--------------------------------------------------
                    countPointLasso++;
                    label2.Text = "Point_" + countPointLasso.ToString();
                    //--------------------------------------------------
                    if (canvas != null)
                    {
                        canvas.Dispose();
                    }
                    canvas = new Bitmap(zoomPictureBox1.Image);
                    ResultCanvas = new Bitmap(zoomPictureBox1.Image);
                    StartPositionLassoScreen = new Point(zoomPictureBox1.ClientToImagePoint(e.Location).X,
                            zoomPictureBox1.ClientToImagePoint(e.Location).Y);
                    pressedLasso = true;
                }
        }
Но теперь рисование линии проходит с большой задержкой...
0
29.10.2019, 16:22
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
29.10.2019, 16:22

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Как сделать так, чтобы границы дочерней формы не "уходили" за границы родительской
Всем доброго времени суток! Возник следующий вопрос. Создаю MDI-приложение. Есть родительская форма...

Как в sql реализован логич.тип?Как можно в sql сделать так,чтобы были только значения "0"и"1" или "да"и"Нет"?
Хочу использовать в таблице переменные логического типа, но не нашла ничего про логический тип в...

Как сделать, так чтобы i и j можно было вводить самому "i" И "j" в цикле, есть программа
#include <iostream> using namespace std; int main() {int a=0,b=0; int i=0; cout<<"Vvedite...

Как сделать так, чтобы введенное с клавиатуры слово "helllo" в памяти сохранялось в виде "Hello".
Здравствуйте. Подскажите пожалауйста как сделать чтоб согда я вводу с клавиатуры helllo, в памяти...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.