Delphi 使用返回值设置eventHandler
我需要调用事件处理程序来告诉用户选择Delphi 使用返回值设置eventHandler,delphi,delphi-xe2,Delphi,Delphi Xe2,我需要调用事件处理程序来告诉用户选择TCard或TLabel 然后将此值作为参数返回 我有两个单位游戏,SS\u拼写 这就是SS_咒语中的代码的工作原理 // TSPELL // ====== // The chronology is: // 1. At appropriate points in the game (such as before turn, after cast etc aka trigger points) // the game calls the SpellMe
TCard
或TLabel
然后将此值作为参数返回
我有两个单位游戏
,SS\u拼写
这就是SS_咒语中的代码的工作原理
// TSPELL
// ======
// The chronology is:
// 1. At appropriate points in the game (such as before turn, after cast etc aka trigger points)
// the game calls the SpellMeister's RunSpells method.
// 2. RunSpells checks the database for spells matching the card that
// initiated the spell action, and the trigger point at which it did so.
// For each one that it finds it will create an appropriate object, which
// could be a TSpell descendent or a TSpellAdjuster descendent.
// For each TSpell it finds it fires off an onFindSpell event.
// See below for details of how TSpellAdjusters are handled.
// 3. The handler for the onFindSpell events can (should) call the spells'
// AimAt method for each potential target. A potential target is a card
// or a player.
// 4. A spell's AimAt method checks if the potential target is a legitimate
// target for that spell and if so it calls its ApplySpellTo method to
// actually do the dirty deed.
所以我需要的是,一旦运行咒语获得db信息,它将检查needs2ndtarget:=1,如果是,那么我知道我需要这个咒语的第二个目标
这里是TSpellBase
它是创建TSpell
的类。在创建此事件的附件中,我添加了FOnSeek2ndTarget
在私密部分和受保护和公共财产中的FNeed2Target
,参见第2页和目标。你也会看到
TTargetEvt
,当前设置为接收TCARD,但我需要它来接收TCARD或TLAbel,不知道如何执行此操作
TTargetEvt = procedure (Card : TCard) of Object;
TSpellBase = class
private
FOnManaChange: TManaEvt;
FOnSeek2ndTarget: TTargetEvt;
protected
FCardType : TCardType;
FOriginator : TCard;
FNeed2Target : integer;
function LegitimateTarget (Candidate : TObject) : boolean; virtual;
public
constructor Create; virtual;
property CardType : TCardType read FCardType write FCardType; // ctLava, ctNature, ctWizard, etc etc
property Originator : TCard read FOriginator write FOriginator;
property Need2Target : integer read FNeed2Target write FNeed2Target;
property OnManaChange : TManaEvt read FOnManaChange write FOnManaChange;
property OnSeek2ndTarget : TTargetEvt read FonSeek2ndTarget write FOnSeek2ndTarget;
end;
现在在TSpell,我想我不需要在这里做任何更改,但它是spellmiester.runspell过程所需要的
TSpell = class(TSpellBase)
private
protected
FCategory : TCategory;
FLifeToAdd : Byte;
FMaxRandom : Byte;
FReplaceDmg : Byte;
FReplacement : string;
FStatTarget : Byte;
FTrigger : TTrigger;
procedure ApplySpellTo(Target : TObject); virtual; abstract; // Apply the spell to the target
public
procedure AimAt(Candidate: TObject); virtual;
property Category : TCategory read FCategory write FCategory;
property LifeToAdd : Byte read FLifeToAdd write FLifeToAdd;
property MaxRandom : Byte read FMaxRandom write FMaxRandom;
property ReplaceDmg : Byte read FReplaceDmg write FReplaceDmg;
property Replacement : string read FReplacement write FReplacement;
property StatTarget : Byte read FStatTarget write FStatTarget;
property Trigger : TTrigger read FTrigger write FTrigger;
end;
在这里,我在private部分添加了FOnSeek2ndTarget
。属性,所以现在施法时,它会
到这里,现在给runsspells打电话
TSpellMeister = class
private
FonFindSpell : TRcvSpell;
FOnManaChange : TManaEvt;
FOnSeek2ndTarget : TTargetEvt;
// FonNewAdjuster : TRcvSpell;
protected
FAdjusters : TAdjusters;
FQuery : TADOQuery;
public
constructor Create(DBCon: TADOConnection);
destructor Destroy; override;
function IfNull( const Value, Default : OleVariant ) : OleVariant;
procedure Adjust(Attacker : TCard; Victim : TObject; var TheDamage : integer); overload;
procedure Adjust(Attacker : TCard; var TheCost : integer); overload;
procedure RunSpells(Card : TCard; Trigger : TTrigger);
property onFindSpell : TRcvSpell read FonFindSpell write FonFindSpell;
property OnManaChange : TManaEvt read FOnManaChange write FOnManaChange;
property OnSeek2ndTarget: TTargetEvt read FOnSeek2ndTarget write FOnSeek2ndTarget;
// property onNewAdjuster : TRcvSpell read FonNewAdjuster write FonNewAdjuster;
end;
这就是问题所在,我添加了foundspell.Need2ndTarget
这会从数据库中获取数据,如果是1,则需要用户为该法术选择另一个目标。现在我加了
如果FoundSpell.Need2Target=1,则
FOnSeek2ndTarget(卡片)
但我相信这是不对的
//**************************************************************************
procedure TSpellMeister.RunSpells(Card: TCard; Trigger: TTrigger);
//**************************************************************************
var
OneSpell : TSpellBase;
FoundSpell : TSpell; // Just so only have to cast once
begin
assert(assigned(FonFindSpell),'TSpellMeister.RunSpells : No onFindSpell event handler!');
// Search the database
FQuery.Active := FALSE;
FQuery.Parameters.ParamByName(SQL_PARAM_SPELL_ORIGINATOR).Value := Card.CName;
FQuery.Parameters.ParamByName(SQL_PARAM_SPELL_TRIGGER ).Value := Trigger;
FQuery.Active := TRUE;
// Iterate through the spell records. For each one, create a category-specific
// TSpell descendant and fire off an onFindSpell event.
if FQuery.RecordCount > 0 then
begin
FQuery.Recordset.MoveFirst;
while not FQuery.Recordset.EOF do
begin
case TCategory(FQuery.Recordset.Fields[DB_FLD_CATEGORY].Value) of
caAboveLife : OneSpell := TSpellAboveLife.Create;
caDamage : OneSpell := TSpellDamage.Create;
caDamagePlus : OneSpell := TSpellDamagePlus.Create;
caDamagePlusPercent : OneSpell := TSpellDamagePlusPercent.Create;
caDamagePercentIncrease : OneSpell := TSpellDamagePercentIncrease.Create;
caDamagePercentDecrease : OneSpell := TSpellDamagePercentDecrease.Create;
caDamageSpells : OneSpell := TSpellDamageSpells.Create;
caDestroy : OneSpell := TSpellDestroy.Create;
.....
else raise ERangeError.CreateFmt(ERROR_INVALID_DB_NUMBER,[DB_FLD_CATEGORY,FQuery.Recordset.Fields[DB_FLD_CATEGORY].Value]);
end;
try
if assigned(OneSpell) then
begin
OneSpell.CardType := TCardType (IfNull( FQuery.Recordset.Fields[ DB_FLD_CARD_TYPE ].Value,0) );
OneSpell.Originator := Card;
OneSpell.OnManaChange := Self.OnManaChange;
OneSpell.OnSeek2ndTarget := self.OnSeek2ndTarget;
assert(OneSpell.Originator.COwner is TPlayer,'TSpellMeister.RunSpells : OneSpell.Originator.COwner not a player: ' + OneSpell.Originator.COwner.ClassName);
try
FoundSpell := TSpell(OneSpell);
FoundSpell.Originator := Card;
FoundSpell.Trigger := Trigger;
FoundSpell.CardType := TCardType ( FQuery.Recordset.Fields[ DB_FLD_CARD_TYPE ].Value );
FoundSpell.Category := TCategory ( FQuery.Recordset.Fields[ DB_FLD_CATEGORY ].Value );
FoundSpell.LifeToAdd := IfNull( FQuery.Recordset.Fields[ DB_FLD_LIFE_TO_ADD ].Value,0);
FoundSpell.MaxRandom := IfNull( FQuery.Recordset.Fields[ DB_FLD_MAX_RANDOM ].Value,0);
FoundSpell.PerCent := IfNull( FQuery.Recordset.Fields[ DB_FLD_PER_CENT ].Value,0);
FoundSpell.Plus := IfNull( FQuery.Recordset.Fields[ DB_FLD_PLUS ].Value,0);
FoundSpell.ReplaceDmg := IfNull( FQuery.Recordset.Fields[ DB_FLD_REPLACE_DMG ].Value,0);
FoundSpell.Replacement := IfNull( FQuery.Recordset.Fields[ DB_FLD_REPLACEMENT ].Value,0);
FoundSpell.StatTarget := IfNull( FQuery.Recordset.Fields[ DB_FLD_STAT_TARGET ].Value,0);
FoundSpell.Target := TTargetType( IfNull(FQuery.Recordset.Fields[ DB_FLD_TARGET ].Value,0) );
FoundSpell.Need2Target := IfNull( FQuery.Recordset.Fields[ DB_FLD_NEED2TARGET ].Value,0);
assert(FoundSpell.Originator.COwner is TPlayer,'TSpellMeister.RunSpells : FoundSpell.Originator.COwner not a player: ' + OneSpell.Originator.COwner.ClassName);
if FoundSpell.Need2Target = 1 then
FOnSeek2ndTarget(Card);
FonFindSpell(FoundSpell);
finally
FreeAndNil(OneSpell);
end;
end;
except // I think this is OK but is there a possible bug if
FreeAndNil(OneSpell); // spell adjuster added to list then destroyed?
end; // List item would then be invalid.
FQuery.Recordset.MoveNext;
end;
end;
end;
所有这些都是ss_法术单位,现在是使用ss_法术单位的游戏单位
在论坛。创建我有
FSpellMeister.OnSeek2ndTarget := self.Handle2ndTarget;
不知道该怎么处理第二个目标目前只是
//****************************************************************************
procedure TFGame.Handle2ndTarget(Card : TCard);
begin
showmessage('Select a target HANDLE2ndTARGET');
end;
只是想看看我是否至少能到这里
因此,我的问题是,如果您无法理解,当foundspell.Need2ndTarget:=1时,如何使用事件FOnSeek2ndTarget()将ss_拼写中的变量设置为TObject(tcard或tlabel)代码>
我需要知道如何使用事件返回var
参数
如下定义您的事件:
type
TMyEvent = procedure(var ReturnValue: Integer) of object;
然后以通常的方式添加事件属性:
....
private
FOnMyEvent: TMyEvent;
....
published
property OnMyEvent: TMyEvent read FOnMyEvent write FOnMyEvent;
....
细微差别体现在你如何呈现事件。通常,如果您正在编写一个提供事件的组件,那么您必须考虑到事件没有附加处理程序的可能性。如果事件是要返回一个值,那么你怎么可能既没有hander,又有一个返回值呢?诀窍是在显示事件之前,将参数指定为默认值。例如:
procedure TMyComponent.DoMyEvent(out ReturnValue: Integer);
begin
Result := DefaultValueForMyEventHandler;// you supply something meaningful here
if Assigned(FOnMyEvent) then
FOnMyEvent(Result);
end;
因此,如果组件的使用者没有为事件提供处理程序,那么该方法仍然会产生一个合理的值
如果您阅读本文并认为FOnMyEvent
为nil
毫无意义,那么您的设计是错误的。如果您想强迫消费者提供行为,而不允许依赖违约,那么事件是错误的机制。在这种情况下,要求使用者通过参数提供行为,可能由组件构造函数的签名强制执行。或者其他方式
我刚刚给出了一个与代码无关的基本示例。我试着理解这些概念。希望你能根据自己的具体需要来调整 只需更改您的TTargetEvt
类型的签名,例如:
TTargetEvt = procedure (Card : TCard; var Target: TObject) of Object;
然后相应地更新RunSpells()
:
var
Target: TObject;
...
if FoundSpell.Need2Target = 1 then
begin
Target := nil;
if Assigned(FOnSeek2ndTarget) then FOnSeek2ndTarget(Card, Target);
// use Target as needed...
end;
...
procedure TFGame.Handle2ndTarget(Card : TCard; var Target: TObject);
begin
Target := ...;
end;
然后相应地更新处理程序:
var
Target: TObject;
...
if FoundSpell.Need2Target = 1 then
begin
Target := nil;
if Assigned(FOnSeek2ndTarget) then FOnSeek2ndTarget(Card, Target);
// use Target as needed...
end;
...
procedure TFGame.Handle2ndTarget(Card : TCard; var Target: TObject);
begin
Target := ...;
end;
我真的完全不知道你在问什么。这里的代码太多了。你首先需要弄清楚你的问题是什么,然后问这个问题。发布所有代码并希望我们能解决您的问题是没有用的。是否希望事件返回值?将返回值设为var
参数。是吗?是的,我试图展示与问题相关的代码。。我移走了很多。对不起,时间太长了。。但是,是的,我需要知道如何使用事件返回var参数FNeed2Target:Integer
。不要使用0
和1
来指示布尔状态。将变量声明为Boolean
。我当前正在对数据库中的所有值使用整数,并在代码中设置了枚举,因此为了保持此变量的一致性,我添加了TNeed2Target=(neNoTarget,neTarget)但是如果我需要的ReturnValue是一个对象怎么办。您是否可以执行对象的TMyEvent=procedure(var ReturnValue:TObject)代码>当然。你可以使用任何你喜欢的类型;这是目标中的读数?因此,在handle2ndTarget中,如果我设置Target:=slot1。那么在运行咒语中,目标值现在是slot1?这是正确的。事件参数中的var
说明符将RunSpell
s localTarget
变量的内存地址传递给处理程序,允许处理程序直接访问变量并更改其值。这很好,解决了我的大多数问题,现在在runspell中,它会得到db信息,告诉我一个法术是否需要第二个目标。。所以,一旦所有这些都被检查,它调用到Handle2ndTarget,我需要Target:=对象用户点击。。你会怎么做,才能返回targetI的值?我已经在你之前的一个问题中回答了这个问题。您需要接受事件驱动的习惯用法。没有其他方法了。所以我需要做的是,在施放卡牌之后,在整个法术动作之前,检查db,看看它是否需要第二个目标。然后设置变量,在单击对象时,它将检查该变量是否为真。。如果是这样,它会将TObject保存到Var2,那么我只需执行Target:=Var2