Ошибка при установке TDateTimePicker.Font.Style курсивом в Delphi 5 - PullRequest
1 голос
/ 24 августа 2009

Можно ли установить шрифт TDateTimePicker курсивом? Я делаю это в этом коде

var
  DatEdit : TDateTimePicker;
begin
  //I know Canvas is a stupid name for TPanel
  DatEdit:=TDateTimePicker.Create(Canvas);

  DatEdit.OnEnter := CtrlInputProc;
  DatEdit.OnExit := CtrlExitProc;
  DatEdit.Enabled := false;
  DatEdit.Font.Style := DatEdit.Font.Style + [fsItalic]; //this line creates an exception
  DatEdit.Parent := Canvas;

end;

И каждый раз, когда код выполняет последнюю строку, возникает исключение EInvalidOperation с сообщением:

„Control” has no parent window.

Это функция Delphi 5, или я что-то не так делаю?

1 Ответ

7 голосов
/ 24 августа 2009

Да, вы делаете что-то не так. :)

Некоторые аспекты оконного элемента управления требуют, чтобы элемент управления был помещен в его окно контейнера. Обычно это отражает некоторые требования самого базового класса окна (не класса VCL, а объекта окна MS Windows, представляющего элемент управления).

В этом случае просто переместите присваивание свойства Parent так, чтобы оно происходило ДО того, как вы попытаетесь изменить Font.Style:

  DatEdit.OnEnter := CtrlInputProc;
  DatEdit.OnExit := CtrlExitProc;
  DatEdit.Enabled := false;
  DatEdit.Parent := Canvas;
  DatEdit.Font.Style := DatEdit.Font.Style + [fsItalic];

Я не знаю, можно ли таким образом успешно установить шрифт курсивом или нет, но это должно как минимум устранить ваше исключение.

ОБНОВЛЕНИЕ: Я подтвердил, что шрифт может быть выделен курсивом таким образом, если вы сначала установили родительский элемент управления. (Я использовал Delphi 2009, но я был бы удивлен, если бы он не работал в Delphi 5)

К вашему сведению: я бы настоятельно рекомендовал бы другой выбор имени для этого элемента управления панели "Canvas".

Приложение: -------

Это вызов InvalidateRect () в обработчике сообщений CMFontChanged () , который требует дескриптор окна (который, в свою очередь, требует, чтобы элемент управления был родительским).

Если вам абсолютно необходимо установить Parent после изменения Font , вы можете получить свой собственный класс управления из TDateTimePicker и реализуйте ответ на сообщение CMFontChanged () , которое подавляет унаследованное поведение, если элемент управления не является родительским:

type
  TMyDateTimePicker = class(TDateTimePicker)
  protected
    procedure CMFontchanged(var Message: TMessage); message CM_FONTCHANGED;
  end;


  procedure TMyDateTimePicker.CMFontchanged(var Message: TMessage);

    procedure AdjustHeight;
    var
      DC: HDC;
      SaveFont: HFont;
      SysMetrics, Metrics: TTextMetric;
    begin
      DC := GetDC(0);
      try
        GetTextMetrics(DC, SysMetrics);
        SaveFont := SelectObject(DC, Font.Handle);
        GetTextMetrics(DC, Metrics);
        SelectObject(DC, SaveFont);
      finally
        ReleaseDC(0, DC);
      end;
      Height := Metrics.tmHeight + (GetSystemMetrics(SM_CYBORDER) * 8);
    end;

  begin
    if HasParent then
      inherited
    else
      AdjustHeight;
  end;

Обратите внимание, что процедура AdjustHeight () воспроизводится из частного метода TDateTimePicker . Если вы изменяете только Font.Style , вам может не понадобиться воспроизводить этот код, и вы можете удалить его и вызвать его, но если вы измените другие свойства Font , тогда это следует убедиться, что размер элемента управления правильный.

Когда вы вызываете унаследованный , вызывается закрытый механизм AdjustHeight () , поэтому в этом случае нет необходимости вызывать локальную копию этой процедуры.

...