|
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.

