Советы по Delphi

         

Как запустить приложение в полноэкранном режиме?


Запуск приложения в полноэкранном режиме означает, что окно приложения полностью занимает рабочий стол. Это бывает необходимо для обеспечения поддержки функции акселератора видеокарты, которая может ускорить работу только полной области экрана, но не только, к примеру, если вам необходимо сделать только вашу программу видимой для пользователя. Кстати: Полноэкранный запуск в общих чертах имеет отношение не только к OpenGL, DirectX и 3D. Строго говоря полноэкранный режим требует только установки флага состояния окна wsMaximize, и все.

Но есть другой вопрос, подразумеваемый требованиями для полноэкранных приложений. Это наличие возможности выбора пользователем специфического разрешения экрана и глубины цвета или возможность запуска приложения в фиксированном разрешении. Последнее важно в каждом конкретном случае, поскольку не все видеокарты поддерживают все разрешения и часто игра или другое 3D-приложение хотят работать в другом разрешении (в основном на более низком), чем пользователь использует в каждодневной работе.

Так что полностью вопрос читается так: как запустить полноэкранное приложение в специфичном разрешении экрана и глубине цвета (без перезагрузки)? Ключевым пунктом является функция ChangeDisplaySettings. В зависимости от видеодрайвера, вы можете динамически установить один из множества режимов, не перегружая компьютер:

    function SetFullscreenMode(ModeIndex: Integer) : Boolean;
// изменение видеорежима, задаваемого 'ModeIndex'
var DeviceMode : TDevMode;
begin
with
DeviceMode do begin dmSize:=SizeOf(DeviceMode); dmBitsPerPel:=VideoModes[ModeIndex].ColorDepth;

dmPelsWidth:=VideoModes[ModeIndex].Width; dmPelsHeight:=VideoModes[ModeIndex].Height; dmFields:=DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT; // при неудачной смене режима переходим в режим текущего разрешения Result:=ChangeDisplaySettings(DeviceMode,CDS_FULLSCREEN) = DISP_CHANGE_SUCCESSFUL; if Result then ScreenModeChanged:=True; if ModeIndex = 0 then ScreenModeChanged:=False; end; end;

Если вы обратили внимание, в этом примере присутствует глобальная переменная VideoModes. Ее наличие обусловлено необходимостью перечисления всех доступных режимов, которые могут быть установлены динамически и загружены в структуру, подобную VideoModes для гарантии использования только описанных режимов:

    const MaxVideoModes = 200; // это не очень актуально
type TVideoMode = record
Width, Height, ColorDepth  : Word; Description : String[20]; end;
var VideoModes        : array[0..MaxVideoModes] of TVideoMode;
NumberVideomodes  : Integer = 1; // 1, поскольку есть режим по умолчанию

Как вы видите, это делает наш пример более функциональным для использования. При необходимомости, вы можете заменить в вышеуказанной функции VideoModes на фиксированные значения (скажем, на 640, 480, 16). Перечисление всех видеорежимов осуществляется при помощи EnumDisplaySettings:

    procedure ReadVideoModes;
var I, ModeNumber : Integer;
done          : Boolean; DeviceMode    : TDevMode; DeskDC        : HDC;
begin
// создание режима "по умолчанию" with VideoModes[0] do try DeskDC:=GetDC(0); ColorDepth:=GetDeviceCaps(DeskDC,BITSPIXEL); Width:=Screen.Width; Height:=Screen.Height; Description:='default'; finally ReleaseDC(0,DeskDC); end;
// перечисляем все доступные видеорежимы ModeNumber:=0; done:=False; repeat done:=not EnumDisplaySettings(nil,ModeNumber,DeviceMode); TryToAddToList(DeviceMode); Inc(ModeNumber); until (done or (NumberVideomodes >= MaxVideoModes));
// режимы низкого разрешения не всегда перечислимы, о них запрашивают явно with DeviceMode do begin dmBitsPerPel:=8; dmPelsWidth:=42; dmPelsHeight:=37; dmFields:=DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT; // тест видеодрайвера: убедимся, что он справится со всеми видеорежимами if ChangeDisplaySettings(DeviceMode,CDS_TEST or CDS_FULLSCREEN) <> DISP_CHANGE_SUCCESSFUL then begin I:=0; while (I < NumberLowResModes-1) and (NumberVideoModes < MaxVideoModes) do begin dmSize:=Sizeof(DeviceMode); dmBitsPerPel:=LowResModes[I].ColorDepth; dmPelsWidth:=LowResModes[I].Width; dmPelsHeight:=LowResModes[I].Height; dmFields:=DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT; TryToAddToList(DeviceMode); Inc(I); end; end; end; end;

Я думаю эта функция не тяжела для понимания. Есть две части, которые нужно рассмотреть. Сначала - стандартный путь перечисления видеорежимов. Потом проверям, что все режимы низкого разрешения также протестированы. Это все-таки потребует список режимов низкого разрешения:

    type TLowResMode = record
Width, Height, ColorDepth  : Word; end;
const NumberLowResModes = 60;
LowResModes       : array[0..NumberLowResModes-1] of TLowResMode = ((Width:320;Height:200;ColorDepth: 8),(Width:320;Height:200;ColorDepth:15), (Width:320;Height:200;ColorDepth:16),(Width:320;Height:200;ColorDepth:24), (Width:320;Height:200;ColorDepth:32),(Width:320;Height:240;ColorDepth: 8), (Width:320;Height:240;ColorDepth:15),(Width:320;Height:240;ColorDepth:16), (Width:320;Height:240;ColorDepth:24),(Width:320;Height:240;ColorDepth:32), (Width:320;Height:350;ColorDepth: 8),(Width:320;Height:350;ColorDepth:15), (Width:320;Height:350;ColorDepth:16),(Width:320;Height:350;ColorDepth:24), (Width:320;Height:350;ColorDepth:32),(Width:320;Height:400;ColorDepth: 8), (Width:320;Height:400;ColorDepth:15),(Width:320;Height:400;ColorDepth:16), (Width:320;Height:400;ColorDepth:24),(Width:320;Height:400;ColorDepth:32), (Width:320;Height:480;ColorDepth: 8),(Width:320;Height:480;ColorDepth:15), (Width:320;Height:480;ColorDepth:16),(Width:320;Height:480;ColorDepth:24), (Width:320;Height:480;ColorDepth:32),(Width:360;Height:200;ColorDepth: 8), (Width:360;Height:200;ColorDepth:15),(Width:360;Height:200;ColorDepth:16), (Width:360;Height:200;ColorDepth:24),(Width:360;Height:200;ColorDepth:32), (Width:360;Height:240;ColorDepth: 8),(Width:360;Height:240;ColorDepth:15), (Width:360;Height:240;ColorDepth:16),(Width:360;Height:240;ColorDepth:24), (Width:360;Height:240;ColorDepth:32),(Width:360;Height:350;ColorDepth: 8), (Width:360;Height:350;ColorDepth:15),(Width:360;Height:350;ColorDepth:16), (Width:360;Height:350;ColorDepth:24),(Width:360;Height:350;ColorDepth:32), (Width:360;Height:400;ColorDepth: 8),(Width:360;Height:400;ColorDepth:15), (Width:360;Height:400;ColorDepth:16),(Width:360;Height:400;ColorDepth:24), (Width:360;Height:400;ColorDepth:32),(Width:360;Height:480;ColorDepth: 8), (Width:360;Height:480;ColorDepth:15),(Width:360;Height:480;ColorDepth:16), (Width:360;Height:480;ColorDepth:24),(Width:360;Height:480;ColorDepth:32), (Width:400;Height:300;ColorDepth: 8),(Width:400;Height:300;ColorDepth:15), (Width:400;Height:300;ColorDepth:16),(Width:400;Height:300;ColorDepth:24), (Width:400;Height:300;ColorDepth:32),(Width:512;Height:384;ColorDepth: 8), (Width:512;Height:384;ColorDepth:15),(Width:512;Height:384;ColorDepth:16), (Width:512;Height:384;ColorDepth:24),(Width:512;Height:384;ColorDepth:32));

И остается функция TryToAddToList:

    procedure TryToAddToList(DeviceMode: TDevMode);
// Добавление видеорежима к списку, это это не дубликат и режим действительно может быть установлен.
var I : Integer;
begin
// Смотрим на предмет дублирования видеорежима (такое может быть из-за показателя // частоты смены кадров или из-за того, что мы явно пробуем все режимы низкого разрешения) for I:=1 to NumberVideomodes-1 do with DeviceMode do if ((dmBitsPerPel = VideoModes[I].ColorDepth) and (dmPelsWidth  = VideoModes[I].Width)      and (dmPelsHeight = VideoModes[I].Height))    then Exit; // повтор видеорежима (дубликат)
// устанавливаем тестируемый режим (на самом деле мы не устанавливаем данный режим, а хотим получить сообщение о его поддержке видеокартой). if ChangeDisplaySettings(DeviceMode,CDS_TEST or CDS_FULLSCREEN) <> DISP_CHANGE_SUCCESSFUL then Exit;
// если это новый, поддерживаемый режим, то добавляем его к списку with DeviceMode do begin VideoModes[NumberVideomodes].ColorDepth:=dmBitsPerPel; VideoModes[NumberVideomodes].Width:=dmPelsWidth; VideoModes[NumberVideomodes].Height:=dmPelsHeight; VideoModes[NumberVideomodes].Description:=Format('%d x %d, %d bpp',[dmPelsWidth,dmPelsHeight,dmBitsPerPel]); end; Inc(NumberVideomodes); end;

Для завершения реализации вашего проекта необходима функция, восстанавливающий видеорежим по умолчанию при завершении работы вашего приложения:

    procedure RestoreDefaultMode;
// восстанавливаем видеорежим по умолчанию
var T : TDevMode absolute 0; // маленькая хитрость: создаем указатель на ноль
begin
// Так как первый параметр является переменной, мы не можем использовать ноль // непосредственно. Взамен мы используем переменную с абсолютным адресом нуля. ChangeDisplaySettings(T,CDS_FULLSCREEN); end;

[000107]



Содержание раздела