Delphi игнорирует флаг CS_OWNDC при создании компонента TFrame, впоследствии происходит сбой wglMakeCurrent - PullRequest
1 голос
/ 31 января 2011

Я пытаюсь собрать некоторые компоненты для использования OpenGL в RAD Studio 2009. Я хочу иметь несколько контекстов рендеринга.

Моя идея состоит в том, чтобы иметь что-то вроде «основного компонента OpenGL», называемого GLMaster. Это потомок TFrame, поэтому он должен предоставить мне DC. Также есть компонент для GLMonitor, действующий как камера.

Я создаю OpenGL RC в переопределенном GLMaster.Loaded внутри «если нет (csDesigning в ComponentState) затем» -клаузе. DC для этого я не храню, в справке RAD Studio указано, что вы не должны: «TWinControl.Handle Не обращайтесь к свойству Handle во время создания компонента или потоковой передачи. Базовое окно не существует до тех пор, пока не будет использована ссылка на свойство Handle. Когда это происходит, метод HandleNeeded вызывается автоматически. " Я обрабатываю это с помощью указателей на функции в компонентах, используя GLMaster, указывающий на GLMaster.GetCurrentDC (возвращает HDC).

Во время уничтожения GLMonitor хочет очистить некоторые текстуры рендеринга и другие ресурсы OpenGL. При получении DC для вызова wglMakeActive следует указатель функции, и выполнение переходит к GLMaster.GetCurrentDC. Pointer (Self) говорит мне, что это тот же GLMaster, в котором мы создали «master RC» во время потоковой передачи компонентов. Свойство [GLMaster.] Handle теперь недействительно! Однако если я освобожу GLMonitor в OnClose формы приложения (используя просто GLMonitor_1.Free;), то Handle внутри GLMaster.GetCurrentDC действителен, и все работает.

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

Почему VCL / Delphi тихо предоставляет вновь созданным компонентам другие дескрипторы и тем самым косвенно другие DC, даже если я предоставляю флаг OWNDC? Есть ли способ получить «ВСЕ компоненты теперь загружены, а их свойства считываются из файла .dfm и» -message, чтобы я мог запустить GLMaster.InitEverything внутри компонента?

Сейчас я думаю, что самый быстрый путь вперед - это поместить это InitEverything в обработчик OnShow основной формы. А затем вызов GLMatser.CleanAll в OnClose основной формы. Но я не хочу никакого кода в форме, поэтому я создал компоненты в первую очередь!

P.S. Не то чтобы я думал, что это имеет значение для этой конкретной проблемы, но я использую профиль ядра OpenGL 3.2.

Ответы [ 3 ]

3 голосов
/ 31 января 2011

Я отвечаю на вопрос «Почему VCL / Delphi тихо обеспечивает вновь созданные компоненты другими дескрипторами».

Почему дескриптор окна элемента управления может измениться во время выполнения

Ваш TFrame (потомок TWinControl) находится на другом TWinControl, скажем, TForm. Родительский контейнер предоставляет оболочки свойств для многих настроек, что позволяет нам легко вносить изменения; Некоторые из этих изменений не могут быть реализованы без повторного создания дескриптора windhow. Вы можете получить длинный список свойств, которые вызывают это, выполнив поиск RecreateWnd в Forms.pas, Controls.pas и т. Д.

Примеры свойств, которые вызывают RecreateWnd для реализации изменения во время выполнения:

  • TScollBox.BorderStyle
  • TForm.BorderIcons (для детей с MDI)

Когда родитель вашего TFrame должен изменить дескриптор окна, ваш TFrame также должен будет изменить дескриптор окна. Ваш Delphi Control, независимо от происхождения, должен справиться с этим, и другие элементы управления имеют худший результат: элементы управления, реализованные в виде оберток вокруг элементов управления Windows, должны сохранять состояние и перезагружать состояние (TEdit, TComboBox, ...)

Что я думаю, что происходит

Во время потоковой передачи (загрузки формы) некоторые элементы управления выполняют что-то, что требует дескриптор окна перед завершением загрузки. Скорее всего, ваш собственный код! После завершения загрузки формы, возможно, потребуется заново создать ее дескриптор, что, в свою очередь, приводит к изменению дескриптора вашего фрейма.

Что вы можете переопределить

Учитывая то, как работает VCL, вам нужно быть готовым к изменению дескриптора окна. Вам нужно выполнить поиск в Controls.pas слов Handle , HDC . Если ваш элемент управления настолько тесно связан с его дескриптором окна и HDC, в ваших же интересах прочитать эти материалы.

Посмотрите на эти процедуры. Может быть, вы можете найти лучшее место для ловли:

  • CreateHandle
  • CreateWnd
  • DestroyHandle
  • DestroyWnd
  • GetDeviceContext
1 голос
/ 31 января 2011

Если заголовком является вопрос, то нет, Delphi не игнорирует CS_OWNDC при создании фрейма. Только что протестировано с помощью приведенной ниже процедуры с рамкой на форме. Когда флаг не указан, линия снова и снова рисуется сама по себе, в результате получается линия от (0,0) до (10,10). Когда DC принадлежит, линия расширяется от (0,0) до (50,50), нет необходимости говорить, но извлеченный DC всегда одинаков.

procedure TFrame2.WmPaint(var Msg: TWMPaint);
var
  i: Integer;
  DC: HDC;
  Pt: TPoint;
begin
  inherited;
  for i := 1 to 5 do begin
    DC := GetDC(Handle);
    GetCurrentPositionEx(DC, @Pt);
    LineTo(DC, Pt.X + 10, Pt.Y + 10);
    ReleaseDC(Handle, DC);
  end;
end;
0 голосов
/ 31 января 2011

если ваш вопрос такой:

ВСЕ компоненты теперь загружены, и их свойства считываются из файла .dfm и

Ответ:

Да , просто переопределите метод Loaded вашего компонента. Он вызывается, когда все ссылки действительны (после окончания чтения dfm).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...