Как использовать аргумент в приведении с помощью Delphi

Asked
Viewd694

2

Как это сделать в Delphi:

 procedure ToggleVisibility(ControlClass : TControlClass);
var
  i : integer;
begin
  for i := 0 to ComponentCount - 1 do
    if Components[i] is ControlClass then
      ControlClass(Components[i]).Visible := not Control(Components[i]).Visible;
end;
 

Компилятор не допускает приведение в этом случае.Есть идеи?

Я использую Delphi 2007.

  • почему вы вызываете параметр ComponentClass, но он имеет тип TControlClass?Не следует ли вместо этого называть параметр ControlClass?

    Jeroen Wiert Pluimers12 ноября 2009, 14:57
  • Возможный дубликат http://stackoverflow.com/questions/1083087/cast-tobject-using-his-classtype - я не уверен, потому что я не уверен на 100%, я понимаю, что вы пытаетесь сделать.

    David12 ноября 2009, 12:54
  • @Harriv: Подобное редактирование несколько неудачно, так как позже будет трудно сказать, почему в ответах используется другая (худшая) схема именования.Я полностью согласен с Джеруном (и если вы согласитесь, вы должны также проголосовать за его комментарий), но это изменение, возможно, следует откатить.Вы также ввели еще одну ошибку.

    mghie13 ноября 2009, 12:11

4 ответов

2
 (Components[i] as ComponentClass).Visible
 
  • Хм, тогда мы должны проголосовать за него.Хотя ... У меня под рукой Delphi, а у TComponent нет свойства Visible, так что я боюсь, что мой голос будет за сообщение mghie.

    Stijn Sanders12 ноября 2009, 13:36
  • @Tihauan: Вы, конечно, правы, и я тоже не понимаю голосов против.+1, чтобы компенсировать их.

    mghie12 ноября 2009, 14:43
  • интересным, но упускаемым из виду фактом, что Тихауан использует «AS» для каста.IMO Это более элегантно, чем проверка с помощью «IS» и явное приведение типов.

    PA.12 ноября 2009, 14:43
  • Я ценю объяснение.На самом деле можно использовать типы классов для безопасного приведения типов.Если не верите, можете попробовать код.

    Tihauan12 ноября 2009, 12:54
  • У меня нет Delphi там, где я сейчас, но я вам верю на слово!Я просто попытался отменить голос против, но он сказал, что он слишком старый - извините: /

    David12 ноября 2009, 13:06
  • Если я правильно понимаю вопрос, это не сработает, потому что ComponentClass - это метакласс, и вы не можете использовать один из них.Я ответил более подробными объяснениями - просто подумал, что мне нужно объяснить отрицательный голос.

    David12 ноября 2009, 12:51
  • @Pa: Вы не можете пропустить is, не изменив работу кода, поэтому вы получите is и as. Я не знаю, действительно ли это более элегантно…

    mghie12 ноября 2009, 14:46
  • Это здорово, я не знал этой разницы между жестким и безопасным приведением типов.

    Harriv13 ноября 2009, 12:07
  • @Stijn: TComponent не имеет свойства Visible, НО, приглядевшись, можно увидеть, что компонент приведен к «ComponentClass», который является типом TControlClass, который на самом деле имеет свойство Visible.Я подумал, что не должно быть так сложно понять, что мое решение РАБОТАЕТ и отвечает на вопрос.

    Tihauan12 ноября 2009, 14:05
1

Попробуйте этот вариант с помощью RTTI

 Uses
 TypInfo;

procedure TForm1.ToggleVisibility(ComponentClass: TClass);
var
  i       : integer;
  PropInfo: PPropInfo;
  aValue  : Variant;
begin
  for i := 0 to ComponentCount - 1 do
    if Components[i] is ComponentClass then
     begin
      PropInfo := GetPropInfo(Components[i].ClassInfo, 'Visible');
      if Assigned(PropInfo) then
      begin
       aValue:=GetPropValue(Components[i], 'Visible');
       if PropInfo.PropType^.Kind=tkEnumeration then //All enumerated types. This includes Boolean, ByteBool, WordBool, LongBool and Bool
       SetOrdProp(Components[i], PropInfo, Longint(not Boolean(aValue)));
      end;
     end;
end;
 

Выполнить

 ToggleVisibility(TEdit);
 
  • Интересное решение, но сложное.Есть ли причина использовать такое решение?

    Harriv13 ноября 2009, 12:09
  • Вы действительно уверены, что все свойства Visible всех возможных компонентов Delphi относятся к типу, который может быть жестко приведен к Boolean?

    mghie12 ноября 2009, 13:06
  • @mghie Чтобы изменить тип свойства, вам необходимо повторно объявить свойство.НоспереопределениесвойствомVisibleвы можетеAvidскрытие/ показуправления,такчто ваш кодможет бытьтакжене работают, какожидалось.:-)

    Heinz Z.12 ноября 2009, 13:33
  • @mghie: Я пропустил, что RRUZ сделал метод более общим, чем требовалось в исходном плакате.

    Heinz Z.12 ноября 2009, 16:35
  • @Harriv: Да, есть, поскольку в Delphi нет утиного набора текста.Рассмотрим два разных класса, которые не находятся в отношениях «предок-потомок», но оба имеют свойство с одинаковым именем и типом.Это решение подойдет для этого.

    mghie13 ноября 2009, 12:16
  • @Heinz: Это может быть правдой, но не имеет значения для кода выше.Обратите внимание, что метод принимает аргумент любого класса, поэтому переданный экземпляр не обязательно должен быть элементом управления и, следовательно, может иметь совершенно другое свойство Visible.Поскольку ограничений типа нет, не следует делать никаких предположений об этом в коде.

    mghie12 ноября 2009, 14:40
10

Поскольку компонент - это TControl или потомок, вы должны преобразовать его в TControl:

 procedure ToggleVisibility(ComponentClass : TControlClass);
var
  i : integer;
begin
  for i := 0 to ComponentCount - 1 do begin
    if Components[i] is ComponentClass then
      TControl(Components[i]).Visible := not TControl(Components[i]).Visible;
  end;
end;
 
  • А, ладно.Спасибо Heinz и mghie!Я не понимал, что такое TControlClass, и думаю, что был довольно сбит с толку.

    David12 ноября 2009, 13:47
  • @Tihauan: не имеет значения, собираетесь ли вы изменить TControlClass на что-то другое.Этот метод имеет дело со свойством Visible, введенным в TControl.

    Oliver Giesen16 ноября 2009, 09:00
  • @David Проверка Components[i] is ComponentClass для Componets [i] относится к классу, который должен обрабатывать метод.TControl(Components[i]) - это способ доступа к свойству Visible.И это правильно, потому что каждый экземпляр класса, совместимого с TControlClass, является потомком TControl.Чтобы код лучше читался, переменную ComponentClass следует переименовать в ControlClass.

    Heinz Z.12 ноября 2009, 13:21
  • Что делать, если позже вы измените класс управления на что-то другое.Легко забыть о зависимости, которую вы считаете само собой разумеющейся.

    Tihauan12 ноября 2009, 12:47
  • @Tihauan: Верно.Я не особо задумывался об этом, так как считаю всю идею ошибочной и никогда не стал бы писать такую процедуру.Обратите внимание, что он даже не компилируется в том виде, в каком он есть, как код в вопросе.

    mghie12 ноября 2009, 12:52
  • @David: См. мой комментарий к вашему ответу.Он находится в controls.pas году.

    mghie12 ноября 2009, 12:54
  • Разве вы не имеете в виду «если Components [i] - это TControl»?

    David12 ноября 2009, 12:53
2

Нет смысла приводить ComponentClass (Components [i]). Visible, потому что .Visible должен принадлежать к определенному классу, чтобы его можно было правильно скомпилировать.Следовательно, вам нужно указать точный класс, к которому следует привести.Например, если TControl имеет свойство .Visible, но производный класс создает новый вид свойства .Visible, компилятор не будет знать, для какого из этих двух свойств он должен компилироваться.

Итак, вопрос в том, хотите ли вы инвертировать TControl.Visible, тогда вы должны написать (Components [i] as TControl) .Visible.Думаю, это то, что вам нужно.

Если вы хотите инвертировать .Visible любого потомка TControl, независимо от того, относится ли он к элементу управления Visible или нет, и независимо от того, связан ли он с TControl.Visible или нет, тогда вам следует выбрать RTTIрешение, описанное в другом месте.