Лабораторная работа № 5: Windows Forms — элементы управления

Лабораторная работа № 5: Windows Forms — элементы управления

Лабораторная работа № 5: WindowsForms— элементы управления

Содержание

Вводная часть

Создание приложения WindowsForms

Модификация приложения WindowsForms

Модификация приложения WindowsForms: динамическое добавление и уничтожение элемента управления

Модификация приложения WindowsForms: стандартные диалоговые окна

6. Модификация приложения WindowsForms: открытие файла, сохранение файла и работа с текстом

Модификация приложения WindowsForms: прочее

Завершающая часть

О приложении к Лабораторной работе № 5

Вводная часть

В этой работе будет рассмотрено несколько новых элементов управления, которые ещё не были рассмотрены, но с которыми рано или поздно придётся столкнуться и некоторые особенности по работе с ними. Элементы управления, это 50% успеха программы (остальные 50% это её оформление…). Красивая программа зачастую больше ценится, чем более функциональная, но содержащая невзрачный, недружелюбный к пользователю интерфейс.

С каждым выпуском VisualStudio (и в частности «фреймворков»), стандартных элементов для использования становится только больше, что неудивительно. Также, на данный момент энтузиастами-программистами написано множество новых элементов управления с различной функциональностью, подчас очень удобной.

Целью данной работы станет создание приложения с различными элементами управления и демонстрацией их основной функциональности на простых примерах. В частности рассмотрим:

1. Динамическое создание элемента управления.

2. Получение доступа к элементу управления по его имени.

3. Уничтожение элемента управления.

4. Поиск по однотипным элементам управления.

5. Создание массива элементов управления.

6. Работа со стандартными диалоговыми окнами Windows (окно выбора цвета, выбора шрифта и прочее).

7. Организация функциональности текстового расширенного редактора (формат сохранения RichTextFormat) и подключение возможности сохранения и открытия файлов.

8. Пример добавления изображения во время работы приложения и некоторые другие элементы управления.

Завершающаячасть

Компилируем приложение (Release) и запускаем. Результат работы показан на рисунках ниже:

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

Рис. 8. 1. Модифицированное приложение WindowsForms

Отображение выбранного с помощью диалога изображения и всплывающей подсказки при наведении на изображении мышки. Полный путь до этого изображения и название с расширением отображены в заголовке приложения на рисунке выше (вынесено в статичное текстовое поле около строки состояния).

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

Рис. 8. 2. Модифицированное приложение WindowsForms: результат работы переключателей на фоне уже выбранного изображения

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

Рис. 8. 3. Модифицированное приложение WindowsForms: результат работыформы Простые часы (ползунок двигается с каждой секундой при работающих часах)

Содержание

Вводная часть

Завершающая часть

Вводная часть

В этой работе будет рассмотрена работа свекторной графикой и рисованием в массиве простых объектов на подобии точек и линий, кривых, эллипсов и прямоугольников. Однако, в отличие от предыдущей лабораторной работы практикума, приложение будет способно «запоминать» нарисованный объект — вести историю рисования. В любой момент можно «выделить» ранее нарисованный объект при помощи мыши и изменить его свойства (толщину, цвет, положение и размер). Мы будем создавать векторный графический редактор.

Конечным итогом редактора в любом случае должно стать некий файл с изображением. Однако, способность формировать BMPили JPEG-файл была работе. Для нашего редактора, сохраняемым типом файлов станет некий собственный тип, «сериализирующий» и сохраняющий все объекты как массив (список) параметров. Фактически такой файл не будет отличаться от того же JPEG (файл это всегда последовательность битов), и будет являться «собственным» графическим форматом. После открытия такого файла, можно изменить параметры ранее нарисованных объектов, а также можно продолжить рисование.

В данной работе будет рассмотрено, как создать приложение Windows Forms для рисования графических объектов в области клиента Windows (непосредственно в специальном пользовательском элементе управления), рисование будет осуществляться с помощью мыши. Инструментами рисования, реализованные в данной работе являются: прямоугольник, эллипс, линия и карандаш. Есть хорошо известные методы создания таких типов приложений, в частности: взаимодействие с мышью (без мерцания при рисовании), осуществления рисования и выделенным инструментом, выделение нарисованных объектов, управление объектами Z-порядка и прочее.

Заходя вперёд скажем, что наше решение будет содержать два проекта: LWP15Draw—Приложение Windows Forms и LWP15Toolkit—Библиотека классов. LWP15Tools реализует функциональность приложения, аLWP15Toolkitсодержит классы для управления документами.

Данная лабораторная работа была создана и переработана, на основе статьи «DrawTools» (Alex Fr, 25 января 2007 года).

Число объектов

Имя типа

Объект

Имя типа

Объект

...

Имя типа

Объект

Это позволяет писать код общий сериализации в классе GraphicList не зная никаких подробностей о сериализованных объектов (абстрактно, для любого объекта):

privateconststring entryCount = "Count";

privateconststring entryType = "Type";

// Сохранитьсписоквпоток

[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]

publicvirtualvoid GetObjectData(SerializationInfo info, StreamingContext context)

{

// Числообъектов

info.AddValue(entryCount, graphicsList.Count);

int i = 0;

foreach (DrawObject o in graphicsList)

{

// Типобъекта

info.AddValue(

String.Format(CultureInfo.InvariantCulture,

"{0}{1}",

entryType, i),

o.GetType().FullName);

// Самобъект

o.SaveToStream(info, i);

i++;

}

}

// Загружаемизпотока

protected GraphicsList(SerializationInfo info, StreamingContext context)

{

graphicsList = new ArrayList();

// Числообъектов

int n = info.GetInt32(entryCount);

string typeName;

object drawObject;

for ( int i = 0; i < n; i++ )

{

// Типобъекта

typeName = info.GetString(

String.Format(CultureInfo.InvariantCulture,

"{0}{1}",

entryType, i));

// СоздаёмобъектпоименитипачерезusingReflection)

drawObject = Assembly.GetExecutingAssembly().CreateInstance(

typeName);

// Заполняемобъектизпотока

((DrawObject)drawObject).LoadFromStream(info, i);

graphicsList.Add(drawObject);

}

}

Проверканажатиякнопкимыши:

Как определить, что под указателем мыши находится нарисованный ранее объект?

Класс DrawObjectимеет virtual-функциюHitTest, которая определяет, принадлежит ли точка графическому объекту (проверят, куда нажал пользователь):

publicvirtualint HitTest(Point point)

{

return -1;

}

Производные классы используют virtual PointInObject для проверки нажатия. Эта функция вызывается из HitTest. КлассDrawRectangle реализует эту функцию:

protectedoverridebool PointInObject(Point point)

{

return rectangle.Contains(point);

// rectangle - принадлежиттипу Rectangle

}

Чуть более сложный вариант определения нажатия по линии:

protectedoverridebool PointInObject(Point point)

{

GraphicsPath areaPath;

Pen areaPen;

Region areaRegion;

// Создаём путь, который содержит широкую линию

// Длялёгкоговыборамышью

AreaPath = new GraphicsPath();

AreaPen = newPen(Color.Black, 7);

AreaPath.AddLine(startPoint.X, startPoint.Y, endPoint.X, endPoint.Y);

// startPoint и endPoint - принадлежаттипу Point

AreaPath.Widen(AreaPen);

// Создаём область из пути

AreaRegion = newRegion(AreaPath);

return AreaRegion.IsVisible(point);

}

Обработка состояния бездействия приложения:

Каждое Windows Forms приложениев своём составе имеетэлементы управлениятакие каккнопки пунктов меню, кнопки панелей инструментов и прочее. В зависимости от текущей ситуации и команды пользователя, эти элементы управления могут иметь различные состояния: включены/выключены, отмечены/не отмечены, видимые/невидимые и так далее. Действие пользователя может изменить это состояние. Настройка состояний элементов управления в каждом обработчике сообщений вызывать ошибку. Вместо этого, это управлять состояние элемента управлениялучше через функции, которые вызываются после каждого действия пользователя. В MFC(VisaulC++)существует функцияON_UPDATE_COMMAND_UI, которая позволяет обновить состояние кнопок панели инструментов во время бездействия приложения. Такая возможность может осуществляться также и в .NET программе.

Рассмотрим ситуацию, когда пользователь нажимает кнопку на панели инструментов (Прямоугольник). Эта кнопка должна активироваться, а ранее активный инструмент должен быть снят. Обработчик сообщений кнопки(Прямоугольник) не изменяет состояние элементов управления формы, он просто сохраняет текущее выделение кнопки в некоторой переменной. Обработчик сообщений Idle активирует инструмент и снимает выделение с неактивного инструмента. Передача изменения состояния кнопок происходит через метод, а не напрямую:

publicvoid SetStateOfControls()

{

// Выбор активного инструмента

tbPointer.Pushed = (drawArea.ActiveTool == DrawArea.DrawToolType.Pointer);

tbRectangle.Pushed = (drawArea.ActiveTool == DrawArea.DrawToolType.Rectangle);

tbEllipse.Pushed = (drawArea.ActiveTool == DrawArea.DrawToolType.Ellipse);

tbLine.Pushed = (drawArea.ActiveTool == DrawArea.DrawToolType.Line);

tbPolygon.Pushed = (drawArea.ActiveTool == DrawArea.DrawToolType.Polygon);

menuDrawPointer.Checked = (drawArea.ActiveTool == DrawArea.DrawToolType.Pointer);

menuDrawRectangle.Checked = (drawArea.ActiveTool == DrawArea.DrawToolType.Rectangle);

menuDrawEllipse.Checked = (drawArea.ActiveTool == DrawArea.DrawToolType.Ellipse);

menuDrawLine.Checked = (drawArea.ActiveTool == DrawArea.DrawToolType.Line);

menuDrawPolygon.Checked = (drawArea.ActiveTool == DrawArea.DrawToolType.Polygon);

// ...

}

// Инструмент "Прямоугольник" выбран

privatevoid CommandRectangle()

{

drawArea.ActiveTool = DrawArea.DrawToolType.Rectangle;

}

5. Модификация приложения WindowsForms: подготовка библиотеки классов

Проект LWP15Toolsбудет содержать четыре самостоятельных класса.

Для выбора, куда именно вставлять новый класс, выбираем в обозревателе решений проект LWP15Tools:

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

Для добавления нового файла в проект необходимо выполнить: Проект ->Добавить класс... (Shift+Alt+C). Также аналогично действие можно произвести щёлкнув на имени проекта правой кнопкой мыши, затем Добавить->Класс...:

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

В окне Добавление нового элемента – LWP15Tools в поле Имя вводим DocManager.cs. Также добавим в проект добавим ссылку на библиотеку System.Windows.Forms (вкладка .NETокна Добавить ссылку). Для добавления ссылки в обозревателе решений нажмём правую кнопку мыши по пункту Ссылки в проекте LWP15Toolsзатем Добавить ->Добавить ссылку...:

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

Текст первого файла класса DocManager.cs:[искомый код можно найти в приложении к данной лабораторной работе в (описания можно того или иного приложения можно посмотреть в пунтке № 8 протокола работы), а именно необходимо открыть Приложение № 1 (Библиотека классов LWP15Tools)].

Небольшое замечание. Ранее они уже были даны в предыдущих лабораторных работах, но приводим напоминание...

Обратим внимание на следующий код:

#regionКлассDocManagerData

...

#endregion

Этот код формирует из участков кода файла блоки, которые можно закрыть нажав на «минус» слева от строчи #regionи развернуть нажав «плюс» слева от свёрнутого элемента. Выглядит это так:

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

Также обратим внимание вот на этот код:

///<summary>

///Открываемдокумент

///</summary>

///<param name="newFileName">

/// Имя файла документа. Empty - функция выводит OpenFileDialog

///</param>

///<returns></returns>

Это описание, в данном случае для функции. Отображается во время использования функции в любом месте, при наведении мыши на экземпляр самой функции. Например, подсвечиваем функцию из этого класса:

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

О самом классе. Класс выполняет достаточно много функций связанных с сопровождением файлов приложения (создание нового документа, сохранение и открытие), а также работает с системным реестром (ассоциирует тип файла программы с нашим приложением). Забегая вперёд, можно сказать что для поддержки работы с реестром необходимо Запустить приложение один раз от имени администратора для WindowsVistaи Windows 7 (если включён UACи параметрами для него выставлены по умолчанию). В этом случае всех ключи в реестре будут созданы, и дальнейшая работа приложения с ними будет обеспечена. Основной функцией класса является следующая функция:

///<summary>

///Инициализация

///</summary>

///<paramname="data"></param>

publicDocManager(DocManagerDatadata)

{

Функция инициализирует класс и принимает данные (data) для работы класса.Это данные связанные с типом файлов для приложения, в частности основная инициализация для главной формы LWP15Mainвыглядит так:

privateDocManager docManager;

...

// DocManager

DocManagerData data = newDocManagerData();

data.FormOwner = this;

data.UpdateTitle = true;

data.FileDialogFilter = "Файлы LWP15Draw (*.lwp)|*.lwp|Всефайлы (*.*)|*.*";

data.NewDocName = "New.lwp";

data.RegistryPath = registryPath;

docManager = newDocManager(data);

docManager.RegisterFileType("lwp", "lwpfile", "Файл LWP15Draw");

...

Переходим к следующему классу. Назовём файл для него PersistWindowState.cs. Для работы кода добавим новую ссылку System.Drawing.Код файла такой:[искомый код можно найти в приложении к данной лабораторной работе в (описания можно того или иного приложения можно посмотреть в пунтке № 8 протокола работы), а именно необходимо открыть Приложение № 1 (Библиотека классов LWP15Tools)].

Класс отвечает за работу с окном приложения (сохраняет в реестр размер и положение окна, а также состояние минимизации окна, если приложение было свёрнуто).

Следующий файл класса будет носить имя MruManager.cs (класс MruManager). Класс будет обеспечивать работу со список недавно использованных (последних) файлов. По умолчанию будет отображаться 10 наиболее часто используемых файлов. Число символов в пути и имени не будет превышать 40. Работа списка будет выглядеть примерно так:

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

Код файла класса следующий: [искомый код можно найти в приложении к данной лабораторной работе в (описания можно того или иного приложения можно посмотреть в пунтке № 8 протокола работы), а именно необходимо открыть Приложение № 1 (Библиотека классов LWP15Tools)].

Последний класс отвечает за открытие файла приложение перетаскиванием из проводника Windows. Имя файла класса: DragDropManager.cs. Код файла следующий:[искомый код можно найти в приложении к данной лабораторной работе в (описания можно того или иного приложения можно посмотреть в пунтке № 8 протокола работы), а именно необходимо открыть Приложение № 1 (Библиотека классов LWP15Tools)].

Такимобразом,был сформированфайлбиблиотекиLWP15Tools.dll для приложения (можно откомпилировать). Можно переходить к самому приложению.

Завершающая часть

Компилируем приложение (Release) и запускаем. Рисуем что хотим, при помощи всех доступных инструментов, смотрим что получилось в окне приложения:

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

Рис. 7. 1. Модифицированное приложение WindowsForms: рисуем

Сохраняем документ («Файл» ->«Сохранить» или «Сохранить как») как Test.lwp, закрываем приложение, вновь запускаем, далее открываем ранее сохранённый файл и смотрим список последних файлов («Файл»):

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

Рис. 7. 2. Модифицированное приложение WindowsForms: открываем ранее сохранённый файл и просматриваем список последних открытых файлов

Выполняем «Файл» ->«Сохранить как изображение....». Сохраняем документ в формате *.gif (Рис. 7. 3):

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

Рис. 7. 3. Результат работы приложения: изображение Test.gif, открытое в стандартном редакторе изображений Windows 7

Перетаскиваем объекты в документеTest.lwp, меняем их размеры и свойства:

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

Рис. 7. 4. Модифицированное приложение WindowsForms: меняем свойства объектов в открытом документе Test.lwp

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

Рис. 7. 5. Модифицированное приложение WindowsForms: перетаскиваем файл Test.lwpна форму из проводника Windows (в результате файл откроется)

Содержание

Вводная часть

Завершающая часть

Вводная часть

В этой работе будет рассмотрена работа срастровой графикой и «простым» рисованием. Фактически мы будем реализовывать функциональность известного приложенияMicrosoftPaint, входящего в состав любого Windows.

Что же такое GDI+? Официальная документация скромно называет еёClass-based API, то есть основанным на классах интерфейсе прикладных программ для ОС Windowsпоколения «не GDI». Так как она встроена в Windows XP и все последующие ОС вплоть до Windows 7, её называют частью этих операционных систем. Часто встречается также определение «библиотека» или «библиотека классов». В действительности, предоставляемый GDI+ набор классов является тонкой оболочкой над множеством обычных функций, реализованных в одной динамической библиотеке GdiPlus.dll.

Итак, GDI+ — это библиотека, призванная заменить существующий уже больше 11 (или 18, в зависимости от того, как считать) лет интерфейс GDI, являющийся графическим ядром предыдущих версий Windows. Она сочетает в себе (по крайней мере, по замыслу) все достоинства своего предшественника и предоставляет множество новых мощных возможностей. Кроме того, при её проектировании заранее ставилась цель наименее болезненного переноса приложений на 64-битные платформы.

Основу для реализации функциональности растрового редактора будет составлять стандартная библиотека System.Drawing. Пространство имён System.Drawing обеспечивает доступ к функциональным возможностям графического интерфейса GDI+.Пространства имён System.Drawing.Drawing2D, System.Drawing.Imaging, и System.Drawing.Text обеспечивают дополнительные функциональные возможности.

Класс Graphics предоставляет методы рисования на устройстве отображения.Такие классы, как Rectangle и Point, инкапсулируют элементы GDI+.Класс Pen используется для рисования линий и кривых, а классы, производные от абстрактного класса Brush, используются для заливки фигур.

ОсновурисункасоставитэлементуправленияPictureBoxпространстваимёнSystem.Windows.Forms, иклассBitmap, который инкапсулирует точечный рисунок GDI+, состоящий из данных пикселей графического изображения и атрибутов рисунка.Объект Bitmap используется для работы с изображениями, определяемыми данными пикселей.

Приложение будет функционировать как растровый редактор изображений. А именно:

· будет доступна функция рисования линий и непрерывных линий с разной толщиной пера и цветом пера при рисовании;

· будет доступна функция рисования фигур, таких как прямоугольник и эллипс;

· будет доступна функция заливки фигур произвольным цветом, а также изменения толщины пера и цвета пера для контуров фигур при рисовании;

· будет доступна возможность очистки поля рисования (полная очистка и ластик), а также сохранения рисунка в разные графические форматы (например: JPEG);

· будет доступна возможность загрузки сохранённого рисунка или любого другого рисунка;

· будет доступна возможность работы с «эффектами», а именно осветление выбранного участка рисунка.

Пространства имён GDI+:

GDI+ — это уровень, находящийся между GDI и приложением, которые предоставляет более интуитивно понятную, основанную на наследовании объектную модель. Хотя GDI+ — это в основном оболочка вокруг GDI, тем не менее, Microsoft посредством GDI+ предлагает ряд новых возможностей и увеличенную производительность по сравнению с некоторыми старыми средствами GDI.

Часть базовой библиотеки классов .NET, связанная с GDI+, огромна! Гораздо важнее понять фундаментальные принципы, касающиеся рисования. Полные списки всех классов и методов, доступных в GDI+, конечно же, содержатся в документации SDK и MSDN.

Обзор основных пространств имен, в которых находятся базовые классы GDI+:

System.Drawing:

Содержит большинство классов, структур, перечислений и делегатов, обеспечивающих базовую функциональность рисования.

System.Drawing.Drawing2D:

Представляет основную поддержку для двумерной и векторной графики, включая сглаживание, геометрические трансформации и графические пути.

System.Drawing.Imaging:

Содержит различные классы, обеспечивающие манипуляции с графическими изображениями (битовые карты, файлы GIF и тому подобное).

System.Drawing.Printing:

Содержит классы, имеющие отношение к печати и предварительному просмотру выводимых на печать изображений.

System.Drawing.Design:

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

System.Drawing.Text:

Включает классы для выполнения более сложных манипуляций со шрифтами и семействами шрифтов.

Контексты устройств и объект Graphics:

В GDI способ идентификации устройства, на которое нужно направить вывод, заключается в обращении к объекту, называемому контекстом устройства (device context — DC). DC сохраняет информацию об определенном устройстве и может транслировать вызовы функций программного интерфейса GDI в конкретные команды, направляемые устройствам. Вы также можете опросить контекст устройства на предмет того, какие возможности он предоставляет (например, может ли принтер печатать в цвете или же только в черно-белом изображении), дабы соответствующим образом откорректировать вывод. Если вы пытаетесь заставить устройство делать что-то такое, что оно не способно сделать, то DC обычно обнаруживает это и предпринимает соответствующие действия (которые, в зависимости от ситуации, могут означать генерацию исключения либо модификацию запроса таким образом, чтобы получить как можно более близкий результат в рамках возможностей данного устройства).

Однако DC не только имеет дело с аппаратным устройством. Он служит в качестве моста между приложением и Windows, и принимает во внимание любые требования и ограничения, налагаемые на рисование Windows. Например, если Windows знает, что необходимо перерисовать лишь часть окна вашего приложения, DC перехватит и отменит попытки рисования вне этой области. Благодаря связи DC с Windows, работа через контекст устройств может упростить ваш код и в других отношениях.

Например, аппаратным устройствам необходимо сообщать, где следует рисовать объекты, и обычно им нужны координаты, отсчитываемые относительно верхнего левого угла экрана (или другого выходного устройства). Однако приложения обычно отображают нечто в клиентской области (области, зарезервированной для рисования) собственного окна, возможно, используя собственную систему координат. Поскольку окно может быть позиционировано в любом месте экрана, и пользователь в любой момент может его переместить, преобразования между этими системами координат могут оказаться непростой задачей. Однако DC всегда знает, где находится ваше окно, и может выполнять такие преобразования автоматически.

В GDI+ контекст устройства помещен в оболочку базового класса .NET с именем System.Drawing.Graphics. Большая часть рисования выполняется вызовом методов экземпляра Graphics. Фактически, поскольку класс Graphics отвечает за выполнение большинства операций рисования, очень немного в GDI+ происходит такого, что не касалось бы тем или иным образом экземпляра Graphics, а потому понимание того, как управлять этим объектом, является ключом к пониманию того, как рисовать на устройствах отображения с помощью GDI+.

Завершающая часть

Компилируем приложение (Release) и запускаем. Рисуем что хотим, при помощи всех доступных инструментов, осветляем области и жмём Сохранить как..., после чего сохраняем творение на диск и проверяем что и как сохранилось:

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

Рис. 5. 1. Модифицированное приложение WindowsForms: рисуем

Сохранённый документ в формате *.gif (Рис. 5. 2):

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

Рис. 5. 2. Результат работы приложения: изображение Рисунок.gif, открытое в стандартном редакторе изображений Windows 7

Теперь жмём Очистить и далее откроем при помощи нашего приложения сторонний рисунок:

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

Рис. 5. 3. Модифицированное приложение WindowsForms: загружаем сторонний рисунок

И осветляем его:

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

Рис. 5. 4. Модифицированное приложение WindowsForms: осветляем сторонний рисунок

Сохраняем полученный рисунок и проверяем, всё ли сохранилось.

Лабораторная работа № 5: Windows Forms — элементы управления - student2.ru

Рис. 5. 5. Модифицированное приложение WindowsForms: применяем «ластик/карандаш» с толщиной пера в 25 пикселей (Shift+ПКМ) на заново открытом рисунке

Лабораторная работа № 5: Windows Forms — элементы управления

Наши рекомендации