Ошибка при установке TDateTimePicker.Font.Style курсивом в Delphi 5
Можно ли установить шрифт 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 ответ
Да, вы делаете что-то не так.:)
Некоторые аспекты элемента управления на основе окна требуют, чтобы элемент управления был помещен в его окно контейнера. Обычно это отражает некоторые требования самого базового класса окна (не класса 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 после изменения шрифта, вы можете получить свой собственный класс элемента управления из 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, вам может не понадобиться воспроизводить этот код, и вы можете удалить его и вызов к нему, но если вы измените другие свойства шрифта, то это должно обеспечить правильный размер элемента управления.
При вызове унаследованного вызывается закрытый механизм AdjustHeight(), поэтому в этом случае нет необходимости вызывать локальную копию этой процедуры.