МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ
Брянский государственный технический университет
Е.А. Белов
ПРОГРАММИРОВАНИЕ ПРИЛОЖЕНИЙ WINDOWS. API ГРАФИЧЕСКОГО ИНТЕРФЕЙСА ПОЛЬЗОВАТЕЛЯ
Утверждено редакционно-издательским советом университета в качестве учебного пособия
Брянск 2010
2
ББК 65.29
Белов, Е.А. Программирование приложений Windows. API графического интерфейса пользователя [Текст]+[Электронный ресурс]: учеб. пособие / Е.А. Белов. – Брянск: БГТУ, 2010. – 350 с. –
Режим доступа: http://www.elibrary.ru.
ISВN 5-89838-495-1
Изложены методические основы специальных средств программирования графического интерфейса пользователя операционной системы Windows, в тоом числе динамического программирования и управления базовыми элементами программных систем: окнами, элементами управления, меню и диалоговыми панелями. Рассмотрены методы создания высокоэффективных компактных быстродействующих приложений. Включены примеры программ.
Учебное пособие предназначено для студентов очной и заочной форм обучения специальностей 230105 «Программное обеспечение вычислительной техники и автоматизированных систем», 010503 «Математическое обеспечение и администрирование информационных сетей», а также может быть использовано студентами других специальностей, занимающимися разработкой приложений для Windows.
Ил. 3. Табл. 69. Библиогр. 20 назв.
Научный редактор С.М. Брундасов
Рецензенты: кафедра «Маркетинг» Брянского государственного университета; П.Н. Протасов
ISВN 5-89838-495-1 |
© Брянский государственный |
технический университет, 2010 |
3
ПРЕДИСЛОВИЕ
Наиболее значимым моментом при программировании для операционной системы (ОС) Windows является интерфейс прикладного программирования Application Programming Interface (API).Это набор самых различных функций, с помощью которых приложение может взаимодействовать с Windows. Windows API в основном состоит из трех компонентов: Kernel (ядро), User (пользовательский интерфейс) и GDI (графическая подсистема), которые обеспечивают интерфейс с базовой ОС, управление окнами и приложениями и предоставляет поддержку графики. Интерфейс пользователя представляет собой систему различных элементов. Элементами являются окна, кнопки, меню, диалоговые панели и другие объекты Windows. Каждый элемент задают множествами параметров состояния, входных и выходных сообщений. Для элементов одного класса описывают единый метод изменения параметров состояния и обработки входных и выходных сообщений. Основной задачей проектирования интерфейса пользователя является разработка целостной системы управления множеством состояний программного продукта. Именно вопросам проектирования и разработки пользовтальского интерфейса посвящено учебное пособие.
Излагаемый в учебном пособии материал предполагает знакомство студентов с языком программирования C++, изучаемым на более ранних курсах высшей школы. Материал учебного пособия является основой для изучения дисциплин, связанных с программированием компьютерной графики для ОС Windows, выскоуровневых средств разработки MFC, Windows Forms и т.д.
Учебное пособие состоит из шести глав. В каждой главе излагается теоретический и практический материал, приводятся упражнения и вопросы для контроля полученных знаний.
Вглаве 1 рассматривается поняте окна с точки зрения языка программирования, способы описания классов и функций окон, главной функции приложения, функции для создания окон, функции перемещения и изменения расположения окон, а также механизм получения и обработки сообщений.
Вглаве 2 рассматриваются определенные в системе Windows классы окон, а также элементы управления: статический текст,
кнопки, списки, редактор текста, полосы прокрутки и
4
комбинированные списки; описываются способы создания элементов управления, механизмы работы с ними, функции обмена и обработки сообщений между окнами и элементами управления.
Вглаве 3 содержатся сведения о графических примитивах системы рисования, рассматривается понятие контекста отображения, его атрибуты, функции отображения текста и графических примитивов, примеры вывода таблиц и графиков.
Вглаве 4 рассматривается главное меню окна и его разделы, временные и плавающее меню, а также функции динамического создания, изменения меню и управления состоянием элементов меню. Здесь же описываются способы создания акселераторов и работы с ними.
Глава 5 посвящена панелям инструментов и строкам состояния. В ней рассматриваются способы создания и использования панели инструментов и строки состояния, обработки уведомительных сообщений. Примеры и упражнения, приведенные в этой главе, связаны с примерами и упражнениями из предыдущих глав.
В глава 6 рассматриваются способы динамического создания диалоговых панелей. Показаны модальные и немодальные панели, а также блокноты диалоговых панелей. Представлены примеры обмена данными и обработки сообщений в диалоговых панелях и их блокнотах, а также примеры создания стандартных диалоговых панелей операционной системы.
Излагаемый материал построен на основе курса лекций по дисциплине «Программирование приложений Windows», которые автор читает в Брянском государственном техническом университете.
5
ГЛАВА 1. СОЗДАНИЕ ОКОН
Окна являются основой графического интерфеса пользователя операционной системы Windows.
Для разработчика окно является совокупностью большого числа элементов, функционирующих под управлением приложения и операционной системы.
С точки зрения языка программирования, окна – это объекты (переменные), над которыми выполняют действия. Объект принадлежит к определенному классу (типу), который описывает множество данных (параметров состояния окна) и метод (функцию) изменения этих данных.
1.1. Виды окон
Программы для операционной системы Windows называют приложениями. Пользователь взаимодействует с приложением через окна следующих видов:
1.Окно приложения. Оно элементизует работу, появляется первым при запуске и закрывается вместе с прекращением работы приложения.
2.MDI-окна. Они служат для одновременной обработки нескольких документов.
3.Окно помощи. Оно в большей степени работает под управлением операционной системы, чем под управлением приложения.
4.Диалоговое окно. Оно обеспечивает оперативный обмен данными между пользователем и приложением (рис. 1).
Главное окно на рис. 1 имеет обрамляющие двойные рамки, заголовок, различные кнопки, полосу меню, панель инструментов с кнопками, полосы просмотра, строку состояния и др. Эти элементы также являются окнами, имеют свои данные и метод их изменения, т.е. принадлежат к классам окон.
1.2. Класс окон
Для создания окна операционной системе указывают, к какому классу оно принадлежит. Если к моменту создания окна операционной системе известен класс создаваемого окна (например, это определенный в системе или зарегистрированный текущим или
6
другим приложением класс), то можно воспользоваться именем этого класса. Иначе необходимо создать новый класс (описать функцию окна и набор используемых ресурсов) и зарегистрировать его.
Рис. 1. Окно со множеством элементов:
1 – кнопка системного меню; 2 – кнопка сворачивания окна в пиктограмму; 3 – кнопка максимилизации или восстановления размеров окна; 4 – кнопка закрытия окна; 5 – рамки изменения размеров окна
1.2.1. Описание используемых классом окон ресурсов
Набор используемых ресурсов класса задается в структуре типа WNDCLASS. Эта структура описана следующим образом:
typedef struct { UINT style;
WNDPROC lpfnWndProc; int cbClsExtra;
int cbWndExtra; HANDLE hInstance;
7 |
|
HICON |
hIcon; |
HCURSOR |
hCursor; |
HBRUSH |
hbrBackground; |
LPCTSTR |
lpszMenuName; |
LPCTSTR |
lpszClassName; } |
WNDCLASS; |
Назначение полей структуры WNDCLASS:
1)style – стиль окон, принимает значения из прил. 1, табл. 1.1.
Например: wcstyle = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
2)lpfnWndProc – указатель на функцию окна;
3)cbClsExtra – число дополнительных байт класса;
4)cbWndExtra – число дополнительных байт окна этого класса;
5)hInstance – дескриптор текущего приложения;
6)hIcon – дескриптор пиктограммы (иконки), в которую превращается окно при минимизации. Ресурс иконки загружается функциейLoadIcon: ICON LoadIcon( HINSTANCE hInst, LPCTSTR lpIconName);
7)hCursor – дескриптор курсора мыши при его прохождении над окном.Ресурс курсора загружается функцией LoadCursor: HCURSOR LoadCursor( HINSTANCE hInst, LPCTSTR lpCursorName);
hbrBackground – дескриптор кисти закрашивания фона окна.В качестве кисти можно использовать цвета или пиктограмму. Чаще используют значение системного цвета (прил. 1, табл. 1.4.) плюс 1. Цвета преобразуют в тип HBRUSH. Например, следующий оператор устанавливает системный цвет закрашивания фона: wc. hbrBackground = (HBRUSH)( COLOR_WINDOW+1);
9)lpszMenuName – имя ресурса главного меню окон этого класса. Если задать NULL, окна этого класса не имеют заданного по умолчанию меню.
10)lpszClassName – текстовая строка, содержащая имя регистрируемого класса окон, например: wc.lpszClassName = szName;
1.2.2. Пример регистрации класса окон
Для регистрации класса окон удобно использовать функцию следующего вида:
int RegClass( WNDPROC Proc, LPCTSTR szName) {
8
WNDCLASS wc;
Wc.style = CS.HREDRAW | CS.VREDRAW; wc.cbClsExtra = wccbWndExtra = 0; wc.lpfnWndProc = Proc; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = (LPCTSTR)NULL; wc.lpszClassName = szName;
return RegisterClass(&wc); }
Формальными параметрами этой функции являются указатели на функцию окна и строку с именем класса. Имя, список формальных параметров и тип возврата функции могут быть другими. Главное, чтобы приложению после регистрации были доступны имя зарегистрированного класса, а операционной системе – функция окна этого класса. Поясним некоторые операторы этой функции.
Функция RegisterClass регистрирует класс в операционной системе. Ее аргументом является адрес подготовленной структуры wc. При успешной регистрации класса она возвращает ненулевое значение, иначе – нуль.
1.2.3. Функция окна
Функция окна описывает реакцию окна на поступающие сообщения. От обычных функций отличается следующим:
•имеет стандартные тип возврата и список формальных параметров;
•вызывается только операционной системой при поступлении сообщения окну;
•сообщения, которые не обрабатываются функцией окна, возвращаются операционной системе.
Есть еще одно отличие. В объектно-ориентированном программировании методы изменения параметров состояния объекта (функции-члены) обычно описывают отдельно. Функция окна реализует единственный метод для изменения всех параметров состояния окна.
Имя функции окна – это обычное имя, определяемое разработчиком. При регистрации класса операционная система запоминает указатель на эту функцию.
9
Рассмотрим пример описания функции окна.
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
static short ex, cy, left, top; //Описание локальных переменных switch (msg) //Обработка сообщения
{ case WM_CREATE: { …; return 0;} case WM_MOVE:{
left=LOWORD(lParam);
top=HIWORD(lParam); return 0;
}
case WM_SIZE:{
cx= LOWORD(lParam); cy= HIWORD(lParam);
return 0;
}
case WM_COMMAND: //Обрабатываем команды{ switch ( LOWORD(wParam))
{ case CM_FILE_EXIT:
{DestroyWindow(hwnd); return 0; }
//Далее могут быть ветви других команд
} return 0;
}
caseWM_DESTROY:
{…; PostQuitMessage(0); return 0;}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
Заголовок функции окна определен соглашениями Windows и
имеет вид LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
Тип возврата LRESULT равноценен типу signed long. Модификатор CALLBACK указывает на соглашение о том, что эта функция вызывается операционной системой (такие функции называют функциями обратного вызова).
Имена типов UINT, WPARAM, LPARAM описаны следующим образом:typedef unsigned int UINT; typedef UINT WPARAM; typedef LONG LPARAM;
10
Параметр hwnd – дескриптор окна-адресата, a параметры msg, wParam и lParam описывают полученное сообщение. Так, параметр msg принимает код рообщения.
Рассмотрим, каким сообщениям соответствуют используемые в примере имена констант. В Windows описаны несколько сот кодов сообщений с префиксом WM_.
Код WM_CREATE поступает от функции CreateWindow перед созданием окна. Если после обработки этого сообщения функции CreateWindow возвращается значение – 1, то окно не создается.
Код WM_SIZE функция окна получает после изменения размеров окна, a код WM_MOVE – после перемещения левого верхнего угла рабочей области окна. Если при изменении размеров окна изменились координаты левого верхнего угла рабочей области, то функция окна сначала получает код WM_MOVE, а затем – код WM_SIZE. После изменения режима отображения окна функция окна получает код WM_SIZE, а затем – WM_MOVE.
Код WM_COMMAND функция окна получает при поступлении команды. Тогда младшее слово параметра wParam содержит код команды. Разработчик свои сообщения часто связывает с командами меню и описывает идентификаторы для этих команд. Так, для идентификатора CM_FILE_EXIT команды меню текст приложения должен содержать макроопределение вида
#define CM_FILE_EXIT 3001
Код WM_DESTROY функции окна посылают перед разрушением окна. В примере функция окна, вызывая функцию DestroyWindow, сама себе отправляет сообщение WM_DESTROY.
Рассмотрим сообщения от мыши. Пусть курсор мыши находится над рабочей областью окна. После нажатия левой клавиши мыши функция окна получит код WM_LBUTTONDOWN а правой клавиши – код WM_RBUTTON DOWN. После отжатия левой (правой) клавиши функция окна получит код WM_LBUTTONUP (WM_RBUTTONUP). После перемещении курсора мыши функция окна получает код WM_MOUSEMOVE.
Можно получать сообщения от мыши, даже если курсор мыши не находится над рабочей областью окна. Для передачи мыши в монопольное использование окну hwnd вызывают функцию: HWND SetCapture(HWND hwnd);
Эта функция возвращает дескриптор окна, у которого в
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
Программирование приложений Windows. API графического интерфейса пользователя
Автор: kotmatros255 от 10-08-2021, 13:08, Коментариев: 0
Категория: КНИГИ » ПРОГРАММИРОВАНИЕ
Название: Программирование приложений Windows. API графического интерфейса пользователя
Автор: Белов Е.А.
Издательство: Брянск: БГТУ
Год: 2010
ISВN: 5-89838-495-1
Формат: pdf
Страниц: 351
Размер: 23,6 Mb
Язык: Русский
Изложены методические основы специальных средств программирования графического интерфейса пользователя операционной системы Windows, в том числе динамического программирования и управления базовыми элементами программных систем: окнами, элементами управления, меню и диалоговыми панелями. Рассмотрены методы создания высокоэффективных компактных быстродействующих приложений. Включены примеры программ.
Нашел ошибку? Есть жалоба? Жми!
Пожаловаться администрации
Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
Книжные памятники Свет
Обратная связь
Версия для слабовидящих
Войти
НЭБ
-
Коллекции и спецпроекты
-
Новости
-
Информация для библиотек
-
Программное обеспечение для библиотек
-
Вопросы и ответы
-
Обратная связь
-
Форум
Наши продукты
Книжные памятники
Пресса
Свет
Мы в соцсетях
Версия для слепых
Программирование приложений Windows. API графического интерфейса пользователя : учебное пособие / Е.А. Белов ; М-во образования и науки Российской Федерации, Брянский гос. технический ун-т
Белов Е.А.
Белов Е.А.
2010
Год издания
Брянск : Брянский гос. технический ун-т
Место издания
О произведении
Библиотека
Рязанская областная универсальная научная библиотека имени Горького
Еще
Ближайшая библиотека с бумажным экземпляром издания
Пожалуйста, авторизуйтесь
Вы можете добавить книгу в избранное после того, как
авторизуетесь на портале. Если у вас еще нет учетной записи, то
зарегистрируйтесь.
Программирование в Windows основывается на использовании функций API (Application Program Interface, т.е. интерфейс программного приложения).
Программа для Windows в значительной степени состоит из таких вызовов. Все взаимодействие с внешними устройствами и ресурсами операционной системы происходит посредством таких функций.
Программный интерфейс приложений
Windows API (Application Programming Interfaces) — общее наименование целого набора базовых функций интерфейсов программирования приложений операционных систем семейств Microsoft Windows.
Windows API в настоящее время поддерживает свыше тысячи вызовов функций, которые можно использовать в приложениях. Каждая функция Windows API имеет развернутое имя, написанное буквами как верхнего, так и нижнего регистров.
Все основные функции Windows объявляются в заголовочных файлах. Главный заголовочный файл называется WINDOWS.H, и в этом файле содержится множество ссылок на другие заголовочные файлы.
Основное отличие функций API от библиотечных функций С: код библиотечных функций связывается с кодом программы пользователя, а код функций API остается вне программы пользователя в динамически подключаемых библиотеках (DLL – Dynamic Link Library), что позволяет создавать более компактный и эффективный код приложений.
При запуске программы Windows она взаимодействует с операционной системой посредством процесса «динамического связывания». Большая часть динамических библиотек DLL расположена в каталоге WINDOWSSYSTEM.
При компоновке программы для Windows, чтобы сделать ее исполняемой, необходимо связывать ее с «библиотеками импорта», поставляемыми в составе среды программирования (IDE – Integrated Development Environment), которой может являться, в частности, Microsoft Visual Studio. Библиотеки импорта содержат имена всех функций Windows из динамически подключаемых библиотек и ссылки на них. Компоновщик использует эту информацию для создания в исполняемом EXE-файле таблицы, которую Windows использует при загрузке программы для настройки адресов функций API.
Графический интерфейс пользователя
Графический интерфейс пользователя (Graphical User Interface, GUI) еще называют «визуальный интерфейс» или «графическая оконная среда».
GUI делает возможным использование графики на растровом экране. Графика дает лучшее восприятие элементов управления на экране, визуально богатую среду для передачи информации. В GUI экран становится устройством ввода и показывает различные графические объекты в виде картинок и конструкций для ввода информации, таких как кнопки или полосы прокрутки. Используя клавиатуру и манипулятор (мышь, тачпад), пользователь может непосредственно оперировать объектами на экране. Графические объекты можно перетаскивать, кнопки можно нажимать, полосы прокрутки можно прокручивать. Взаимодействие между пользователем и программой становится более тесным.
Пользователям не надо тратить слишком много времени на то, чтобы научиться пользоваться компьютером и составлять новые программы. Система Windows способствует этому, поскольку все программы для Windows выглядят и воспринимаются одинаково.
Любая программа для Windows имеет окно — прямоугольную область на экране, в котором приложение отображает информацию и получает реакцию от пользователя. Окно идентифицируется заголовком. Большинство функций программы запускается посредством меню. Слишком большой для экрана объем информации может быть просмотрен с помощью полос прокрутки. Некоторые пункты меню вызывают появление окон диалога, в которые пользователь вводит дополнительную информацию.
Программирование Windows-приложений тесно связано с понятиями объектно-ориентированного программирования. Главным объектом в операционной системе Windows является окно. Окно может содержать элементы управления: кнопки, списки, окна редактирования и др. Эти элементы, по сути, также являются окнами, но обладающими особыми свойствами.
Активное окно – окно, получающее реакцию от пользователя в данный момент.
Основными элементами окна являются
- 1 — строка заголовка title bar
- 2 — строка меню menu bar
- 3 — системное меню system menu
- 4 — кнопка сворачивания окна minimize box
- 5 — кнопка разворачивания окна maximize box
- 6 — рамка изменения размеров sizing border
- 7 — клиентская область client area
- 8 — горизонтальная и вертикальная полосы прокрутки scroll bars
Многозадачность
Многозадачность (multitasking) — свойство операционной системы обеспечивать возможность параллельной (или псевдопараллельной) обработки нескольких процессов.
Операционная система Windows является многозадачной. Если программа DOS после своего запуска должна быть постоянно активной, и если ей что-то требуется (к примеру, получить очередную порцию данных с устройства ввода-вывода), то она сама должна выполнять соответствующие запросы к операционной системе, то в Windows все наоборот. Программа пассивна, после запуска она ждет, когда ей уделит внимание операционная система. Операционная система делает это посылкой специально оформленных групп данных, называемых сообщениями. Сообщения могут быть разного типа, они функционируют в системе достаточно хаотично, и приложение не знает, какого типа сообщение придет следующим.
Логика построения Windows-приложения должна обеспечивать корректную и предсказуемую работу при поступлении сообщений любого типа. Одновременно несколько программ могут выполняться и иметь вывод на экран. Каждая программа занимает на экране прямоугольное окно. Пользователь может перемещать окна по всему экрану, менять их размер, переключаться между разными программами и передавать данные от одной программы к другой.
Операционная система не сможет реализовать многозадачность без управления памятью. Так как одни программы запускаются, а другие завершаются, память фрагментируется. Операционная система Windows имеет средства управления фрагментами памяти.
Процессы и потоки
Процессом (process) называется экземпляр программы, загруженной в память. Экземпляр программы может создавать потоки (thread), которые представляют собой последовательность инструкций на выполнение.
Выполняются не процессы, а именно потоки. Любой процесс имеет хотя бы один поток. Этот поток называется главным (основным) потоком приложения.
Потоки на самом деле выполняются не одновременно, а по очереди. Распределение процессорного времени происходит между потоками, но переключение между ними происходит так часто, что кажется будто они выполняются параллельно.
Все потоки ранжируются по приоритетам. Приоритет потока обозначается числом от 0 до 31, и определяется исходя из приоритета процесса, породившего поток, и относительного приоритета самого потока. Таким образом, достигается наибольшая гибкость, и каждый поток в идеале получает столько времени, сколько ему необходимо.
Дескрипторы
Дескриптор (описатель) объекта — служебная структура данных, представляющая собой беззнаковое целое число и служащая для идентификации различных объектов. Дескриптор представляет собой указатель на некоторую системную структуру или индекс в некоторой системной таблице.
Примеры дескрипторов, описанных в заголовочном файле windows.h
typedef void *HANDLE; // абстрактный дескриптор (например, файла)
typedef void *HMODULE; // дескриптор модуля
typedef void *HINSTANCE; // дескриптор экземпляра программы
typedef void *HKEY; // дескриптор ключа в реестре
typedef void *HGDIOBJ; // дескриптор граф. примитива (перо, кисть)
typedef void *HWND; // дескриптор окна
typedef void *HMENU; // дескриптор меню
typedef void *HICON; // дескриптор иконки
typedef void *HBITMAP; // дескриптор картинки
typedef void *HFONT; // дескриптор шрифта
Контекст устройства
GDI – графический интерфейс устройства. Функции системной библиотеки GDI32.dll используются для вывода графики на экран.
Дескриптор контекста устройства — это паспорт конкретного окна для функций GDI. Контекст устройства фактически является структурой данных, которая внутренне поддерживается GDI. Он связан с конкретным устройством вывода информации (принтер, дисплей). Что касается дисплея, то в данном случае контекст устройства обычно связан с конкретным окном на экране.
Назад: Создание Windows-приложений
Аннотация: В данной лекции вводятся основные термины и понятие, используемые при разработке Windows-приложений. Рассматриваются простейшие примеры создания Windows-приложения с использованием Win-API.
Основные понятия и термины, используемые при разработке Windows приложений
Примеры программ для лекции.
Ядро Windows:
- USER (16, 32) .dll – функции ввода с клавиатуры мыши, ввод через интерфейс и т.д. (взаимодействие приложений с пользователями и средой Windows).
- KERNEL (16, 32) .dll – функции операционной системы (память, распределение системных ресурсов, загрузка).
- GDI (16, 32) .dll – графический интерфейс (функции создания и отображения графических объектов).
GUI (Graphics User Interface) – стандартный графический интерфейс пользователя. Это та часть Windows, которая обеспечивает поддержку аппаратно-независимой графики.
API (Application Program Interface) — интерфейс прикладных программ (набор функций, сосредоточенных в ядре Windows и дополнительных библиотеках).
DLL (Dynamic Link Libraries) — библиотека динамической компоновки. Функции API содержатся в библиотеках динамической загрузки.
DDE – динамический обмен данными.
Нотация Windows («венгерская нотация Чарльза Симони»)
При программировании под Windows принято использовать префиксы перед именами переменных, указывающие на принадлежность к типу данных. Рекомендуется давать имена собственным переменным и идентификаторам, придерживаясь следующих принципов:
- мнемоническое значение – идентификатор должен легко запоминаться;
- смысловое значение – роль идентификатора должна быть ясна из его названия;
- преемственность – похожие объекты должны иметь похожие идентификаторы;
- быстрота принятия решения – придумывание, ввод и редактирование идентификатора не должны занимать много времени.
Некоторые префиксы венгерской нотации:
Префикс | Значение |
---|---|
A | массив |
B | логический тип (int) |
By | беззнаковый символьный тип (byte) |
C | символьный тип (1 байт) |
Cb | счетчик байтов |
Cr | цвет |
cx,cy | короткий тип (short) |
Dbl | double (с плавающей точкой) |
Dw | беззнаковое длинное целое число (dword) |
Flt | float (вещественная с плавающей точкой) |
Fn | функция |
g_ | префикс для глобальной переменной (глобальная переменная) |
H | handle (беззнаковое целое число) |
hDC | handle (указатель на контекст устройства) |
I | целое (integer) |
Id | интегральное значение идентификатора |
L | длинный тип (long) |
Lp | длинный указатель |
Lpsz | дальний указатель на строку, заканчивающуюся нулевым байтом |
m_ | переменная класса |
N | short или int |
Np | ближний указатель |
P | указатель |
Pfn | указатель на функцию |
Pst | указатель на структуру |
Psz | указатель на строку, заканчивающуюся нулевым байтом |
Pv | указатель на тип void |
S | строка |
Sz | строка, заканчивающая нуль-символом |
U | беззнаковый символ |
Tm | текстовая метрика |
V | тип void |
W | беззнаковое целое (word, 16-бит) |
x, y | короткое целое число (координата x или y) |
Часто используемые типы данных Windows:
Тип данных | Описание |
---|---|
HANDLE | определяет идентификатор; 32-разрядное целое, используемое в качестве дескриптора – числа, определяющего некоторый ресурс |
HWND | определяет идентификатор окна |
HDC | определяет идентификатор контекста устройства |
LONG | 32-битовое целое со знаком |
LPSTR | определяет линейный указатель |
NULL | 0 |
UINT | тип данных Win32 (32 бита для Win32) |
WCHAR | 16-битовый символ UNICODE. Используется для представления символов языков мира |
Создание простейшего Windows-приложения с использованием Win API
Элементы Windows-приложения
Построение приложения Windows включает выполнение следующих этапов:
- Создание WinMain(…) и связанных с ней функций на языке C или C++.
- Создание описаний меню и всех дополнительных ресурсов, помещение описаний в файл описания ресурсов.
- Создание уникальных курсоров, пиктограмм и битовых образов.
- Создание диалоговых окон.
- Создание файла проекта.
- Компиляция и компоновка всего кода.
Простейшая программа. Создание и вывод Windows-окна на экран
Создадим пустой проект Windows- приложения с помощью мастера:
- File New Project.
- Project types: Win32 Templates: Win32 Project.
- Ok.
- Установить галочку Empty project.
- Добавить в проект файл *.cpp.
- Project Properties. Вкладка Configuration Properties General.
- Значение поля Character Set устанавливаем Use Multi-Byte Character Set.
Добавим следующий код:
#include <windows.h> LONG WINAPI WndProc(HWND, UINT, WPARAM,LPARAM); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HWND hwnd; MSG msg; WNDCLASS w; memset(&w,0,sizeof(WNDCLASS)); w.style = CS_HREDRAW | CS_VREDRAW; w.lpfnWndProc = WndProc; w.hInstance = hInstance; w.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); w.lpszClassName = "My Class"; RegisterClass(&w); hwnd = CreateWindow("My Class", "Окно пользователя", WS_OVERLAPPEDWINDOW,500, 300, 500, 380, NULL, NULL, hInstance, NULL); ShowWindow(hwnd,nCmdShow); UpdateWindow(hwnd); while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LONG WINAPI WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam) { switch (Message) { case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, Message, wparam, lparam); } return 0; }
Скомпилируем и запустим программу. На экране появится Windows-окно.
Комментарии к программе
Все приложения Windows должны содержать два основных элемента: функцию WinMain(…) и функцию окна WndProc.
Функция WinMain(…) служит точкой входа в приложение. Эта функция отвечает за следующие действия:
- регистрацию типа класса окон приложения;
- выполнение всех инициализирующих действий;
- создание и инициализацию цикла сообщений приложения;
- завершение программы (обычно при получении сообщения WM_QUIT ).
Функция WndProc отвечает за обработку сообщений Windows. Эта часть программы является наиболее содержательной с точки зрения выполнения поставленных перед программой задач. Если мы хотим, чтобы программа обращала на наши действия внимание, то необходимо добавить ветки case для оператора switch в оконную процедуру WndProc. Например, если мы хотим, чтобы наше приложение обращало внимание на щелчок левой кнопкой мыши – добавляем ветку case WM_LBUTTONDOWN. В настоящий момент в оконной процедуре происходит только обработка сообщения WM_DESTROY. Больше Windows-окно пока ничего делать не умеет.
Заголовочный файл windows.h нужен для любой традиционной Windows программы на C. Именно в нем содержатся разные определения констант ( WM_DESTROY и т. д.).
Параметры функции WinMain:
- hInstance (тип HINSTANCE ) – является идентификатором текущего экземпляра приложения. Данное число однозначно определяет программу, работающую под управлением Windows.
- hPrevInstance (тип HINSTANCE ) – указывал ранее (Windows 3.1) на предыдущий запущенный экземпляр приложения. В современных версиях Windows он равен NULL.
- lpCmdLine – это указатель на строку, заканчивающуюся нулевым байтом. В этой строке содержатся аргументы командной строки приложения (как правило, содержит NULL ).
- nCmdShow – этот параметр принимает значение одной из системных констант, определяющих способ изображения окна (например, SW_SHOWNORMAL, SW_SHOWMAXIMIZED или SW_SHOWMINIMIZED ).
Обзор типов оконных приложений в C#. Знакомство со структорой проекта WPF. Компоновка.
В C# есть несколько технологий для созданий оконных приложений:
-
Windows Forms — разработка «классических» приложений Windows (а-ля XP), считается устаревшей
Windows Forms — интерфейс программирования приложений (API), отвечающий за графический интерфейс пользователя и являющийся частью Microsoft .NET Framework. Данный интерфейс упрощает доступ к элементам интерфейса Microsoft Windows за счет создания обёртки для существующего Win32 API в управляемом коде. Причём управляемый код — классы, реализующие API для Windows Forms, не зависят от языка разработки.
-
WPF (Window Presentation Foundation) — основной фреймворк, на котором мы дальше и будем работать
-
UWP (Universal Windows Platform) — вроде как «последний писк», рассчитанный на разработку универсальных приложений под Windows Phone, Windows 8 и.т.д
Особенности платформы WPF
Если при создании традиционных приложений на основе WinForms за отрисовку элементов управления и графики отвечали такие части ОС Windows, как User32 и GDI+, то приложения WPF основаны на DirectX. В этом состоит ключевая особенность рендеринга графики в WPF: используя WPF, значительная часть работы по отрисовке графики, как простейших кнопочек, так и сложных 3D-моделей, ложиться на графический процессор на видеокарте, что также позволяет воспользоваться аппаратным ускорением графики.
Одной из важных особенностей является использование языка декларативной разметки интерфейса XAML, основанного на XML: вы можете создавать насыщенный графический интерфейс, используя или декларативное объявление интерфейса, или код на управляемых языках C# и VB.NET, либо совмещать и то, и другое.
Преимущества WPF
Что вам, как разработчику, предлагает WPF?
-
Использование традиционных языков .NET-платформы — C# и VB.NET для создания логики приложения
-
Возможность декларативного определения графического интерфейса с помощью специального языка разметки XAML, основанном на xml и представляющем альтернативу программному созданию графики и элементов управления, а также возможность комбинировать XAML и C#/VB.NET
-
Независимость от разрешения экрана: поскольку в WPF все элементы измеряются в независимых от устройства единицах, приложения на WPF легко масштабируются под разные экраны с разным разрешением.
-
Новые возможности, которых сложно было достичь в WinForms, например, создание трехмерных моделей, привязка данных, использование таких элементов, как стили, шаблоны, темы и др.
-
Хорошее взаимодействие с WinForms, благодаря чему, например, в приложениях WPF можно использовать традиционные элементы управления из WinForms.
-
Богатые возможности по созданию различных приложений: это и мультимедиа, и двухмерная и трехмерная графика, и богатый набор встроенных элементов управления, а также возможность самим создавать новые элементы, создание анимаций, привязка данных, стили, шаблоны, темы и многое другое
-
Аппаратное ускорение графики — вне зависимости от того, работаете ли вы с 2D или 3D, графикой или текстом, все компоненты приложения транслируются в объекты, понятные Direct3D, и затем визуализируются с помощью процессора на видеокарте, что повышает производительность, делает графику более плавной.
Создание оконного приложения
Запустите Microsoft Visual Studio (MVS) и создайте новое приложение:
Тип приложения: WPF (.NET Framework)
При создании задаете Имя проекта и, если нужно, Расположение. Остальные параметры оставляем по-умолчанию.
Название проекта должно отражать предметную область или название компании (за это есть отдельные баллы на WorldSkills-е и демо-экзамене)
По-умолчанию IDE Visual Studio разбито на 3 части:
- слева панель элементов — список визуальных элементов (кнопки, токстовые поля и т.п.)
- в центре основное окно, предназначенное для редактирования исходного кода. При отображении файлов XAML (читается как «замл») разбито на две части: визуальное отображение и текст разметки
- справа Обозреватель решений и структура проекта: Properties (Свойства); Ссылки (Зависимости); App.config — настройки проекта; App.xaml — разметка проекта и MainWindow.xaml — разметка окна.
Если каких-то панелей нет на экране, то можно их найти в меню Вид.
Основные типы файлов проекта:
- .XAML eXtended Application Markup Languale — язык разметки, очень похож на XML. В таких файлах хранится описание внешнего вида окна.
- .cs — файлы с исходным кодом на C# для окна.
Структура проекта
В структуре проекта WPF следует выделить следующие моменты. Во-первых, в проекте имеется файл App.xaml
и связанный с ним файл кода App.xaml.cs
— это глобальные файлы для всего приложения, позже мы о них поговорим подробнее. А пока только следует знать, что App.xaml
задает файл окна программы, которое будет открываться при запуске приложения. Если вы откроете этот файл, то можете найти в нем строку StartupUri="MainWindow.xaml"
— то есть в данном случае, когда мы запустим приложение, будет создаваться интерфейс из файла MainWindow.xaml
.
Далее в структуре определены файл разметки MainWindow.xaml
и файл связанного кода MainWindow.xaml.cs
. Файл MainWindow.xaml
и представляет определение окна приложение, которое мы увидим при запуске.
Введение в язык XAML
XAML (eXtensible Application Markup Language) — язык разметки, используемый для инициализации объектов в технологиях на платформе .NET. Применительно к WPF данный язык используется прежде всего для создания пользовательского интерфейса декларативным путем, наподобие HTML в веб-программировании.
XAML — не является обязательной частью приложения, мы вобще можем обходиться без него, создавая все элементы в файле связанного с ним кода на языке C#. Однако использование XAML все-таки несет некоторые преимущества:
-
Возможность отделить графический интерфейс от логики приложения, благодаря чему над разными частями приложения могут относительно автономно работать разные специалисты: над интерфейсом — дизайнеры, над кодом логики — программисты.
-
Компактность, понятность, код на XAML относительно легко поддерживать.
При компиляции приложения в Visual Studio код в xaml-файлах также компилируется в бинарное представление кода xaml, которое называется BAML (Binary Application Markup Language). И затем код baml встраивается в финальную сборку приложения — exe или dll-файл.
Структура и пространства имен XAML
При создании нового проекта WPF он уже содержит файлы с кодом xaml. Так, создаваемый по умолчанию в проекте файл MainWindow.xaml
будет иметь следующую разметку:
<Window x:Class="XamlApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:XamlApp" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Grid> </Grid> </Window>
Если вы совершенно не знакомы с xaml и с xml, то даже этот небольшой минимальный код окна может вызывать затруднения.
Подобно структуре веб-страничке на html, здесь есть некоторая иерархия элементов. Элементов верхнего уровня является Window, который представляет собой окно приложения. При создании других окон в приложении нам придется всегда начинать объявление интерфейса с элемента Window, поскольку это элемент самого верхнего уровня.
Кроме Window существует еще два элемента верхнего уровня:
- Page
- Application
Элемент Window имеет вложенный пустой элемент Grid, а также подобно html-элементам ряд атрибутов (Title, Width, Height) — они задают заголовок, ширину и высоту окна соответственно.
Пространства имен XAML
При создании кода на языке C#, чтобы нам были доступны определенные классы, мы подключаем пространства имен с помощью директивы using, например, using System.Windows;
.
Чтобы задействовать элементы в XAML, мы также подключаем пространства имен. Вторая и третья строчки как раз и представляют собой пространства имен, подключаемые в проект по умолчанию. А атрибут xmlns представляет специальный атрибут для определения пространства имен в XML.
Так, пространство имен http://schemas.microsoft.com/winfx/2006/xaml/presentation содержит описание и определение большинства элементов управления. Так как является пространством имен по умолчанию, то объявляется без всяких префиксов.
http://schemas.microsoft.com/winfx/2006/xaml — это пространство имен, которое определяет некоторые свойства XAML, например свойство Name или Key. Используемый префикс x в определении xmlns:x означает, что те свойства элементов, которые заключены в этом пространстве имен, будут использоваться с префиксом x — x:Name или x:Key. Это же пространство имен используется уже в первой строчке x:Class=»XamlApp.MainWindow» — здесь создается новый класс MainWindow и соответствующий ему файл кода, куда будет прописываться логика для данного окна приложения.
Это два основных пространства имен. Рассмотрим остальные:
xmlns:d=»http://schemas.microsoft.com/expression/blend/2008″: предоставляет поддержку атрибутов в режиме дизайнера. Это пространство имен преимущественно предназначено для другого инструмента по созданию дизайна на XAML — Microsoft Expression Blend
xmlns:mc=»http://schemas.openxmlformats.org/markup-compatibility/2006″: обеспечивает режим совместимости разметок XAML. В определении объекта Window двумя строчками ниже можно найти его применение:
xmlns:local=»clr-namespace:XamlApp»: пространство имен текущего проекта. Так как в нашем случае проект называется XamlApp, то простраство имен называется аналогично. И через префикс local я смогу получить в XAML различные объекты, которые я определил в проекте.
Важно понимать, что эти пространства имен не эквивалентны тем пространствам имен, которые подключаются при помощи директивы using в c#.
Элементы и их атрибуты
XAML предлагает очень простую и ясную схему определения различных элементов и их свойств. Каждый элемент, как и любой элемент XML, должен иметь открытый и закрытый тег, как в случае с элементом Window:
Либо элемент может иметь сокращенню форму с закрывающим слешем в конце, наподобие:
Но в отличие от элементов xml каждый элемент в XAML соответствует определенному классу C#. Например, элемент Button соответствует классу System.Windows.Controls.Button. А свойства этого класса соответствуют атрибутам элемента Button.
Например, добавим кнопку в создаваемую по умолчанию разметку окна:
<Window x:Class="XamlApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:XamlApp" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Grid x:Name="grid1"> <Button x:Name="button1" Width="100" Height="30" Content="Кнопка" /> </Grid> </Window>
Сначала идет элемент самого высшего уровня — Window, затем идет вложенный элемент Grid — контейнер для других элементов, и в нем уже определен элемент Button, представляющий кнопку.
Для кнопки мы можем определить свойства в виде атрибутов. Здесь определены атрибуты x:Name (имя кнопки), Width, Height и Content. Причем, атрибут x:Name берется в данном случае из пространства имен «http://schemas.microsoft.com/winfx/2006/xaml», которое сопоставляется с префиксом x. А остальные атрибуты не используют префиксы, поэтому берутся из основного пространства имен «http://schemas.microsoft.com/winfx/2006/xaml/presentation».
Подобным образом мы можем определить и другие атрибуты, которые нам нужны. Либо мы в общем можем не определять атрибуты, и тогда они будут использовать значения по умолчанию.
Определив разметку xaml, мы можем запустить проект, и нам отобразится графически весь код xaml — то есть наша кнопка.
Специальные символы
При определении интерфейса в XAML мы можем столкнуться с некоторыми ограничениями. В частости, мы не можем использовать специальные символы, такие как знак амперсанда &, кавычки » и угловые скобки < и >. Например, мы хотим, чтобы текст кнопки был следующим: <"Hello">
. У кнопки есть свойство Content, которое задает содержимое кнопки. И можно предположить, что нам надо написать так:
<Button Content="<"Hello">" />
Но такой вариант ошибочен и даже не скомпилирутся. В этом случае нам надо использовать специальные коды символов:
Символ | Код |
---|---|
< |
< |
> |
> |
& | & |
« | " |
Например:
<Button Content="<"Hello">" />
Еще одна проблема, с которой мы можем столкнуться в XAML — добавление пробелов. Возьмем, к примеру, следующее определение кнопки:
<Button> Hello World </Button>
Здесь свойство Content задается неявно в виде содержимого между тегами <Button>....</Button>
. Но несмотря на то, что у нас несколько пробелов между словами «Hello» и «World», XAML по умолчанию будет убирать все эти пробелы. И чтобы сохранить пробелы, нам надо использовать атрибут xml:space="preserve"
:
<Button xml:space="preserve"> Hello World </Button>
Файлы отделенного кода
При создании нового проекта WPF в дополнение к создаваемому файлу MainWindow.xaml
создается также файл отделенного кода MainWindow.xaml.cs
, где, как предполагается, должна находится логика приложения связанная с разметкой из MainWindow.xaml
. Файлы XAML позволяют нам определить интерфейс окна, но для создания логики приложения, например, для определения обработчиков событий элементов управления, нам все равно придется воспользоваться кодом C#.
По умолчанию в разметке окна используется атрибут x:Class
:
<Window x:Class="XamlApp.MainWindow" .......
Атрибут x:Class
указывает на класс, который будет представлять данное окно и в который будет компилироваться код в XAML при компиляции. То есть во время компиляции будет генерироваться класс XamlApp.MainWindow, унаследованный от класса System.Windows.Window.
Кроме того в файле отделенного кода MainWindow.xaml.cs
, который Visual Studio создает автоматически, мы также можем найти класс с тем же именем — в данном случае класс XamlApp.MainWindow. По умолчанию он имеет некоторый код:
namespace XamlApp { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } } }
По сути пустой класс, но этот класс уже выполняет некоторую работу. Во время компиляции этот класс объединяется с классом, сгенерированном из кода XAML. Чтобы такое слияние классов во время компиляции произошло, класс XamlApp.MainWindow определяется как частичный с модификатором partial. А через метод InitializeComponent() класс MainWindow вызывает скомпилированный ранее код XAML, разбирает его и по нему строит графический интерфейс окна.
Взаимодействие кода C# и XAML
В приложении часто требуется обратиться к какому-нибудь элементу управления. Для этого надо установить у элемента в XAML свойство Name.
Еще одной точкой взаимодействия между xaml и C# являются события. С помощью атрибутов в XAML мы можем задать события, которые будут связанны с обработчиками в коде C#.
Итак, создадим новый проект WPF, который назовем XamlApp. В разметке главного окна определим два элемента: кнопку и текстовое поле.
<Grid x:Name="grid1"> <TextBox x:Name="textBox1" Width="150" Height="30" VerticalAlignment="Top" Margin="20" /> <Button x:Name="button1" Width="100" Height="30" Content="Кнопка" Click="Button_Click" /> </Grid>
И изменим файл отделенного кода, добавив в него обработчик нажатия кнопки:
namespace XamlApp { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { string text = textBox1.Text; if (text != "") { MessageBox.Show(text); } } } }
Определив имена элементов в XAML, затем мы можем к ним обращаться в коде c#: string text = textBox1.Text
.
В обработчике нажатия кнопки просто выводится сообщение , введенное в текстовое поле. После определения обработчика мы его можем связать с событием нажатия кнопки в xaml через атрибут Click: Click="Button_Click"
. В результате после нажатия на кнопку мы увидим в окне введенное в текстовое поле сообщение.
Пространства имен из C# в XAML
По умолчанию в WPF в XAML подключается предустановленный набор пространств имен xml. Но мы можем задействовать любые другие пространства имен и их функциональность в том числе и стандартные пространства имен платформы .NET, например, System или System.Collections. Например, по умолчанию в определении элемента Window подключается локальное пространство имен:
xmlns:local="clr-namespace:XamlApp"
Локальное пространство имен, как правило, называется по имени проекта (в моем случае проект называется XamlApp) и позволяет подключить все классы, которые определены в коде C# в нашем проекте. Например, добавим в проект следующий класс:
public class Phone { public string Name { get; set; } public int Price { get; set; } public override string ToString() { return $"Смартфон {this.Name}; цена: {this.Price}"; } }
Используем этот класс в коде xaml:
<Grid x:Name="layoutGrid"> <Button x:Name="phoneButton" Width="250" Height="40" HorizontalAlignment="Center"> <Button.Content> <local:Phone Name="Lumia 950" Price="700" /> </Button.Content> </Button> </Grid>
Так как пространство имен проекта проецируется на префикс local, то все классы проекта используются в форме local:Название_Класса
. Так в данном случае объект Phone устанавливается в качестве содержимого кнопки через свойство Content. Для сложных объектов это свойство принимает их строковое представление, которое возвращается методом ToString().
Мы можем подключить любые другие пространства имен, классы которых мы хотим использовать в приложении. Например:
<Window x:Class="XamlApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:XamlApp" xmlns:col="clr-namespace:System.Collections;assembly=mscorlib" xmlns:sys="clr-namespace:System;assembly=mscorlib" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <col:ArrayList x:Key="days"> <sys:String>Понедельник</sys:String> <sys:String>Вторник</sys:String> <sys:String>Среда</sys:String> <sys:String>Четверг</sys:String> <sys:String>Пятница</sys:String> <sys:String>Суббота</sys:String> <sys:String>Воскресенье</sys:String> </col:ArrayList> </Window.Resources> <Grid> </Grid> </Window>
Здесь определены два дополнительных пространства имен:
xmlns:col="clr-namespace:System.Collections;assembly=mscorlib"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Благодаря этому нам становятся доступными объекты из пространств имен System.Collections и System. И затем используя префикс, мы можем использовать объекты, входящие в данные пространства имен: <col:ArrayList....
Общий синтаксис подключения пространств имен следующий: xmlns:Префикс="clr-namespace:Пространство_имен;assembly=имя_сборки"
. Так в предыдущем случае мы подключили пространство имен System.Collections, классы которого находятся в сборке mscorlib. И данное подключенное пространство имен у нас отображено на префикс col.
Компоновка
Чтобы перейти уже непосредственно к созданию красивых интерфейсов и их компонентов, сначала необходимо познакомиться с компоновкой. Компоновка (layout) представляет собой процесс размещения элементов внутри контейнера. Возможно, вы обращали внимание, что одни программы и веб-сайты на разных экранах с разным разрешением выглядят по-разному: где-то лучше, где-то хуже. В большинстве своем такие программы используют жестко закодированные в коде размеры элементов управления. WPF уходит от такого подхода в пользу так называемого «резинового дизайна», где весь процесс позиционирования элементов осуществляется с помощью компоновки.
Благодаря компоновке мы можем удобным нам образом настроить элементы интерфейса, позиционировать их определенным образом. Например, элементы компоновки в WPF позволяют при ресайзе — сжатии или растяжении масштабировать элементы, что очень удобно, а визуально не создает всяких шероховатостей типа незаполненных пустот на форме.
В WPF компоновка осуществляется при помощи специальных контейнеров. Фреймворк предоставляет нам следующие контейнеры: Grid, UniformGrid, StackPanel, WrapPanel, DockPanel и Canvas.
Различные контейнеры могут содержать внутри себя другие контейнеры. Кроме данных контейнеров существует еще ряд элементов, такие как TabPanel, которые могут включать другие элементы и даже контейнеры компоновки, однако на саму компоновку не столь влияют в отличие от выше перечисленных. Кроме того, если нам не хватает стандартных контейнеров, мы можем определить свои с нужной нам функциональностью.
Контейнеры компоновки позволяют эффективно распределить доступное пространство между элементами, найти для него наиболее предпочтительные размеры.
В WPF при компоновке и расположении элементов внутри окна нам надо придерживаться следующих принципов:
-
Нежелательно указывать явные размеры элементов (за исключеним минимальных и максимальных размеров). Размеры должны определяться контейнерами.
-
Нежелательно указывать явные позицию и координаты элементов внутри окна. Позиционирование элементов всецело должно быть прерогативой контейнеров. И контейнер сам должен определять, как элемент будет располагаться. Если нам надо создать сложную систему компоновки, то мы можем вкладывать один контейнер в другой, чтобы добиться максимально удобного расположения элементов управления.
Grid
Это наиболее мощный и часто используемый контейнер, напоминающий обычную таблицу. Он содержит столбцы и/или строки, количество которых задает разработчик. Для определения строк используется свойство RowDefinitions, а для определения столбцов — свойство ColumnDefinitions:
<Grid> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> </Grid>
Можно писть это в разметке, но можно просто кликнуть мышкой по границе Grid-а:
Каждая строка задается с помощью вложенного элемента RowDefinition, который имеет открывающий и закрывающий тег. При этом задавать дополнительную информацию необязательно. То есть в данном случае у нас определено в гриде 3 строки.
Каждая столбец задается с помощью вложенного элемента ColumnDefinition. Таким образом, здесь мы определили 3 столбца. ТО есть в итоге у нас получится таблица 3х3.
Чтобы задать позицию элемента управления с привязкой к определенной ячейке Grid-а, в разметке элемента нужно прописать значения свойств Grid.Column и Grid.Row, тем самым указывая, в каком столбце и строке будет находиться элемент. Кроме того, если мы хотим растянуть элемент управления на несколько строк или столбцов, то можно указать свойства Grid.ColumnSpan и Grid.RowSpan, как в следующем примере:
<Window x:Class="LayoutApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:LayoutApp" mc:Ignorable="d" Title="Grid" Height="250" Width="350"> <Grid ShowGridLines="True"> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <Button Grid.Column="0" Grid.Row="0" Content="Строка 0 Столбец 0" /> <Button Grid.Column="0" Grid.Row="1" Content="Объединение трех столбцов" Grid.ColumnSpan="3" /> <Button Grid.Column="2" Grid.Row="2" Content="Строка 2 Столбец 2" /> </Grid> </Window>
Атрибут ShowGridLines=»True» у элемента Grid задает видимость сетки, по умолчанию оно равно False.
То есть у нас получится следующая картина:
Установка размеров
Но если в предыдущем случае у нас строки и столбцы были равны друг другу, то теперь попробуем их настроить столбцы по ширине, а строки — по высоте. Есть несколько вариантов настройки размеров.
Автоматические размеры
Здесь столбец или строка занимает то место, которое им нужно
<ColumnDefinition Width="Auto" /> <RowDefinition Height="Auto" />
Абсолютные размеры
В данном случае высота и ширина указываются в единицах, независимых от устройства:
<ColumnDefinition Width="150" /> <RowDefinition Height="150" />
Также абсолютные размеры можно задать в пикселях, дюймах, сантиметрах или точках:
- пиксели: px
- дюймы: in
- сантиметры: cm
- точки: pt (точка в вёрстке это не точка на экране, а 1/72 дюйма)
Например,
<ColumnDefinition Width="1 in" /> <RowDefinition Height="10 px" />
Пропорциональные размеры.
Например, ниже задаются два столбца, второй из которых имеет ширину в четверть от ширины первого:
<ColumnDefinition Width="*" /> <ColumnDefinition Width="0.25*" />
Если строка или столбец имеет высоту, равную *
, то данная строка или столбце будет занимать все оставшееся место. Если у нас есть несколько сток или столбцов, высота которых равна *
, то все доступное место делится поровну между всеми такими сроками и столбцами. Использование коэффициентов (0.25*
) позволяет уменьшить или увеличить выделенное место на данный коэффициент. При этом все коэффициенты складываются (коэффициент *
аналогичен 1*
) и затем все пространство делится на сумму коэффициентов.
Например, если у нас три столбца:
<ColumnDefinition Width="*" /> <ColumnDefinition Width="0.5*" /> <ColumnDefinition Width="1.5*" />
В этом случае сумма коэффициентов равна 1* + 0.5* + 1.5* = 3*
. Если у нас грид имеет ширину 300 единиц, то для коэфициент 1*
будет соответствовать пространству 300 / 3 = 100 единиц. Поэтому первый столбец будет иметь ширину в 100 единиц, второй — 100*0.5=50 единиц, а третий — 100 * 1.5 = 150 единиц.
Можно комбинировать все типы размеров. В этом случае от ширины/высоты грида отнимается ширина/высота столбцов/строк с абсолютными или автоматическими размерами, и затем оставшееся место распределяется между столбцами/строками с пропорциональными размерами:
GridSplitter
Элемент GridSplitter помогает создавать интерфейсы наподобие элемента SplitContainer в WinForms, только более функциональные. Он представляет собой некоторый разделитель между столбцами или строками, путем сдвига которого можно регулировать ширину столбцов и высоту строк. В качестве примера можно привести стандартный интерфейс проводника в Windows, где разделительная полоса отделяет древовидный список папок от панели со списком файлов. Например,
<Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Button Grid.Column="0" Content="Левая кнопка" /> <GridSplitter Grid.Column="1" ShowsPreview="False" Width="3" HorizontalAlignment="Center" VerticalAlignment="Stretch" /> <Button Grid.Column="2" Content="Правая кнопка" /> </Grid>
Двигая центральную линию, разделяющую правую и левую части, мы можем устанавливать их ширину.
Итак, чтобы использовать элемент GridSplitter, нам надо поместить его в ячейку в Gride. По сути это обычный элемент, такой же, как кнопка. Как выше, у нас три ячейки (так как три столбца и одна строка), и GridSplitter помещен во вторую ячейку. Обычно строка или столбец, в которые помещают элемент, имеет для свойств Height или Width значение Auto.
Если у нас несколько строк, и мы хотим, чтобы разделитель распространялся на несколько строк, то мы можем задать свойство Grid.RowSpan:
<Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <GridSplitter Grid.Column="1" Grid.RowSpan="2" ShowsPreview="False" Width="3" HorizontalAlignment="Center" VerticalAlignment="Stretch" />
В случае, если мы задаем горизонтальный разделитель, то тогда соответственно надо использовать свойство Grid.ColumnSpan
Затем нам надо настроить свойства. Во-первых, надо настроить ширину (Width) для вертикальных сплитеров и высоту (Height) для горизонтальных. Если не задать соответствующее свойство, то сплитер мы не увидим, так как он изначально очень мал.
Затем нам надо задать выравнивание. Если мы хотим, что сплитер заполнял всю высоту доступной области (то есть если у нас вертикальный сплитер), то нам надо установить для свойства VerticalAlignment значение Stretch.
Если же у нас горизонтальный сплитер, то надо установить свойство HorizontalAlignment в Stretch
Также в примере выше используется свойство ShowsPreview. Если оно равно False, то изменение границ кнопок будет происходить сразу же при перемещении сплитера. Если же оно равно True, тогда изменение границ будет происходить только после того, как перемещение сплитера завершится, и при перемещении сплиттера мы увидим его проекцию.
StackPanel
Это более простой элемент компоновки. Он располагает все элементы в ряд либо по горизонтали, либо по вертикали в зависимости от ориентации. Например,
<Grid> <StackPanel> <Button Background="Blue" Content="1" /> <Button Background="White" Content="2" /> <Button Background="Red" Content="3" /> </StackPanel> </Grid>
В данном случае для свойства Orientation по умолчанию используется значение Vertical, то есть StackPanel создает вертикальный ряд, в который помещает все вложенные элементы сверху вниз. Мы также можем задать горизонтальный стек. Для этого нам надо указать свойство Orientation=»Horizontal»:
<StackPanel Orientation="Horizontal"> <Button Background="Blue" MinWidth="30" Content="1" /> <Button Background="White" MinWidth="30" Content="2" /> <Button Background="Red" MinWidth="30" Content="3" /> </StackPanel>
При горизонтальной ориентации все вложенные элементы располагаются слева направо. Если мы хотим, чтобы наполнение стека начиналось справа налево, то нам надо задать свойство FlowDirection: <StackPanel Orientation="Horizontal" FlowDirection="RightToLeft">
. По умолчанию это свойство имеет значение LeftToRight — то есть слева направо.
WrapPanel
Эта панель, подобно StackPanel, располагает все элементы в одной строке или колонке в зависимости от того, какое значение имеет свойство Orientation — Horizontal или Vertical. Главное отличие от StackPanel — если элементы не помещаются в строке или столбце, создаются новые столбец или строка для не поместившихся элементов.
<Window x:Class="LayoutApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:LayoutApp" mc:Ignorable="d" Title="WrapPanel" Height="250" Width="300"> <WrapPanel> <Button Background="AliceBlue" Content="Кнопка 1" /> <Button Background="Blue" Content="Кнопка 2" /> <Button Background="Aquamarine" Content="Кнопка 3" Height="30"/> <Button Background="DarkGreen" Content="Кнопка 4" Height="20"/> <Button Background="LightGreen" Content="Кнопка 5"/> <Button Background="RosyBrown" Content="Кнопка 6" Width="80" /> <Button Background="GhostWhite" Content="Кнопка 7" /> </WrapPanel> </Window>
В горизонтальном стеке те элементы, у которых явным образом не установлена высота, будут автоматически принимать высоту самого большого элемента из стека.
Вертикальный WrapPanel делается аналогично:
<WrapPanel Orientation="Vertical"> <Button Background="AliceBlue" Content="Кнопка 1" Height="50" /> <Button Background="Blue" Content="Кнопка 2" /> <Button Background="Aquamarine" Content="Кнопка 3" Width="60"/> <Button Background="DarkGreen" Content="Кнопка 4" Width="80"/> <Button Background="LightGreen" Content="Кнопка 5"/> <Button Background="RosyBrown" Content="Кнопка 6" Height="80" /> <Button Background="GhostWhite" Content="Кнопка 7" /> <Button Background="Bisque" Content="Кнопка 8" /> </WrapPanel>
В вертикальном стеке элементы, у которых явным образом не указана ширина, автоматически принимают ширину самого широкого элемента.
Мы также можем установить для всех вложенных элементов какую-нибудь определенную ширину (с помощью свойства ItemWidth) или высоту (свойство ItemHeight):
<WrapPanel ItemHeight="30" ItemWidth="80" Orientation="Horizontal"> <Button Background="AliceBlue" Content="1" /> <Button Background="Blue" Content="2" /> <Button Background="Aquamarine" Content="3"/> <Button Background="DarkGreen" Content="4"/> <Button Background="LightGreen" Content="5"/> <Button Background="AliceBlue" Content="6" /> <Button Background="Blue" Content="7" /> </WrapPanel>
Image
Для добавления ресурсов в проект можно создать в нём каталог (кликнуть правой кнопкой мышки на название проекта и выбрать Добавить — Создать папку) и скопировать в него нужный ресурс, в нашем случае картинку.
Обратите внимание, копировать нужно именно в интерфейсе Visual Studio, а не средствами ОС, иначе VS будет искать ресурс не в папке проекта, а в текущей папке VS.
И добавим картинку в сетку:
... <Image Source="./img/simon.png" VerticalAlignment="Top"/> </Grid>
Атрибут VerticalAlignment устанавливает вертикальное выравнивание элемента относительно предка (Grid-а).
Атрибут Grid.ColumnSpan (есть и RowSpan) позволяет разместить элемент не в одной ячейке Grid-a, а «размазать» на несколько. Например, можно сделать фоновую картинку (как в примере ниже) или горизонтальное меню в верхней строке.
<Image Source="./img/simon.png" VerticalAlignment="Top" Grid.ColumnSpan="3"/>