Комбинированные приложения
Данный тип приложений позволяет переключаться между оконным и полноэкранным режимами по ходу работы приложения, которое можно запустить в оконном режиме. Если же оно работает слишком медленно, то пользователь способен переключиться в полноэкранный режим. Оба режима нами были рассмотрены ранее, и вы помните, что для каждого из них установки, определяющие режим работы, необходимо задавать при создании первичной поверхности. Поэтому для комбинированного приложения при переключении режимов следует повторять весь код инициализации заново, одной магической строкой переключение осуществить не удастся. Также при каждом переключении надо повторять все действия деактивации диалога с DirectDraw.
Вот и все тонкости, которые связаны с комбинированными приложениями, можем переходить к иллюстрации - проекту каталога Ех29. Этот пример является моим переложением на Delphi программы из пакета DirectX 7.0 SDK. Работа приложения очень простая: по экрану перемещается одинокий кружок, отскакивающий от границ окна подобно бильярдному шару. Приложение запускается в полноэкранном режиме, но в любой момент работы программы можно переключиться в альтернативный режим, нажав комбинацию клавиш +, о чем информирует пользователя подсказка, располагающаяся в левом верхнем углу экрана (рис. 3.14).
Для упрощения кодирования поведения кружочка окно приложения устанавливаем 640x480 пикселов и не допускаем изменения его размеров:
procedure TfrmDD.FormCanResize(Sender: TObject; var NewWidth,
NewHeight: Integer; var Resize: Boolean);
begin
Resize := False; // Запрещаем любые изменения размеров окна
end;
Вот почему для этого примера лучше задать размеры области экрана большими, чем принятые по умолчанию.
Вводимые глобальные переменные связаны с позицией круга на экране, направлением его движения и параметрами области вывода:
// Круг рисуется средствами GDI, вписанным в квадрат
xl : Integer =0; // Левый верхний угол квадрата
yl : Integer = 0;
х2 : Integer =40; // Правый нижний угол квадрата
у2 : Integer = 40;
xDir : Integer =4; // Текущее приращение координаты X
yDir : Integer =4; // Текущее приращение координаты Y
rcScreen : TRECT; // Позиция окна, используется для оконного режима
rcViewport : TRECT; // Область вывода, 640x480
rcWindow : TRECT; // Структура для хранения позиции окна на экране
flgWindowed : BOOL = False; // Текущий режим работы приложения
Код обработчика создания окна будет вызываться при каждом переключении режима:
procedure TfrmDD.FormCreate(Sender: TObject);
var
hRet : HRESULT;
begin
// Обнуляем все объекты DirectDraw
FDDClipper := nil; // Объект отсечения будет удаляться дважды,
FDDSBack := nil; // можно этого и не выполнять, но для корректности
FDDSPrimary := nil; // первого вызова FormCreate лучше все-таки сделать
FDD := nil;
//В зависимости от режима задаем стиль рамки и видимость курсора
if flgWindowed then begin
BorderStyle := bsSizeable; // Обычный стиль, с областью заголовка
ShowCursor(True);
end
else begin
BorderStyle := bsNone; // Без рамки и области заголовка
ShowCursor(False);
end;
// Создается главный объект DirectDraw
hRet := DirectDrawCreateEx (nil, FDD, IDirectDraw7, nil);
if Failed(hRet) then ErrorOut(hRet, 'DirectDrawCreateEx');
// Инициализация поверхностей
if Failed (InitSurfaces(Handle)) then Close;
FActive := True;
end;
Процедура инициализации поверхностей объединяет в себе оба подхода, изученные нами для полноэкранного и оконного режимов:
function TfrmDD.InitSurfaces(Window : THandle) : HRESULT;
var
hRet : HRESULT;
ddsd : TDDSURFACEDESC2;
ddscaps : TDDSCAPS2;
p : TPoint;
begin
if flgWindowed then begin // Оконный режим
// Получить обычный доступ
hRet := FDD.SetCooperativeLevel(Window, DDSCL_NORMAL);
if Failed(hRet) then begin Result := hRet;
ErrorOut(hRet, 'SetCooperativeLevel');
Exit;
end;
// Получаем размеры области вывода и границы экрана
Windows.GetClientRect(Window, rcViewport);
Windows.GetClientRect(Window, rcScreen);
// Находим позицию клиентской области окна на экране
р.Х := rcScreen.Left;
p.Y := rcScreen.Top;
Windows.ClientToScreen(Window, p);
OffsetRect(rcScreen, p.X, p.Y);
// Создаем первичную поверхность
ZeroMemory(@ddsd, SizeOf(ddsd));
with ddsd do begin
dwSize := SizeOf(ddsd);
dwFlags := DDSD_CAPS;
ddsCaps.dwCaps := DDSCAPS_PRIMARYSURFACE;
end;
hRet := FDD.CreateSurface(ddsd, FDDSPrimary, nil);
if Failed(hRet) then ErrorOut(hRet, 'CreateSurface FAILED');
// Для оконного приложения создаем объект отсечения
hRet := FDD.CreateClipper(0, FDDClipper, nil);
if Failed(hRet) then ErrorOut(hRet, 'CreateClipper FAILED');
// Ассоциируем отсечение с окном приложения
FDDClipper.SetHWnd(0, Window);
FDDSPrimary.SetClipper(FDDClipper) ;
FDDClipper := nil;
// Создаем поверхность заднего буфера, непосредственного вывода with ddsd do begin
dwFlags := DDSD_WIDTH or DDSD_HEIGHT or DDSD_CAPS;
dwWidth := 640;
Читать дальше
Конец ознакомительного отрывка
Купить книгу