标记/取消标记一组枚举中的另一个选项
Mark / Unmarked another option from a set of enum
我在 component
中有一组 enum
像这样:
type
TOption = (clVisible, clVisibleAlways, clRenderable, clEditable);
TOptions = set of TOption;
const
defaultOptions = [clVisible, clRenderable];
type
TMyComp = class(TComponent)
private
FOptions: TOptions;
procedure SetOptions(const Value: TOptions);
public
property Options: TOptions read FOptions write SetOptions default defaultOptions;
...
procedure TMyComp.SetOptions(const Value: TOptions);
var
ToBeSet, ToBeCleared: TOptions;
begin
if FOptions <> Value then
begin
ToBeCleared:= FOptions - Value;
ToBeSet:= Value - FOptions;
FOptions:= Value;
//clVisible -> clRenderable
if (clVisible in ToBeSet) and (clRenderable in ToBeCleared) then
begin
Include(FOptions, clRenderable);
Include(ToBeSet, clRenderable);
end;
//not clRenderable -> not clVisible
if (clRenderable in ToBeCleared) and (clVisible in ToBeSet) then
begin
Exclude(FOptions, clVisible);
Exclude(ToBeSet, clVisible);
end;
//not clVisible -> not clVisibleAlways
if (clVisible in ToBeCleared) and (clVisibleAlways in ToBeSet) then
begin
Exclude(FOptions, clVisibleAlways);
Exclude(ToBeSet, clVisibleAlways);
end;
//clVisibleAlways -> clVisible
if (clVisibleAlways in ToBeSet) and (clVisible in ToBeCleared) then
begin
Include(FOptions, clVisible);
Include(ToBeSet, clVisible);
end;
end;
end;
我想做但行不通的是:
- 如果检查了
clVisibleAlways
,还检查 clVisible
- 如果检查了
clVisible
,还检查 clRenderable
- 如果
clRenderable
未选中,也取消选中 clVisible
- 如果
clVisible
未选中,也取消选中 clVisibleAlways
请大家支持一下这个话题。
您可以将 TOption
集包装到助手 class 中,这将提供额外的赋值逻辑:
TOption = (clVisible, clVisibleAlways, clRenderable, clEditable);
TOptions = set of TOption;
TOptionHelper = class
public
constructor Create();
procedure Include(const AOption : TOption);
procedure Exclude(const AOption : TOption);
function GetOptions() : TOptions;
property Options : TOptions read GetOptions;
strict private
FOptions : TOptions;
end;
constructor TOptionHelper.Create;
begin
FOptions := [clVisible, clRenderable];
end;
procedure TOptionHelper.Exclude(const AOption: TOption);
begin
end;
function TOptionHelper.GetOptions: TOptions;
begin
Result := FOptions;
end;
procedure TOptionHelper.Include(const AOption: TOption);
begin
case AOption of
clVisibleAlways : FOptions := FOptions + [clVisible];
//and so on...
end;
end;
我认为您的方法不必要地复杂。
更新
必须清楚地区分添加或删除选项(我以前没有这样做)。更新后的代码可以做到这一点,并且在 Delphi 10.1 Berlin 中运行良好。我的测试组件称为 TNewButton
并且基于 TButton
.
procedure TNewButton.SetOptions(const Value: TOptions);
var
Opts: TOptions; { Because of "const"; you can also remove "const"
and use Value instead of Opts. }
begin
if FOptions <> Value then
begin
Opts := Value;
{ Find out if we are adding or removing an option. }
if Opts - FOptions <> [] then
begin
{ We are adding an option. }
if clVisibleAlways in Opts then
Include(Opts, clVisible);
if clVisible in Opts then
Include(Opts, clRenderable)
end
else
begin
{ We are removing an option. }
if not (clRenderable in Opts) then
Exclude(Opts, clVisible);
if not (clVisible in Opts) then
Exclude(Opts, clVisibleAlways);
end;
FOptions := Opts;
end;
end;
我测试了几次,至少在我的 Object Inspector 中,它完全符合您的要求。
你的逻辑有问题。
线条
if (clVisible in ToBeSet) and (clRenderable in ToBeCleared) then
和
if (clRenderable in ToBeCleared) and (clVisible in ToBeSet) then
是等效的 - 但这显然不是您想要的。
我认为 Rudy 的解决方案也不完全正确,因为 set 和 clear 之间存在潜在的矛盾。
这是我建议的解决方案。
procedure TMyComp.SetOptions(const Value: TOptions);
var
ToBeSet, ToBeCleared: TOptions;
begin
if FOptions <> Value then
begin
ToBeCleared:= FOptions - Value;
ToBeSet:= Value - FOptions;
FOptions:= Value;
//clVisible -> clRenderable
if (clVisible in ToBeSet) then
begin
Include(FOptions, clRenderable);
Exclude( ToBeCleared, clRenderable); // avoid contradiction!
end;
//not clRenderable -> not clVisible
if (clRenderable in ToBeCleared) then
begin
Exclude(FOptions, clVisible);
Exclude(ToBeSet, clVisible);
Include(ToBeCleared, clVisible ); // Chain reaction - Clearing clRederable clears clVisible and therefore by implication clVisibleAlways!
end;
//not clVisible -> not clVisibleAlways
if (clVisible in ToBeCleared) then
begin
Exclude(FOptions, clVisibleAlways);
Exclude(ToBeSet, clVisibleAlways);
end;
//clVisibleAlways -> clVisible
if (clVisibleAlways in ToBeSet) then
begin
Include(FOptions, clVisible);
Include(ToBeSet, clVisible);
end;
end;
end;
我会使用更像这样的东西:
procedure TMyComp.SetOptions(const Value: TOptions);
var
ToBeSet, ToBeCleared, LNewOptions: TOptions;
begin
ToBeCleared := FOptions - Value;
ToBeSet := Value - FOptions;
LNewOptions := FOptions - ToBeCleared + ToBeSet;
if (clVisibleAlways in LNewOptions) then
Include(LNewOptions, clVisible);
if (clVisible in LNewOptions) then
Include(LNewOptions, clRenderable);
if not (clRenderable in LNewOptions) then
Exclude(LNewOptions, clVisible);
if not (clVisible in LNewOptions) then
Exclude(LNewOptions, clVisibleAlways);
if FOptions <> LNewOptions then
begin
FOptions := LNewOptions;
// update the rest of your component as needed...
end;
end;
我将添加用于解决问题的完整代码。这将消除一些关于我选中或取消选中选项的顺序的限制。
procedure TMyComp.SetOptions(Value: TOptions);
var
ToBeSet, ToBeCleared: TOptions;
clRenderableChanged, clVisibleChanged, clVisibleAlwaysChanged: Boolean;
begin
if FOptions <> Value then
begin
ToBeCleared:= FOptions - Value;
ToBeSet:= Value - FOptions;
clRenderableChanged:= (clRenderable in ToBeSet) and (not (clRenderable in FOptions)) or ((clRenderable in ToBeCleared) and (clRenderable in FOptions));
clVisibleChanged:= (clVisible in ToBeSet) and (not (clVisible in FOptions)) or ((clVisible in ToBeCleared) and (clVisible in FOptions));
clVisibleAlwaysChanged:= (clVisibleAlways in ToBeSet) and (not (clVisibleAlways in FOptions)) or ((clVisibleAlways in ToBeCleared) and (clVisibleAlways in FOptions));
FOptions:= Value;
if clRenderableChanged then
begin
if clRenderable in ToBeSet then Include(FOptions, clVisible);
if clRenderable in ToBeCleared then
begin
Exclude(FOptions, clVisible);
Exclude(FOptions, clVisibleAlways);
end;
end;
if clVisibleChanged then
begin
if clVisible in ToBeSet then Include(FOptions, clRenderable);
if clVisible in ToBeCleared then Exclude(FOptions, clVisibleAlways);
end;
if clVisibleAlwaysChanged then
begin
if clVisibleAlways in ToBeSet then
begin
Include(FOptions, clVisible);
Include(FOptions, clRenderable);
end;
end;
end;
end;
无论如何,这要归功于所有回答这个问题的人的帮助。
更新
我认为我的一些问题是因为我在安装组件更改后没有重新启动 Delphi。
我在 component
中有一组 enum
像这样:
type
TOption = (clVisible, clVisibleAlways, clRenderable, clEditable);
TOptions = set of TOption;
const
defaultOptions = [clVisible, clRenderable];
type
TMyComp = class(TComponent)
private
FOptions: TOptions;
procedure SetOptions(const Value: TOptions);
public
property Options: TOptions read FOptions write SetOptions default defaultOptions;
...
procedure TMyComp.SetOptions(const Value: TOptions);
var
ToBeSet, ToBeCleared: TOptions;
begin
if FOptions <> Value then
begin
ToBeCleared:= FOptions - Value;
ToBeSet:= Value - FOptions;
FOptions:= Value;
//clVisible -> clRenderable
if (clVisible in ToBeSet) and (clRenderable in ToBeCleared) then
begin
Include(FOptions, clRenderable);
Include(ToBeSet, clRenderable);
end;
//not clRenderable -> not clVisible
if (clRenderable in ToBeCleared) and (clVisible in ToBeSet) then
begin
Exclude(FOptions, clVisible);
Exclude(ToBeSet, clVisible);
end;
//not clVisible -> not clVisibleAlways
if (clVisible in ToBeCleared) and (clVisibleAlways in ToBeSet) then
begin
Exclude(FOptions, clVisibleAlways);
Exclude(ToBeSet, clVisibleAlways);
end;
//clVisibleAlways -> clVisible
if (clVisibleAlways in ToBeSet) and (clVisible in ToBeCleared) then
begin
Include(FOptions, clVisible);
Include(ToBeSet, clVisible);
end;
end;
end;
我想做但行不通的是:
- 如果检查了
clVisibleAlways
,还检查clVisible
- 如果检查了
clVisible
,还检查clRenderable
- 如果
clRenderable
未选中,也取消选中clVisible
- 如果
clVisible
未选中,也取消选中clVisibleAlways
请大家支持一下这个话题。
您可以将 TOption
集包装到助手 class 中,这将提供额外的赋值逻辑:
TOption = (clVisible, clVisibleAlways, clRenderable, clEditable);
TOptions = set of TOption;
TOptionHelper = class
public
constructor Create();
procedure Include(const AOption : TOption);
procedure Exclude(const AOption : TOption);
function GetOptions() : TOptions;
property Options : TOptions read GetOptions;
strict private
FOptions : TOptions;
end;
constructor TOptionHelper.Create;
begin
FOptions := [clVisible, clRenderable];
end;
procedure TOptionHelper.Exclude(const AOption: TOption);
begin
end;
function TOptionHelper.GetOptions: TOptions;
begin
Result := FOptions;
end;
procedure TOptionHelper.Include(const AOption: TOption);
begin
case AOption of
clVisibleAlways : FOptions := FOptions + [clVisible];
//and so on...
end;
end;
我认为您的方法不必要地复杂。
更新
必须清楚地区分添加或删除选项(我以前没有这样做)。更新后的代码可以做到这一点,并且在 Delphi 10.1 Berlin 中运行良好。我的测试组件称为 TNewButton
并且基于 TButton
.
procedure TNewButton.SetOptions(const Value: TOptions);
var
Opts: TOptions; { Because of "const"; you can also remove "const"
and use Value instead of Opts. }
begin
if FOptions <> Value then
begin
Opts := Value;
{ Find out if we are adding or removing an option. }
if Opts - FOptions <> [] then
begin
{ We are adding an option. }
if clVisibleAlways in Opts then
Include(Opts, clVisible);
if clVisible in Opts then
Include(Opts, clRenderable)
end
else
begin
{ We are removing an option. }
if not (clRenderable in Opts) then
Exclude(Opts, clVisible);
if not (clVisible in Opts) then
Exclude(Opts, clVisibleAlways);
end;
FOptions := Opts;
end;
end;
我测试了几次,至少在我的 Object Inspector 中,它完全符合您的要求。
你的逻辑有问题。
线条
if (clVisible in ToBeSet) and (clRenderable in ToBeCleared) then
和
if (clRenderable in ToBeCleared) and (clVisible in ToBeSet) then
是等效的 - 但这显然不是您想要的。
我认为 Rudy 的解决方案也不完全正确,因为 set 和 clear 之间存在潜在的矛盾。
这是我建议的解决方案。
procedure TMyComp.SetOptions(const Value: TOptions);
var
ToBeSet, ToBeCleared: TOptions;
begin
if FOptions <> Value then
begin
ToBeCleared:= FOptions - Value;
ToBeSet:= Value - FOptions;
FOptions:= Value;
//clVisible -> clRenderable
if (clVisible in ToBeSet) then
begin
Include(FOptions, clRenderable);
Exclude( ToBeCleared, clRenderable); // avoid contradiction!
end;
//not clRenderable -> not clVisible
if (clRenderable in ToBeCleared) then
begin
Exclude(FOptions, clVisible);
Exclude(ToBeSet, clVisible);
Include(ToBeCleared, clVisible ); // Chain reaction - Clearing clRederable clears clVisible and therefore by implication clVisibleAlways!
end;
//not clVisible -> not clVisibleAlways
if (clVisible in ToBeCleared) then
begin
Exclude(FOptions, clVisibleAlways);
Exclude(ToBeSet, clVisibleAlways);
end;
//clVisibleAlways -> clVisible
if (clVisibleAlways in ToBeSet) then
begin
Include(FOptions, clVisible);
Include(ToBeSet, clVisible);
end;
end;
end;
我会使用更像这样的东西:
procedure TMyComp.SetOptions(const Value: TOptions);
var
ToBeSet, ToBeCleared, LNewOptions: TOptions;
begin
ToBeCleared := FOptions - Value;
ToBeSet := Value - FOptions;
LNewOptions := FOptions - ToBeCleared + ToBeSet;
if (clVisibleAlways in LNewOptions) then
Include(LNewOptions, clVisible);
if (clVisible in LNewOptions) then
Include(LNewOptions, clRenderable);
if not (clRenderable in LNewOptions) then
Exclude(LNewOptions, clVisible);
if not (clVisible in LNewOptions) then
Exclude(LNewOptions, clVisibleAlways);
if FOptions <> LNewOptions then
begin
FOptions := LNewOptions;
// update the rest of your component as needed...
end;
end;
我将添加用于解决问题的完整代码。这将消除一些关于我选中或取消选中选项的顺序的限制。
procedure TMyComp.SetOptions(Value: TOptions);
var
ToBeSet, ToBeCleared: TOptions;
clRenderableChanged, clVisibleChanged, clVisibleAlwaysChanged: Boolean;
begin
if FOptions <> Value then
begin
ToBeCleared:= FOptions - Value;
ToBeSet:= Value - FOptions;
clRenderableChanged:= (clRenderable in ToBeSet) and (not (clRenderable in FOptions)) or ((clRenderable in ToBeCleared) and (clRenderable in FOptions));
clVisibleChanged:= (clVisible in ToBeSet) and (not (clVisible in FOptions)) or ((clVisible in ToBeCleared) and (clVisible in FOptions));
clVisibleAlwaysChanged:= (clVisibleAlways in ToBeSet) and (not (clVisibleAlways in FOptions)) or ((clVisibleAlways in ToBeCleared) and (clVisibleAlways in FOptions));
FOptions:= Value;
if clRenderableChanged then
begin
if clRenderable in ToBeSet then Include(FOptions, clVisible);
if clRenderable in ToBeCleared then
begin
Exclude(FOptions, clVisible);
Exclude(FOptions, clVisibleAlways);
end;
end;
if clVisibleChanged then
begin
if clVisible in ToBeSet then Include(FOptions, clRenderable);
if clVisible in ToBeCleared then Exclude(FOptions, clVisibleAlways);
end;
if clVisibleAlwaysChanged then
begin
if clVisibleAlways in ToBeSet then
begin
Include(FOptions, clVisible);
Include(FOptions, clRenderable);
end;
end;
end;
end;
无论如何,这要归功于所有回答这个问题的人的帮助。
更新 我认为我的一些问题是因为我在安装组件更改后没有重新启动 Delphi。