Reference = add reference, в висуал студия 2010 не могу найти в вкладке Solution Explorer, Microsoft.Xna.Framework. Его нету. |
Усложненные технологии визуализации
3.2.3. Диалоговое окно выбора видеорежима
Диалоговое окно выбора видеорежима из примера Ch03\Ex05 хотя и выполняет свою задачу, однако имеет при этом ряд существенных недостатков, затрудняющих его применение в реальных приложениях:
- При каждом запуске приложения приходится заново выбирать видеорежим, что довольно быстро начинает раздражать. Поэтому было бы логичным реализовать сохранение параметров выбранного видеорежима в конфигурационный файл.
- Все параметры видеорежимов "свалены в одну кучу ", отчего очень быстро начинает "рябить в глазах ". Коммерческие приложения обычно разбивают информацию о видеорежимах на три списка: в первом списке пользователь выбирает разрешение экрана, во втором – глубину цвета (формат пикселей), а в третьем – частоту обновления экрана.
- Для пользователя актуальны только те видеорежимы, соотношение сторон которых совпадает с соотношением сторон монитора. С другой стороны, для оценки в уме соотношения сторон видеорежима вроде 1792Ч1344 требуются незаурядные математические способности, поэтому было бы логичным предусмотреть типовые фильтры 4:3, 5:4 и 16:9, отбрасывающие видеорежимы с соотношением сторон отличным заданного8В принципе, можно было бы запрашивать у пользователя соотношение сторон монитора, после чего масштабировать изображение исходя из параметров разрешения экрана и соотношения сторон монитора (такой подход применяется, к примеру, в игре Half-Life 2) .
- Не помешало бы на всякий случай предоставить пользователю возможность выбора визуализации в оконном режиме, который иногда оказывается весьма полезным (например, при одновременной работе с несколькими приложениями).
Ну что ж, настало время разработать новую версию диалогового окна, свободную от этих недостатков (рисунок 3.9). Запустите Visual Studio 2005 и создайте приложение Windows Application. Мы начнем с создания класса, инкапсулирующего работу с файлами конфигурации приложения. Наш файл конфигурации будет содержать 7 полей:
Поле | Тип данных | Описание | Значение по умолчанию |
---|---|---|---|
Width | int | размер заднего буфера вдоль оси X | 0 |
Height | int | размер заднего буфера вдоль оси Y | 0 |
Format | SurfaceFormat | формат пикселей заднего буфера | SurfaceFormat.Unknown |
RefreshRate | int | частота обновления экрана | 0 |
FullScreen | bool | работает ли приложение в полноэкранном режиме ( false – нет, true – да) | true |
Init | bool | равен true, если информация о конфигурации приложения была загружена из файла | false |
ShowSettingForm | bool | надо ли отображать при запуске приложения диалоговое окно выбора видеорежима | true |
Так как наш файл конфигурации не будет представлять собой нечего экстравагантного, все операции по созданию класса вполне можно выполнить в дизайнере Visual Studio. Для этого в окне Solution Explorer раскройте узел Properties, и сделайте двойной щелчок левой кнопкой мыши на узле Setting.settings, после чего слева откроется дизайнер файла конфигурации приложения9Дизайнер файла конфигурации приложения доступен также посредством вкладки Settings окна Properties . Добавьте в настройки приложения новые поля согласно таблице 3.3 и рисунок 3.10.
Теперь приступим к созданию диалогового окна настройки параметров приложения. Добавьте приложение в новую форму, разместите на ней элементы управления аналогично рисунку 3.9 и задайте их свойства согласно таблице 3.4.
Класс | Свойство | Значение |
---|---|---|
Form (диалоговое окно) | Name | SettingsForm |
Text | Параметры | |
FormatBorderStyle | FixedDialog | |
MinimizeBox | false | |
MaximizeBox | false | |
CheckBox | Name | inWindowCheckBox |
Text | Визуализировать в окне | |
GroupBox | Text | Видеорежим |
Label | Text | Соотношение сторон |
ComboBox (фильтр отображаемых видеорежимов по соотношению сторон) | Name | aspectRatioComboBox |
DropDownStyle | DropDownList | |
Label | Text | Разрешение |
ComboBox (список разрешений экрана) | Name | resolutionComboBox |
DropDownStyle | DropDownList | |
Label | Text | Глубина цвета: |
ComboBox (список форматов пикселей) | Name | colorDepthComboBox |
DropDownStyle | DropDownList | |
Label | Text | Частота обновления |
ComboBox (список частот обновления экрана) | Name | refreshRateComboBox |
DropDownStyle | DropDownList | |
Button | Name | okButton |
Text | Ok | |
Button | Text | Cancel |
DialogResult | Cancel |
Как видно, диалоговое окно содержит списки соотношений сторон экрана, разрешений, глубины цвета (формата пикселей) и частот обновления экрана. Информация в этих списках должна отображаться в дружелюбной форме, ведь неподготовленный пользователь вряд ли сможет без подсказки понять разницу между форматами Bgr32 и Bgr565. Кроме того, информация в списках должна быть отсортирована по некоторому критерию: например, видеорежимы должны перечислять в порядке увеличения разрешения экрана. Чтобы реализовать эти требования придется создать четыре структуры (по одной на каждый список), инкапсулирующие элементы списков. Для этого необходимо добавить в файл диалогового окна код из листинга 3.11.
// Инкапсулирует элемент списка соотношений сторон public struct AspectItem { // Коэффициент отношения сторон public float aspect; public AspectItem(float aspect) { this.aspect = aspect; } // Проверяет указанный элемент списка разрешений (ResolutionItem) на соответствие текущему // соотношению сторон. В случае равенства метод возвращает true, иначе - false public bool Compare(float aspect) { // Нулевое соотношение сторон является зарезервированным значением ( "любое соотношение // сторон "), поэтому возвращаем true if (this.aspect == 0) return true; // Сравниваем коэффициенты отношения сторон, закладывая небольшой "запас " в один процент. // Дело в том, что некоторые режимы имеют не совсем "академически " правильное соотношение // сторон. Например, соотношение сторон разрешения 1360 x 768 равно 85/48=1.771, в // как 16/9=1.778. if (Math.Abs(this.aspect - aspect) < this.aspect * 0.01f) return true; else return false; } // Возвращает текущее соотношение сторон в удобочитаемом виде public override string ToString() { if (aspect == 0) return "Любое"; if (Compare(4.0f / 3.0f)) return "4 : 3"; if (Compare(5.0f / 4.0f)) return "5 : 4"; if (Compare(16.0f / 9.0f)) return "16 : 9"; return aspect.ToString(); } } // Инкапсулирует элемент списка разрешений экрана public struct ResolutionItem : IComparable<ResolutionItem> { // Разрешение экрана public int width; public int height; public ResolutionItem(int width, int height) { this.width = width; this.height = height; } // Отношение количества пикселей вдоль осей X и Y для текущего разрешения экрана public float Aspect { get { return (float)width / (float)height; } } // Возвращает в удобочитаемом виде текст элемента списка public override string ToString() { return width.ToString() + " x " + height.ToString(); } // Реализация интерфейса IComparable<ResolutionItem>, используемого при сортировке элементов // списка public int CompareTo(ResolutionItem other) { // Сначала сравнивает ширина разрешений if (width > other.width) return 1; if (width < other.width) return -1; // Если ширина одинаковая, сравнивается высота разрешений. В результате разрешения сначала // сортируются по ширине, а затем по высоте. if (height > other.height) return 1; if (height < other.height) return -1; return 0; } } // Инкапсулирует элемент списка форматов пикселей public struct ColorDepthItem : IComparable<ColorDepthItem> { // Формат пикселей public SurfaceFormat value; public ColorDepthItem(SurfaceFormat value) { this.value = value; } // Возвращает строку с описанием формата пикселя public override string ToString() { string str; switch (value) { case SurfaceFormat.Bgr32: str = "32 бита ({0})"; break; case SurfaceFormat.Bgr565: str = "16 бит ({0})"; break; case SurfaceFormat.Rgba1010102: str = "32 бит ({0})"; break; case SurfaceFormat.Bgr555: str = "16 бит {0}"; break; default: str = "{0}"; break; } return string.Format(str, value); } // Реализация интерфейса IComparable<ColorDepthItem>, используемого при сортировке элементов // списка public int CompareTo(ColorDepthItem other) { if (value > other.value) return -1; if (value < other.value) return 1; return 0; } } // Инкапсулирует элемент списка частот обновлений экрана public struct RefreshRateItem : IComparable<RefreshRateItem> { // Частота обновления экрана public int value; public RefreshRateItem(int value) { this.value = value; } // Возвращает строку с частотой обновления экрана public override string ToString() { return value.ToString() + " Гц"; } // Реализация интерфейса IComparable< RefreshRateItem>, используемого при сортировке // элементов списка public int CompareTo(RefreshRateItem other) { if (value > other.value) return 1; if (value < other.value) return -1; return 0; } }Листинг 3.11.