Опубликован: 28.04.2009 | Доступ: свободный | Студентов: 1840 / 107 | Оценка: 4.36 / 4.40 | Длительность: 16:40:00
Специальности: Программист
Лекция 4:

Хранитель экрана

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 -файлу.

 Вкладка Build Events

увеличить изображение
Рис. 4.3. Вкладка Build Events

Для проверки работоспособности хранителя экрана откройте каталог с .scr -файлом в файловом менеджере и вызовите его контекстное меню (рисунок 4.4). Как видно, контекстное меню любого исполняемого файла хранителя экрана содержит три пункта:

  1. Test - запускает хранитель экрана на выполнение с ключом /s.
  2. Configure (Настроить) - открывает окно конфигурации хранителя экрана.
  3. Install (Установить) - открывает вкладку Screen Saver диалогового окна Display Properties и выбирает данный хранитель экрана в качестве текущего.

Немного проигравшись с нашим хранителем экрана, вы заметите ряд недоделок. Например, при попытке открыть окно конфигурации ровным счетом нечего не происходит, а в окне предварительного просмотра (маленький "дисплейчик") диалогового окна Display Properties просто выводится изображение по умолчанию. А на компьютере с несколькими мониторами выяснится, что наш хранитель экрана активируется только основном мониторе. Что ж, работы нам предстоит еще много.

 Контекстное меню исполняемого файла хранителя экрана

увеличить изображение
Рис. 4.4. Контекстное меню исполняемого файла хранителя экрана

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.

Андрей Леонов
Андрей Леонов

Reference = add reference, в висуал студия 2010 не могу найти в вкладке Solution Explorer, Microsoft.Xna.Framework. Его нету.