2009-07-04 11 views
5

w jaki sposób mogę sprawić, że mój kod zadziała? :) Próbowałem sformułować to pytanie, ale po kilku nieudanych próbach wydaje mi się, że zauważycie problem szybciej, niż czytając moje "wyjaśnienia". Dziękuję Ci.rzucić TObject przy użyciu jego ClassType?

setCtrlState([ memo1, edit1, button1], False); 

_

procedure setCtrlState(objs: array of TObject; bState: boolean = True); 
var 
    obj: TObject; 
    ct: TClass; 
begin 
    for obj in objs do 
    begin 
    ct := obj.ClassType; 


    if (ct = TMemo) or (ct = TEdit) then 
     ct(obj).ReadOnly := not bState;  // error here :(

    if ct = TButton then 
     ct(obj).Enabled:= bState;  // and here :(

    end; 
end; 

Odpowiedz

5

byłoby łatwiejsze w użyciu RTTI zamiast wyraźnej casting, czyli:

uses 
    TypInfo; 

setCtrlState([ memo1, edit1, button1], False); 

procedure setCtrlState(objs: array of TObject; bState: boolean = True); 
var 
    obj: TObject; 
    PropInfo: PPropInfo; 
begin 
    for obj in objs do 
    begin 
    PropInfo := GetPropInfo(obj, 'ReadOnly'); 
    if PropInfo <> nil then SetOrdProp(obj, PropInfo, not bState); 

    PropInfo := GetPropInfo(obj, 'Enabled'); 
    if PropInfo <> nil then SetOrdProp(obj, PropInfo, bState); 
    end; 
end; 
+0

to jest * dokładnie * to, czego szukałem. Dziękuję Ci! –

4

Trzeba oddać obiekt do TMemo ct/TEdit/TButton zanim można ustawić właściwości na obiekt.

Linia, w której pojawiają się błędy, jest błędna, ponieważ ct nadal jest klasą TClass, a nie TButtonem/etc. Jeśli rzucisz na TButton, będziesz mógł ustawić włączone na true.

Polecam lekturę na casting in Delphi. Osobiście polecam używanie operatorów as/is, a nie ClassType. Kod będzie prostszy w tym przypadku i znacznie bardziej zrozumiały.


Osobiście chciałbym napisać to bardziej jak:

procedure setCtrlState(objs: array of TObject; bState: boolean = True); 
var 
    obj: TObject; 
begin 
    for obj in objs do 
    begin 
    // I believe these could be merged by using an ancestor of TMemo+TEdit (TControl?) 
    // but I don't have a good delphi reference handy 
    if (obj is TMemo) then 
     TMemo(obj).ReadOnly := not bState; 

    if (obj is TEdit) then 
     TEdit(obj).ReadOnly := not bState; 

    if (obj is TButton) then 
     TButton(obj).Enabled := bState; 
    end; 
end; 
7

Należy jawnie rzutować obiektu do jakiejś klasy. To powinno działać:

procedure setCtrlState(objs: array of TObject; bState: boolean = True); 
var 
    obj: TObject; 
    ct: TClass; 
begin 
    for obj in objs do 
    begin 
    ct := obj.ClassType; 

    if ct = TMemo then 
     TMemo(obj).ReadOnly := not bState 
    else if ct = TEdit then 
     TEdit(obj).ReadOnly := not bState 
    else if ct = TButton then 
     TButton(obj).Enabled := bState; 
    end; 
end; 

ten może ulec skróceniu za pomocą "is" operator - nie ma potrzeby ct zmiennej:

procedure setCtrlState(objs: array of TObject; bState: boolean = True); 
var 
    obj: TObject; 
begin 
    for obj in objs do 
    begin 
    if obj is TMemo then 
     TMemo(obj).ReadOnly := not bState 
    else if obj is TEdit then 
     TEdit(obj).ReadOnly := not bState 
    else if obj is TButton then 
     TButton(obj).Enabled := bState; 
    end; 
end; 
+0

nie powinien sekund typecast w każdym przypadku być „TEdit” zamiast „TMemo”? – Argalatyr

+0

+0,5 za powiedzenie, że musisz wykonywać rzuty dla każdego rodzaju. +0,5 za użycie "jest" –

+0

naprawiłem literówkę wspomnianą przez Argalatyra –

3

Nie ma potrzeby, aby rzucić się TMemo i TEdit oddzielnie, ponieważ są one obaj potomkowie wspólnej klasy nadrzędnej, które mają właściwość ReadOnly:

procedure TForm1.FormCreate(Sender: TObject); 

    procedure P(const Obj: TComponent); 
    begin 
    if Obj is TCustomEdit then 
     TCustomEdit(Obj).ReadOnly := True; 
    end; 

begin 
    P(Memo1); 
    P(Edit1); 
end; 
2

można uniknąć odwoływania się różne jednostki i wyraźny odlew jeśli nie zwracaj uwagi na małe trafienie skuteczności i ogranicz zmiany wprowadzonych właściwości. Spójrz na jednostkę TypInfo dołączoną do Delphi.