Как получить и работать со свойством FONT АНОНИМНОГО КОНТРОЛЯ?

В Delphi 10.4 в приложении VCL с помощью обработчика событий OnMessage компонента TApplicationEvents я увеличиваю размер шрифта элемента управления, щелкнутого правой кнопкой мыши:

procedure TformMain.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
var
  ThisControl: TControl;
begin
  if (Msg.Message = WM_RBUTTONDOWN) then
  begin
    ThisControl := FindDragTarget(Mouse.CursorPos, True);
    CodeSite.Send('TformMain.ApplicationEvents1Message: RIGHTCLICK!', ThisControl.Name);
    if ThisControl is TLabel then
      TLabel(ThisControl).Font.Size := TLabel(ThisControl).Font.Size + 1
    else if ThisControl is TCheckBox then
      TCheckBox(ThisControl).Font.Size := TCheckBox(ThisControl).Font.Size + 1;
    // ETC. ETC. ETC.! :-(
  end;
end;

Это чрезвычайно НЕЭФФЕКТИВНЫЙ способ заставить это работать для всех типов элементов управления, потому что мне пришлось бы перечислять все существующие типы элементов управления, поскольку TControl не имеет свойства TFont.

Лучшим способом было бы получить свойство TFont элемента управления, не спрашивая ТИП, а затем TYPECAST элемента управления.

Но как?


person user1580348    schedule 11.08.2020    source источник


Ответы (1)


Если вы повторно объявите тип, вы получите доступ к защищенным свойствам класса. В настоящее время вы делаете это с классом интерпозера, но я все еще привык к старым способам. Возможно, придется добавить проверку, если окажется, что тот или иной элемент управления бомбит, когда вы что-то делаете со шрифтом. Это всегда работало для меня до сих пор.

type
  TCrackControl = class(TControl);

procedure TformMain.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
var
  ThisControl: TCrackControl;
begin
  if (Msg.Message = WM_RBUTTONDOWN) then
  begin
    ThisControl := TCrackControl(FindDragTarget(Mouse.CursorPos, True));
    CodeSite.Send('TformMain.ApplicationEvents1Message: RIGHTCLICK!', ThisControl.Name);
    If assigned(ThisControl.Font) then
    ThisControl.Font.Size := ThisControl.Font.Size + 1;
   
  end;
end;
person Renate Schaaf    schedule 11.08.2020
comment
Не лучше ли написать: if System.TypInfo.IsPublishedProp(ThisControl, 'Font') then ThisControl.Font.Size := ThisControl.Font.Size + 1; - person user1580348; 11.08.2020
comment
Нет, поскольку .Font из TCrackControl всегда публикуется - в этом весь смысл определения этого класса и приведения к нему TControl. - person AmigoJack; 11.08.2020
comment
@AmigoJack: я думаю, что вы ошибаетесь. Этот метод не приводит к публикации каких-либо свойств. Единственное, что он делает, это делает защищенные члены доступными, потому что TCrackControl объявлен в том же модуле. (Поэтому strict protected членов нельзя получить таким образом.) - person Andreas Rejbrand; 11.08.2020
comment
Ну, я мог бы объявить ДВЕ управляющие переменные, одну типа TControl и одну типа TCrackControl. Тогда код будет таким: if System.TypInfo.IsPublishedProp(ThisNoCrackControl, 'Font') then ThisCrackControl.Font.Size := ThisCrackControl.Font.Size + 1; - person user1580348; 11.08.2020
comment
(В любом случае приведение к TCrackControl отсутствует в A.) - person Andreas Rejbrand; 11.08.2020
comment
@AndreasRejbrand Какой именно актерский состав вы имеете в виду? - person user1580348; 11.08.2020
comment
Я полагаю, вы имеете в виду: ThisCrackControl := TCrackControl(FindDragTarget(Mouse.CursorPos, True)); В этом случае я мог бы использовать ДВЕ управляющие переменные. - person user1580348; 11.08.2020
comment
Нет, я имел в виду то, что написал! :) Код в этом A не будет компилироваться, пока не будет добавлено приведение TCrackControl. - person Andreas Rejbrand; 11.08.2020
comment
@AndreasRejbrand Тогда как бы вы реализовали необходимую ПРОВЕРКУ, предложенную @RenateSchaaf? Потому что код ответа получит AV, если элемент управления не имеет свойства Font! - person user1580348; 11.08.2020
comment
@AndreasRejbrand Я живу в прошлом, где strict protected не существует (пока). Хотя TControl определяет .Font и скрывается там до тех пор, пока хорошо известные классы элементов управления (например, TCheckBox) не опубликуют его, я знаю, что есть элементы управления, которые никогда не публикуют его (например, TSplitter). Если это также может произойти в событии ОП, тогда возникает вопрос: будет ли это больно? - person AmigoJack; 11.08.2020
comment
@ user1580348: я не обращался к этой части. Мое единственное намерение состояло в том, чтобы отметить, что код, приведенный в этом ответе, даже не компилируется, если не будут внесены упомянутые мной изменения. Наверняка Ренате Шааф только забыла об этом актерском составе. (Upd: Да, теперь это было отредактировано.) // Каждый TControl имеет свойство Font, но, конечно, это может быть и nil. Таким образом, вы можете сделать if Assigned(ThisControl.Font) для проверки. // Но даже если у элемента управления есть шрифт и он защищен, ему может не понравиться, что вы вмешиваетесь в него. Так что ваше первоначальное предложение использовать IsPublishedProp звучит хорошо для меня. - person Andreas Rejbrand; 11.08.2020
comment
Кроме того, обратите внимание, что заявление No, since .Font of TCrackControl is always published, сделанное другим пользователем выше, неверно. - person Andreas Rejbrand; 11.08.2020
comment
@RenateSchaaf Не могли бы вы добавить в свой ответ проверку, предложенную @AndreasRejbrand: if Assigned(ThisControl.Font)? - person user1580348; 11.08.2020
comment
@AndreasRejbrand Спасибо, я исправил. Я думал, что он скомпилируется без приведения типа. Я также добавил проверку для назначенного, надеюсь, что это все, что ему нужно. - person Renate Schaaf; 11.08.2020
comment
На самом деле шрифт TControl всегда назначается, см. VCL.Controls.TControl.Create. - person Renate Schaaf; 11.08.2020
comment
@RenateSchaaf: Да, наверное. Тем не менее, я бы в любом случае оставил тест Assigned. По сути, это бесплатно, и кто знает, может быть, будущая версия VCL будет вести себя по-другому, может быть, FFont позже будет установлено на nil и т. д. - person Andreas Rejbrand; 11.08.2020
comment
@AndreasRejbrand этого никогда не произойдет. VCL слишком зрел, чтобы вносить такие фундаментальные изменения в свое поведение. - person Remy Lebeau; 11.08.2020