скрыть

скрыть

  Форум  

Delphi FAQ - Часто задаваемые вопросы

| Базы данных | Графика и Игры | Интернет и Сети | Компоненты и Классы | Мультимедиа |
| ОС и Железо | Программа и Интерфейс | Рабочий стол | Синтаксис | Технологии | Файловая система |



Google  
 

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



Запуск приложения в полноэкранном режиме означает, что окно приложения полностью занимает рабочий стол. Это бывает необходимо для обеспечения поддержки функции акселератора видеокарты, которая может ускорить работу только полной области экрана, но не только, к примеру, если вам необходимо сделать только вашу программу видимой для пользователя. Кстати: Полноэкранный запуск в общих чертах имеет отношение не только к 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;






Copyright © 2004-2016 "Delphi Sources". Delphi World FAQ




Группа ВКонтакте   Ссылка на Twitter   Группа на Facebook