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

