In this walk-through, you will learn how to create a graph using the Windows Form App (WinForm) step by step.
By default, chart control is not available in the toolbox. You have to install first the chart option, then proceed towards CHART preparation.
Create Project using template “Windows Forms App”
Set your project name and Location, which means the path of the project.
Select Your Framework .Net Version and create the project.
Search the Chart in the toolbox, you will come to know that there is no CHART control.
Install NugGet: System.Windows.Forms.DataVisualization
Right-click on Project and select Manage NuGet packages.
After installation, you can seethe Chart option is visible. Now, drag and drop the chart control on the Form1 canvas.
Double-click on the Form1 canvas area or press F7 on Form1 and enter the following code using the Inside Form1_Laod method.
private void Form1_Load(object sender, EventArgs e)
{
this.Text = "How to Create Chart WinForm .NET 8";
// Clear ChartAreas, Series
chart1.ChartAreas.Clear();
chart1.Series.Clear();
// Create Chart Area
ChartArea chartArea = new ChartArea("GraphArea");
chartArea.AxisX.Title = "Months";
chartArea.AxisY.Title = "Rs. In Lakhs";
// Add Chart Area
chart1.ChartAreas.Add(chartArea);
// Create a Series and set type to Bar
Series series = new Series("Sales")
{
ChartType = SeriesChartType.Bar,
IsValueShownAsLabel = true
};
// Add Data Points
series.Points.AddXY(1, 150);
series.Points.AddXY(2, 70);
series.Points.AddXY(3, 90);
series.Points.AddXY(4, 150);
series.Points.AddXY(5, 170);
series.Points.AddXY(6, 90);
series.Points.AddXY(7, 130);
series.Points.AddXY(8, 70);
series.Points.AddXY(9, 190);
series.Points.AddXY(10, 120);
series.Points.AddXY(11, 90);
series.Points.AddXY(12, 70);
// Add Series to Chart
chart1.Series.Add(series);
// Set Fonts
series.Font = new Font("Verdana", 11);
chart1.ChartAreas[0].AxisY.LabelStyle.Font = new Font("Segoe UI", 9);
}
Output
To change the Chart Type, set the following property.
// Create a Series and set type to Bar
Series series = new Series("Sales")
{
ChartType = SeriesChartType.Line,
IsValueShownAsLabel = true
};
Happy Coding!
Доброго времени суток! В данной статье мы рассмотрим, как можно создавать графики в WinForms C#.
В качестве платформы примера нужно взять .Net Framework 4.8. Далее в ссылки проекта необходимо добавить
ссылку на сборку System.Windows.Forms.DataVisualization.
Для этого нужно в обозревателе решений нажать правой мыши на элемент меню Ссылки и далее Добавить ссылку.
В открывшемся окне необходимо найти сборку и выделить ее галочкой. В панели элементов должен появиться новый элемент — Chart.
Обратите внимание, что проект должен быть для версии .Net Framework 4.*.
Теперь рассмотрим пример кода:
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
namespace ChartsWinForms
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
string[] daysOfWeek = { "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье" };
int[] numberOfVisitors = { 1200, 1450, 1504, 1790, 2450, 1900, 3050 };
// Установим палитру
chart.Palette = ChartColorPalette.SeaGreen;
// Заголовок графика
chart.Titles.Add("Посетители");
// Добавляем последовательность
for (int i = 0; i < daysOfWeek.Length; i++)
{
Series series = chart.Series.Add(daysOfWeek[i]);
// Добавляем точку
series.Points.Add(numberOfVisitors[i]);
}
}
}
}
Таким образом, вот так просто можно создавать графики в WinForms C#.
-
Создано 16.03.2023 13:36:01
-
Михаил Русаков
Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!
Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.
Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления
Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.
Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):
-
Кнопка:
Она выглядит вот так:
-
Текстовая ссылка:
Она выглядит вот так: Как создать свой сайт
- BB-код ссылки для форумов (например, можете поставить её в подписи):
“
В этом уроке поговорим о том, как можно визуализировать информацию с помощью графиков. Для этого будем использовать приложение WPF и элементы Windows Forms.
Для успешного освоения материала рекомендуем вам изучить следующие понятия:
DB (Database), БД. Организованная структура, предназначенная для хранения, изменения и обработки взаимосвязанной информации, преимущественно больших объемов
Framework. Программная платформа, определяющая структуру программной системы; программное обеспечение, облегчающее разработку и объединение разных компонентов большого программного проекта
Windows Presentation Foundation. Аналог WinForms, система для построения клиентских приложений Windows с визуально привлекательными возможностями взаимодействия с пользователем, графическая (презентационная) подсистема в составе .NET Framework (начиная с версии 3.0), использующая язык XAML
Демонстрация работы с графиками в Windows Forms
На данном занятии будет разработано простое приложение Windows Forms для визуализации расходов пользователей. Пользователи распределяют затраты по разным категориям и хранят их в общей базе данных. Итогом работы приложения будет служить работающая форма, в которой для каждого пользователя можно построить диаграммы различных типов для визуализации их расходов по категориям. Основные шаги построения приложения:
- Разработка интерфейса приложения
- Настройка взаимодействия с базой данных
- Реализация обработки данных
Важно
В рамках примера используется готовая база данных с информацией о пользователях, их платежах и категориях расходов
Разработка интерфейса приложения
1. Устанавливаем структуру формы
Важно
Интерфейс приложения будет состоять из двух основных частей: области построения и области настройки параметров просмотра
2. Добавляем элементы настройки параметров просмотра
Важно
Элементами настройки параметров просмотра будут являться выпадающие списки, позволяющие выбрать пользователя и тип диаграммы
3. Подключаем библиотеки для просмотра диаграмм
Важно
Диаграмма будет визуализироваться с помощью элемента Chart из WindowsForms. Воспользоваться данным элементом можно после подключения библиотеки System.Windows.Forms.DataVisualization, расположенного во вкладке Assemblies (сборки)
4. Добавляем элементы управления диаграммой
Важно
Диаграмма будет располагаться внутри элемента WindowsFormsHost. Данный элемент добавляется из окна ToolBox простым перетаскиванием
5. Добавляем пространство имен для работы с элементом Chart
6. Добавляем дополнительные параметры просмотра
Важно
Дополнительными параметрами являются имя диаграммы, а также легенда
Настройка взаимодействия с базой данных
1. Реализуем взаимодействие с базой данных
Важно
Взаимодействие реализуется путем добавления элемента «ADO.NET Entity Data Model»
2. Настраиваем свойства подключения базы данных
3. Добавляем подключение к базе данных
Реализация обработки данных
1. Создаем область построения графиков
Важно
Сперва создается поле для контекста EntityFramework с инициализацией. Затем создается область построения диаграммы ChartArea и добавляется в соответствующую коллекцию в конструкторе MainWindow
2. Добавляем наборы данных
Важно
Для каждого набора данных (например, данные линии на графике) необходимо добавлять в коллекцию Series. В данном случае есть одна серия данных для отображения сумм платежей по категориям. Объект Series создается с указанием названия и необходимости отображения на диаграмме
3. Загружаем данные из базы
Важно
Данные о пользователях загружаются в выпадающий список. Также загружаются типы диаграммы из перечисления SeriesChartType
4. Реализуем адаптивное изменение интерфейса
Важно
При выборе другого значения в ComboBox будет вызываться метод UpdateChart()
5. Получаем выбранные значения в выпадающих списках
Важно
Значения получаются как currentUser и currentType
6. Обрабатываем данные диаграммы
Важно
Приведенный код описывает получение серии данных диаграммы из соответствующей коллекции Series, установку типа диаграммы и очистку предыдущих данных
7. Обрабатываем список категорий
Важно
Список категорий получается из базы данных. Далее, в цикле foreach для каждой категории значение точки диаграммы добавляется в Points. Координата X будет названием категории, а координата Y будет суммой платежа для выбранного пользователя в текущей категории
Результат работы программы
“
Вы познакомились с тем, как использовать основные элементы Windows Forms в приложении WPF. Теперь давайте перейдем от теории к практике!
Для закрепления полученных знаний пройдите тест
Для взаимодействия с базами данных используется технология
Для размещение элемента управления Windows Forms на странице WPF используется
WindowsFormsIntegration является
К сожалению, вы ответили неправильно
Прочитайте лекцию и посмотрите видео еще раз
Но можно лучше. Прочитайте лекцию и посмотрите видео еще раз
Вы отлично справились. Теперь можете ознакомиться с другими компетенциями
C#: строим диаграммы и выполняем анимацию в приложениях Windows Forms
Для непосредственного простейшего построения графика или диаграммы можно использовать следующие арифметические соображения.
1. Узнав с помощью соответствующих свойств размеры графической канвы в пикселях и определив значение xstep
— шаг по оси X, соответствующий одному пикселю на экране, мы сможем обеспечить масштабирование графика по оси X. Для масштабирования по оси Y на первом этапе пересчета требуется также определить максимальное и минимальное значения f(x)
на интервале построения [a, b]
при изменении значения x
с шагом xstep
.
2. Второй этап связан с непосредственным пересчётом значений (x, f(x)
) в экранные координаты (cx, cy
). Для решения этой задачи воспользуемся формулой, согласно которой значение x
, принадлежащее интервалу [a, b]
, можно линейно преобразовать в значение y
, принадлежащее интервалу [c, d]
:
Преобразовать x из интервала значений [a,b] в y из интервала значений [c,d]
Эта формула позволит получить коэффициенты преобразования величин (x, f(x)
) к экранным координатам. Дополнительно придется учесть то, что экранная ось Y проведена сверху вниз.
Схема «ручного» преобразования координат к экранным
Проект Lab6_1. Создав приложение Windows Forms, пропишем в классе формы необходимые данные:
private delegate double Function (double x); //делегат для подключения функции private double func (double x) { return Math.Sin (x); } //сама функция private double x1 = -2 * Math.PI, x2 = 2 * Math.PI; //границы, в реальности границы по x введены откуда-то извне
и построим график на канве формы, например, по её событию Activated
:
this.ClientSize = new Size (640, 480); //размер клиентской части формы double x, xstep, y, y1, y2, ystep; int pw = this.ClientSize.Width, ph = this.ClientSize.Height; //размеры полотна Function f = func; //отображаемая функция xstep = ( x2 - x1 ) / pw; //шаг по x = 1 пикселу y1 = y2 = f (x1); for (x = x1; x <= x2; x += xstep) { //ищем макс. и мин. по y y = f (x); if (y > y2) y2 = y; if (y < y1) y1 = y; } ystep = ( y2 - y1 ) / ph; //шаг по y также = 1 пикселу (искажение пропорций) double xcoeff = pw / ( x2 - x1 ), ycoeff = ph / ( y2 - y1 ); //коэффициенты пересчета физических координат в пиксельные Graphics g = this.CreateGraphics(); //контекст картинки int mx = (int) ( -x1 * xcoeff ), my = (int) ( -y1 * ycoeff ); //начало координат g.DrawLine (Pens.Red, mx, 0, mx, ph); g.DrawLine (Pens.Red, 0, my, pw, my); //оси System.Collections.Generic.List <PointF> Points = new System.Collections.Generic.List <PointF> (); //коллекция точек x = x1; while (x <= x2) { y = f (x); Points.Add (new PointF ( (float) ( ( x - x1 ) * xcoeff ), (float) ( ( y2 - y ) * ycoeff ))); x += xstep; } g.DrawLines (Pens.Green, Points.ToArray ()); //отрисовка
При небольшой модификации можно добиться и пропорционального масштабирования графика по осям (используя один коэффициент пересчёта вместо xcoeff
и ycoeff
).
Разумеется, такой график очень примитивен и нужен только для иллюстрации. В реальности существует компонента Chart
(вкладка Данные), разработанная для поддержки 2D- и частично 3D-диаграмм и графиков.
Скачать пример Lab6_1 в архиве .zip с проектом C# Visual Studio 2019 (11 Кб)
Проект Lab6_2. Добавим на пустую форму компоненту Chart
со свойством Dock = Fill
и выведем туда программно сгенерированные данные (команда меню Файл — График 1).
Dictionary <double, double> f1 = new Dictionary <double, double> (); //коллекция "ключ"-"значение" для пар "x" - "f(x)" double x0 = 0, xmax = Math.PI, dx = Math.PI / 100.0; //границы графика по оси x и шаг f1.Clear (); chart1.Series [0].ChartType = SeriesChartType.Line; //тип диаграммы chart1.Series [0].MarkerStyle = MarkerStyle.Circle; //тип маркеров for (double x = x0; x <= xmax; x += dx) { //заполнение коллекции f1.Add ((int) ( x * 100 ) / 100.0, ( Math.Sin (x) )); } chart1.Series [0].Points.DataBindXY (f1.Keys, f1.Values); //привязать точки коллекции к ряду данных номер 0 chart1.Series [0].LegendText = "Функция 1"; //настроить легенду chart1.Series [0].Color = System.Drawing.Color.Green; chart1.Series [0].BorderWidth = 2;
Для работы примера требуются следующие подключенные пространства имён:
using System.Windows.Forms.DataVisualization.Charting; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D;
Для команды меню Файл — График 2 создадим и выведем красивый Chart
программно:
//Общие свойства Chart myChart = new Chart (); myChart.Parent = this; myChart.Left = 10; myChart.Top = 10; myChart.Width = ( this.ClientSize.Width - 10 ); myChart.Height = ( this.ClientSize.Height - 20 ); myChart.BringToFront (); //или chart1.Visible = false; //Сразу 2 важных вещи: //1. Анонимная "стрелочная" функция-делегат для обработки события //2. По клику диаграмма 2 будет "сама себя" прятать на задний фон myChart.Click += (sendr, args) => { myChart.SendToBack (); }; //Область в которой будет построен график (их может быть несколько) ChartArea myChartArea = new ChartArea (); myChartArea.Name = "myChartArea"; myChart.ChartAreas.Add (myChartArea); //График (их может быть несколько) Series mySeries1 = new Series (); mySeries1.ChartType = SeriesChartType.Column; mySeries1.ChartArea = "myChartArea"; myChart.Series.Add (mySeries1); //Исходные данные для графика double [] yval1 = { 10, 6, 4, 6, 3 }; String [] xval = { "Январь", "Февраль", "Март", "Апрель", "Май" }; mySeries1.Points.DataBindXY (xval, yval1); //фон градиентом myChart.BackColor = System.Drawing.Color.MistyRose; myChart.BackGradientStyle = GradientStyle.DiagonalLeft; //границы в современном стиле myChart.BorderSkin.SkinStyle = BorderSkinStyle.Sunken; myChart.BorderSkin.PageColor = this.BackColor; //линии сетки покажем разными цветами myChartArea.AxisX.MajorGrid.LineColor = System.Drawing.SystemColors.ControlDark; myChartArea.AxisY.MajorGrid.LineColor = System.Drawing.SystemColors.ControlLight; //добавим второй график Series mySeries2 = new Series (); mySeries2.ChartType = SeriesChartType.Point; mySeries2.ChartArea = "myChartArea"; myChart.Series.Add (mySeries2); double [] yval2 = { 4, 7, 3, 5, 5 }; mySeries2.Points.DataBindXY (xval, yval2);
Для построения таблицы значений по данным первого графика в конец обработчика пункта меню Файл — График 1 добавлены строки:
//Создадим новую форму и выведем туда данные 1-го ряда в виде таблицы Form form = new Form (); //Создали форму form.Size = new Size (640, 480); DataGridView dataGridView1 = new DataGridView (); //Создали таблицу dataGridView1.Dock = DockStyle.Fill; //Растянули dataGridView1.AllowUserToAddRows = false; //Запретили пользователю добавлять строки dataGridView1.Columns.Add ("X", "X"); dataGridView1.Columns.Add ("Y", "Y"); //Добавили 2 столбца foreach (DataPoint p in chart1.Series [0].Points) { //Пробегаем по всем точкам графика dataGridView1.Rows.Add (1); //Добавляем строку в таблицу int i = dataGridView1.RowCount - 1; dataGridView1.Rows [i].Cells [0].Value = p.XValue.ToString (); //Добавляем значение X double yp = p.YValues [0]; //Y является массивом, поэтому берём элемент dataGridView1.Rows [i].Cells [1].Value = Math.Round (yp, 3).ToString (); } form.Controls.Add (dataGridView1); //Добавили таблицу на форму form.Show (); //Показали форму
Скачать пример Lab6_2 в архиве .zip с проектом C# Visual Studio 2019 (13 Кб)
Проект Lab6_3. На основе готового парсера выражений реализуем программу- «графопостроитель», умеющую строить графики введённой пользователем функции одной переменной в заданных пределах.
Ввод данных будем выполнять через стандартное меню MenuStrip
, вот его структура:
- Аргумент: пункты «От x1», «С шагом dx», «До x2», в каждый из которых вложен элемент
ToolStripTextBox
(с именамиx1
,dx
,x2
соответственно); - Функция: пункты «Функция», «Переменная», в каждый из которых вложен элемент
ToolStripTextBox
(с именамиfuncexp
,funcvar
соответственно); - Построить: вложенных пунктов нет.
Нам понадобится дополнительный пакет интерпретации формул AngouriMath, установить этот и другие пакеты можно так:
- Нажмем в Обозревателе решений правой кнопкой на названии проекта и в контекстном меню выберем пункт «Управление пакетами NuGet…»;
- В появившейся вкладке выберем «Обзор», отметим «Включить предварительные версии», введём в текстовое поле
AngouriMath
и нажмём Enter; - Когда пакет найден, выбираем его (лучше последнюю стабильную версию) и нажимаем справа «Установить». Все нужные файлы и зависимые пакеты будут установлены во вложенную папку проекта
packages
, а в основной папке будет создан файлpackages.config
.
Для применения пакета добавим в начале файла Form1.cs
директиву
using AngouriMath;
Документацию по пакету можно найти на его странице.
Заметим, что пакеты будут также скопированы в служебную папку packages
Visual Studio и в дальнейшем могут быть восстановлены при разворачивании проекта (если не удалён файл packages.config
).
В классе формы подключим дополнительные стандартные пространства имён
using System.Windows.Forms.DataVisualization.Charting; using System.Text.RegularExpressions;
и опишем нужные данные:
public Series mySeriesOfPoint; public Chart myChart; private bool check = true;
В конструкторе формы создадим и программно настроим компоненту Chart
:
public Form1 () { InitializeComponent (); myChart = new Chart (); //Создаем элемент Chart myChart.Parent = this; //Помещаем его на форму и растягиваем на все окно myChart.Dock = DockStyle.Fill; //Добавляем в Chart область для рисования графиков, их может быть //много, поэтому даем ей имя myChart.ChartAreas.Add (new ChartArea ("Math functions")); //Создаем и настраиваем набор точек для рисования графика, //не забыв указать имя области на которой хотим отобразить этот //набор точек. mySeriesOfPoint = new Series ("Default"); mySeriesOfPoint.ChartType = SeriesChartType.Line; mySeriesOfPoint.ChartArea = "Math functions"; }
Основываясь на документации к установленному пакету и данных из меню «Функция», напишем метод Polynom
, интерпретирующий значение введённого в поле «Функция» выражения для аргумента x
и возвращающий вычисленное значение f(x)
:
bool Polynom (double x, out double y) { string pattern = @"[а-я]"; //можно включить другие "запрещённые" символы ввода Entity exp; //выражение Regex regex = new Regex (pattern, RegexOptions.IgnoreCase); //регулярное выражение для проверки if (!regex.IsMatch (funcexp.Text.Trim ())) { try { exp = funcexp.Text; } catch (AngouriMath.Core.Exceptions.ParseException) { MessageBox.Show ("Ошибка интерпретации функции, проверьте её запись"); y = 0; return false; } } else { MessageBox.Show ("Недопустимые символы в функции, проверьте её запись"); y = 0; return false; } AngouriMath.Core.FastExpression func; try { func = exp.Compile (funcvar.Text.Trim()); check = true; } catch (System.Collections.Generic.KeyNotFoundException) { MessageBox.Show ("Неверный аргумент функции или функция указана неверно"); Entity errorExp = "x"; func = errorExp.Compile ("x"); check = false; } y = func.Substitute (x).Real; return true; }
Команда «Построить» будет собирать данные из меню «Аргумент» и, если они допустимы, выполнять организацию основного цикла:
private void построитьToolStripMenuItem_Click (object sender, EventArgs e) { mySeriesOfPoint.Points.Clear (); myChart.Series.Clear (); double from, to, foot, f; try { from = double.Parse (x1.Text); foot = double.Parse (dx.Text); to = double.Parse (x2.Text); } catch (Exception) { MessageBox.Show ("Введите числовые значения в меню Аргумент!"); return; } if (from + foot >= to) { MessageBox.Show ("Введите корректно: x1 + dx < x2"); return; } for (double x = from; x <= to; x += foot) { check = Polynom (x, out f); if (!check) { MessageBox.Show ("Ошибка интерпретации, построение прервано!"); break; } mySeriesOfPoint.Points.AddXY (x, f); //Добавляем точку в набор } myChart.Series.Add (mySeriesOfPoint); //Добавляем созданный набор точек в Chart check = true; }
Теперь в поле ввода «Функция» можно писать любые допустимые парсером выражения с аргументом x
(или другим, который мы поменяли командой Функция — Переменная), например, cos(x)
, текущее значение переменной x
из программы подставится в выражение и его результат динамически посчитается.
Чтобы при старте приложения сразу показывался график с данными, вызовем метод построения после загрузки формы:
private void Form1_Load (object sender, EventArgs e) { построитьToolStripMenuItem_Click (this, e); //Строим график с данными по умолчанию }
Замечание. Напомним, что в различных национальных стандартах могут применяться разные разделители для элементов списка, целой и дробной части числа и т.п. Для обработки таких ситуаций могут пригодиться как объекты пространства имён
Globalization
, так и простые замены нужных разделителей в интерпретируемых данных, например:String Str = "1,2345"; Str = Str.Replace(",","."); MessageBox.Show (Str.ToString()); //1.2345
Следует также помнить, что для ввода чисел согласно установленной в системе локали, в общем случае предпочтительнее компонента
NumericUpDown
.
Скачать пример Lab6_3 в архиве .zip с проектом C# Visual Studio 2019 (14 Кб)
Приложение Lab6_3 в работе с открытым меню ввода интерпретируемой функции
Теперь рассмотрим принципы простой анимации в программах Windows Forms.
Высокоуровневые методы библиотеки .NET едва ли подойдут для написания насыщенных быстрым движением и графикой мультимедийных или игровых приложений — для этого есть DirectX
и OpenGL
. Тем не менее, иногда бывает нужно куда-то передвинуть или перетащить картинку, «оживить» своё приложение небольшой покадровой анимацией и т.п. В качестве примера покажем несколько типовых действий по реализации анимации в .NET на C#.
Общий подход к анимации следующий: на форму добавляется или программно создаётся компонента Timer
. Её единственное событие Tick
выполняется через заданный в миллисекундах интервал времени Interval
. Обработчик события Tick
отслеживает, нужна ли перерисовка каких-либо объектов на форме и, при необходимости, вызывает соответствующие методы. Самый простой способ — выполнить метод Invalidate
формы, отправляющий сообщение методу Paint
, отвечающему за перерисовку.
Проект Lab6_4. Картинка следует за курсором мыши.
Создав решение Windows Forms на C++, проиллюстрируем добавление в проекту файла ресурсов и загрузку оттуда картинки.
- В верхнем меню выбрать Проект — Добавить компонент — Файл ресурсов;
- Выполнить двойной клик по
Resuorses1.resx
в Обозревателе решений, выбрать Добавить ресурс — Добавить существующий файл, выбрать в окне диалога рисунокbutterfly.png
из папки с исходным кодом проекта, нажать Открыть; - Выбрать добавленный рисунок, в его свойствах установить
Persisitence = "Внедрено в RESX-файл"
;
Теперь из кода рисунок можно загрузить строкой вида
Img = (Image) Resource1.butterfly;
, где Resource1
— имя файла ресурсов, а buttefly
— свойство Name
добавленного ресурса изображения.
Опишем в классе формы необходимые объекты:
Image Img; //изображение Point imgPoint, mousePoint; //координаты картинки и цели bool mouseMode; //следим ли за мышью Timer timer1; //таймер
Дадим им начальные значения в обработчике события Load
формы:
this.DoubleBuffered = true; //включаем двойную буферизацию, чтобы не мерцало Img = (Image) Resource1.butterfly; //загружаем картинку из ресурсов imgPoint = new Point (0, 0); mousePoint = new Point (); mouseMode = true; timer1 = new Timer (); timer1.Interval = 5; //вызываем каждые 5 мс timer1.Enabled = true; timer1.Tick += new EventHandler (timer1_Tick);
Обратите внимание, что для формы включена двойная буферизация графики — это позволит избежать мерцания картинки при её движении. При относительно медленном процессе отрисовки объектов непосредственно на канве, где они отображаются, часто возникает эффект мерцания изображения. Избежать его позволяет двойная буферизация, идея которой состоит в следующем: объект рисуется на невидимой канве, а затем законченный объект быстрым копированием из одной области оперативной памяти в другую помещается на канву отображения. В библиотеку .NET двойная буферизация уже встроена, для её использования достаточно установить в значение true
свойство DoubleBuffered
формы.
Также в этом коде мы программно создали и инициализировали таймер, который будет управлять процессом движения картинки. Видно, что обработчик единственного имеющегося у таймера события Tick
, происходящего с частотой в Interval
миллисекунд, тоже назначен программно.
Вот сам этот метод, добавленный в класс формы плюс вспомогательный метод MoveImg
, отвечающий за изменение координат:
private void timer1_Tick (Object sender, EventArgs e) { //добавили этот метод "вручную", а не из конструктора if (mouseMode) { MoveImg (mousePoint); this.Invalidate (); //перерисовать после смещения! } } private void MoveImg (Point p) { //добавили этот метод "вручную", а не из конструктора if (imgPoint.X < p.X) imgPoint.X++; if (imgPoint.X > p.X) imgPoint.X--; if (imgPoint.Y < p.Y) imgPoint.Y++; if (imgPoint.Y > p.Y) imgPoint.Y--; }
Непосредственно заниматься отрисовкой будет обработчик события Paint
, который мы создадим из стандартного окна «Свойства»:
private void Form1_Paint (object sender, PaintEventArgs e) { if (Img != null) { e.Graphics.DrawImage (Img, imgPoint); } }
По событию MouseDown
будем переключать режим движения картинки, то есть, кликнем раз — движение за курсором прекратится, а следующий клик возобновит движение и т.д.:
private void Form1_MouseDown (object sender, MouseEventArgs e) { mouseMode = !mouseMode; }
Наконец, обработчик события перемещения мыши будет следить за тем, куда нужно смещаться картинке. Обратите внимание на то, какой должна быть «цель» движения, чтобы картинка останавливалась «прямо под курсором»:
private void Form1_MouseMove (object sender, MouseEventArgs e) { if (Img != null) { mousePoint = new Point (e.Location.X - Img.Width / 2, e.Location.Y - Img.Height / 2); } }
Это всё, приложение можно собирать.
Скачать пример Lab6_4 в архиве .zip с проектом C# Visual Studio 2019 (154 Кб)
Проект Lab6_5. Движение картинки мышью.
Так как у Image
нет свойства Location
, будем перемещать добавленный на форму PictureBox
. Ему автоматически присвоится имя pictureBox1
.
Создадим файл ресурсов точно так же, как в предыдущем проекте, и добавим туда рисунок butterfly.png
.
Опишем в классе формы необходимые данные:
Image Img; //картинка bool i_mouse; //флажок, показывающий, нажата ли кнопка мыши для перетаскивания int pozx, pozy; //координаты курсора мыши на картинке PictureBox pictureBox1; //контейнер для рисунка
В обработчике события Load
формы настроим наш PictureBox
:
private void Form1_Load (object sender, EventArgs e) { i_mouse = false; pictureBox1 = new PictureBox (); pictureBox1.Location = new Point (0, 0); pictureBox1.AutoSize = true; pictureBox1.Image = (Image) Resource1.butterfly; pozx = pictureBox1.Width / 2; pozy = pictureBox1.Height / 2; }
Для перемещения объекта мышью понадобится совместная обработка нескольких событий от мыши для компоненты pictureBox1
.
По нажатию кнопки мыши будем включать режим перетаскивания картинки, а по отпусканию — выключать:
private void pictureBox1_MouseDown (object sender, MouseEventArgs e) { i_mouse = true; } private void pictureBox1_MouseUp (object sender, MouseEventArgs e) { i_mouse = false; }
Обработчик события MouseMove
выполнит основную работу:
private void pictureBox1_MouseMove (object sender, MouseEventArgs e) { int mouseX = e.Location.X, mouseY = e.Location.Y; if (i_mouse == true) { if (pictureBox1.Left < 0) { pictureBox1.Left = 0; return; } else if (pictureBox1.Left + pictureBox1.Width > this.ClientRectangle.Width ) { pictureBox1.Left = this.ClientRectangle.Width - pictureBox1.Width; return; } if (pictureBox1.Top < 0) { pictureBox1.Top = 0; return; } else if (pictureBox1.Top + pictureBox1.Height > this.ClientRectangle.Height) { pictureBox1.Top = this.ClientRectangle.Height - pictureBox1.Height; return; } if (Math.Abs (mouseX - pozx) >= 5 || Math.Abs (mouseY - pozy) >= 5) { pictureBox1.Left += mouseX - pictureBox1.Width / 2; pictureBox1.Top += mouseY - pictureBox1.Height / 2; pozx = mouseX; pozy = mouseY; } } }
«Допуск» в 5 пикселей позволяет картинке быть не слишком чувствительной к смещению мыши.
Аналогично можно реализовать перетаскивание группы объектов, например, поместив их в контейнер System.Collections.Generic.List
и программно назначив всем картинкам списка одни и те же обработчики событий мыши. Обработчики событий смогут различать, от какой именно картинки «пришло» событие, например, с помощью следующего кода:
String s = ((PictureBox) sender).Name.ToString (); //вернёт имя компоненты, например, "pictureBox1"
Скачать пример Lab6_5 в архиве .zip с проектом C# Visual Studio 2019 (154 Кб)
Проект Lab6_6. Картинка двигается по форме нажатием клавиш со стрелками.
Для формы создан файл ресурсов с рисунком, как в проектах Lab6_4 и Lab6_5.
Начнём как и в прошлый раз, в пустом проекте Windows Forms к классу формы добавлены следующие поля:
Image img; //картинка Point imgPoint; //точка вывода картинки Keys keyCode; //направление движения (код клавиши) Timer timer1; //таймер
В обработчике события формы Load
они проинициализированы и создаётся таймер, которому программно назначается обработчик его события:
private void Form1_Load (object sender, EventArgs e) { this.DoubleBuffered = true; Img = (Image) Resource1.butterfly; imgPoint = new Point (0, 0); timer1 = Timer (); timer1.Interval = 5; timer1.Enabled = true; timer1.Tick += new EventHandler (timer1_Tick); } private void timer1_Tick (Object sender, EventArgs e) { //добавили этот метод "вручную", а не из конструктора this.Invalidate (); //запросить перерисовку }
На отрисовку теперь будем менять координаты картинки и затем уже обновлять форму:
private void Form1_Paint (object sender, PaintEventArgs e) { switch (keyCode) { case Keys.Right: if (imgPoint.X + Img.Width < this.ClientSize.Width) imgPoint.X++; break; case Keys.Left: if (imgPoint.X > 0) imgPoint.X--; break; case Keys.Up: if (imgPoint.Y > 0) imgPoint.Y--; break; case Keys.Down: if (imgPoint.Y + Img.Height < this.ClientSize.Height) imgPoint.Y++; break; } e.Graphics.DrawImage (Img, imgPoint); }
По нажатию клавиш со стрелками будем запоминать, что нажато, в поле keyCode
, чтобы при следующей отрисовке поменять координаты картинки на экране:
private void Form1_KeyDown (object sender, KeyEventArgs e) { switch (e.KeyCode) { case Keys.Right: case Keys.Left: case Keys.Up: case Keys.Down: keyCode = e.KeyCode; break; //другие клавиши игнорируются } }
Разрешённые клавиши можно нажимать и «во время движения» объекта, он изменит своё направление, если это возможно.
Скачать пример Lab6_6 в архиве .zip с проектом C# Visual Studio 2019 (154 Кб)
Проект Lab6_7. Анимация на основе ImageList
и таймера.
Как и в предыдущих проектах, добавим файл ресурсов с изображениями 1.png
, …, 6.png
из папки проекта, обозначающими фазы движения. Им будут назначены имена _1
, …, _6
.
Опишем в классе формы необходимые данные:
int index, count; //номер картинки и число картинок ImageList imageList1; //компонента для списка картинок PictureBox pictureBox1; //компонента для вывода одной картинки Timer timer1; //таймер
Запрограммируем событие Load
загрузки формы на заполнение списка картинками и настройку PictureBox
и запуск таймера:
private void Form1_Load (object sender, EventArgs e) { imageList1 = new ImageList (); index = 0; count = 6; for (int i = 1; i <= count; i++) { String name = "_" + i; imageList1.Images.Add ((Image) Resource1.ResourceManager.GetObject (name)); } pictureBox1 = new PictureBox (); pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage; pictureBox1.Size = new Size (imageList1.Images[0].Width*4, imageList1.Images[0].Height*4); //предполагаем, что все картинки одинаковы по размеру pictureBox1.Image = imageList1.Images[index]; this.Location = new Point (0, 0); this.Controls.Add (pictureBox1); timer1 = new Timer (); timer1.Interval = 100; timer1.Enabled = true; timer1.Tick += (sendr, args) => { index++; if (index == count) index = 0; pictureBox1.Image = imageList1.Images[index]; }; }
На этот раз мы формирировали имена картинок для загрузки из файла ресурсов динамически, а обработчик события Tick
таймера встроили непосредственно в оператор назначения с помощью стрелочной функции.
Скачать пример Lab6_7 в архиве .zip с проектом C# Visual Studio 2019 (46 Кб)
Задание по теме может быть примерно таким: реализовать одним из рассмотренных способов (или своим собственным) анимацию для графического объекта, созданного в предыдущем задании.
05.04.2023, 19:33 [3797 просмотров]
К этой статье пока нет комментариев, Ваш будет первым