Reference = add reference, в висуал студия 2010 не могу найти в вкладке Solution Explorer, Microsoft.Xna.Framework. Его нету. |
Хранитель экрана
4.3. Преобразование приложения в хранитель экрана
Ну что ж, настало время подумать о преобразовании приложения в хранитель экрана. Как известно, любой хранитель экран должен автоматически завершать работу приложения при активности пользователя. Начнем с клавиатуры - нажатие любой клавиши клавиатуры должно немедленно завершать работу приложения (листинг 4.6).
private void FullscreenFormKeyDown(object sender, KeyEventArgs e) { Close () ; }Листинг 4.6.
Аналогичным образом приложение должно завершать работу при нажатии кнопки мыши или перемещении курсора мыши. Но здесь есть одна тонкость. Дело в том, что курсор мыши с высокой чувствительностью может реагировать даже на незначительные воздействия вроде микроколебаний стола из-за проезжающего за окном поезда. Поэтому во избежание непреднамеренных прерываний хранителя экрана мы будет завершать работу приложения только после того, как курсор отодвинется от первоначального положения в момент активации хранителя экрана на расстояние порядка 10 пикселей (листинг 4.7).
public partial class FullscreenForm : Form { // Флаг, устанавливаемый в true после первого вызова обработчика события MouseMove bool isMouseActive = false; // Координаты мыши при первом вызове обработчика события MouseMove System.Drawing.Point mouseLocation; ... // Обработчик события MouseDown, завершающий работу приложения при нажатии кнопки мыши private void FullscreenForm_MouseDown(object sender, MouseEventArgs e) { Close(); } // Обработчик события MouseMove private void FullscreenForm_MouseMove(object sender, MouseEventArgs e) { // Обработчик события MouseMove запускается впервые if (!isMouseActive) { isMouseActive = true; // Запоминаем текущие координаты мыши mouseLocation = e.Location; } else { // Если курсор мыши переместился вдоль оси X или Y от своего первоначального положения // больше, чем на 10 единиц if ((Math.Abs(e.Location.X - mouseLocation.X) > 10) || (Math.Abs(e.Location.Y - mouseLocation.Y) > 10)) { // Завершаем работу приложения Close(); } } } }Листинг 4.7.
В процессе работы хранителя экрана некоторое приложение может вывести на экран диалоговое окно с важной информацией (например, Internet Explorer по окончанию загрузки файла). При этом окно хранителя экран теряет фокус, который переходит к новому диалоговому окну. Хранитель экрана, поверх которого отображается диалоговое окно, будет выглядеть, мягко говоря, несколько странно, поэтому в качестве одного из критериев завершения работы хранителя экрана логично использовать потерю фокуса формой (листинг 4.8).
// Обработчик события Deactivate полноэкранной формы хранителя экран, завершающий работу // приложения при потере формой фокуса private void FullscreenFormDeactivate(object sender, EventArgs e) { Close () ; }Листинг 4.8.
Курсор мыши является чужеродным элементом для хранителя экрана, поэтому его необходимо скрыть посредством метода Hide класса Cursor:
private void FullscreenFormLoad(object sender, EventArgs e) { Cursor.Hide(); }Листинг 4.9.
Следующее отличие хранителя экрана от обычного приложения состоит в том, что он должен активироваться только при запуске приложения с ключом /s. Соответственно, мы должны добавить в метод Main статического класса Program анализ параметров командной строки (листинг 4.10).
Примечание
Чтобы Visual Studio всегда запускала приложение с ключом /s, укажите этот параметр в поле Command line arguments вкладки Debug свойств проекта.
static class Program { [STAThread] static void Main() { // Получаем массив параметров командной строки string[] args = Environment.GetCommandLineArgs(); // Если первый параметр равен "/S" if ((args.Length == 2) && (args[1].ToUpper() == "/S")) { // Отображаем форму приложения с хранителем экрана Application.Run(new FullscreenForm()); return; } // Если параметр не является "/S", нечего не делаем return; } }Листинг 4.10.
В заключении необходимо присвоить файлу хранителя экрана расширение .scr. Переименовывать файл вручную после каждой компиляции приложения довольно утомительно, поэтому мы автоматизируем этот процесс. Откройте в свойствах проекта вкладку Build Events и введите в поле Post-build event command line следующую команду (рисунок 4.3): copy "$(TargetFileName)" "*.scr".
Теперь после каждой компиляции приложения будет вызываться команда copy, создающая копию exe-файла приложения с расширением .scr. Обратите внимание на получение имени exe-файла приложения посредством встроенного макроса $(TargetFileName) , благодаря чему команда copy не привязана к фиксированному exe -файлу.
Для проверки работоспособности хранителя экрана откройте каталог с .scr -файлом в файловом менеджере и вызовите его контекстное меню (рисунок 4.4). Как видно, контекстное меню любого исполняемого файла хранителя экрана содержит три пункта:
- Test - запускает хранитель экрана на выполнение с ключом /s.
- Configure (Настроить) - открывает окно конфигурации хранителя экрана.
- Install (Установить) - открывает вкладку Screen Saver диалогового окна Display Properties и выбирает данный хранитель экрана в качестве текущего.
Немного проигравшись с нашим хранителем экрана, вы заметите ряд недоделок. Например, при попытке открыть окно конфигурации ровным счетом нечего не происходит, а в окне предварительного просмотра (маленький "дисплейчик") диалогового окна Display Properties просто выводится изображение по умолчанию. А на компьютере с несколькими мониторами выяснится, что наш хранитель экрана активируется только основном мониторе. Что ж, работы нам предстоит еще много.
4.4. Поддержка нескольких мониторов
В настоящее время поддержка видеокартами двух мониторов уже стала нормой, поэтому любой уважающий себя разработчик должен позаботиться о корректном функционировании приложения на компьютере с несколькими мониторами. В частности, хранитель экрана должен показывать заставку на всех мониторах. Наиболее простое решение - просто отображать на всех мониторах одно и то же изображение. Так как наш хранитель экрана представляет собой форму, развернутую на весь экран, в случае нескольких мониторов мы можем просто создать несколько экземпляров формы - по одному на каждый монитор.
Начнем с метода Main. Информация об экранных координатах всех мониторов системы храниться в коллекции AllScreens класса Screen. Соответственно приложение должно просто перебрать элементы этой коллекции и использовать полученную информацию при создании форм (листинг 4.11).
static void Main() { string[] args = Environment.GetCommandLineArgs(); if ((args.Length == 2) && (args[1].ToUpper() == "/S")) { // Перебираем все мониторы foreach (Screen screen in Screen.AllScreens) { // Создаем форму размеров во весь монитор FullscreenForm form = new FullscreenForm(screen); // Отображаем форму form. Show () ; } // Запускаем цикл обработки сообщений. Изображение форм будет обновляться посредством // обработчиков события Idle, регистрируемых конструктором формы. Application.Run(); return; } return; }Листинг 4.11.
Конструктор формы, разумеется, так же придется подправить, ведь теперь он будет принимать информацию об экране, на котором будет отображаться форма. Вступать же в силу данный параметр будет после конструирования формы в обработчике события Load (листинг 4.12).
Screen screen = null; public FullscreenForm(Screen screen) { this.screen = screen; InitializeComponent(); } private void FullscreenFormLoad(object sender, EventArgs e) { // Форма должна занимать весь экран // Внимание! Свойство Bounds не оказывает влияния, если форма развернута на весь экран // (т.е. когда свойство WindowsState равно Maximized) Bounds = screen.Bounds; }Листинг 4.12.
Наконец необходимо определиться с завершением работы. До сих пор все наши приложения содержали лишь одно главное окно, закрытие которого методом Close приводило к завершению работы всего приложения. Теперь же окон несколько, поэтому вызов метода Close закроет лишь единственное окно. Поэтому мы будет завершать работу приложения путем вызова метода Application.Exit. Правда у этого подхода есть один подводный камень - при завершении работы методом Application.Exit не вызываются обработчики события FormClosed. Поэтому код из обработчиков необходимо перенести в обработчики события FormClosing, корректно вызываемых методом Application.Exit. Другой нюанс связан с обработчиком события Deactivate: так мы создаем несколько форм, в процессе создания они будут неминуемо получать-терять фокус (ведь в каждый момент времени только одна форма может иметь фокус). Поэтому во избежание досрочного завершения хранителя экра на в процессе инициализации приложения необходимо игнорировать событие Deactivate. Основные фрагменты обновленных обработчиков событий формы приведены в листинге 4.13.
// Ресурсы теперь освобождаются в обработчике события FormClosing private void FullscreenFormFormClosing(object sender, FormClosingEventArgs e) { if (firework != null) { firework.Dispose() ; firework = null; } } private void FullscreenFormDeactivate(object sender, EventArgs e) { // Пока в приложение не запущен цикл обработки сообщений, игнорируем событие Deactivate if (Application.MessageLoop) Application.Exit(); } private void FullscreenForm_MouseDown(object sender, MouseEventArgs e) { // Обратите внимание на завершение приложения посредством метода Application.Exit (вместо // Form.Close) Application.Exit(); } ...Листинг 4.13.
Готовое приложение можно найти в example.zip в каталоге Examples\Ch04\Ex04.