Delphi TRadioGroup:单击当前选中项两次以取消选中它。能做到吗?
我搜索了一下,没有找到答案: 我在一个放射组中有四项,其中三项是汽车名称,第四项我称之为“无”。单击第四项时,它将索引设置为-1。到目前为止,这一切都很好。我想有一个功能,如果我点击一个已经选中的项目(activeindex),它会将其设置为-1。这样,我就可以从列表中删除第四个“无”项。这在放射组中可能吗 仅当单击的项目已经是索引(旧索引)并且将被取消选中时,此操作才有效。如果单击了未选中的项目,它仍将为该项目设置索引Delphi TRadioGroup:单击当前选中项两次以取消选中它。能做到吗?,delphi,Delphi,我搜索了一下,没有找到答案: 我在一个放射组中有四项,其中三项是汽车名称,第四项我称之为“无”。单击第四项时,它将索引设置为-1。到目前为止,这一切都很好。我想有一个功能,如果我点击一个已经选中的项目(activeindex),它会将其设置为-1。这样,我就可以从列表中删除第四个“无”项。这在放射组中可能吗 仅当单击的项目已经是索引(旧索引)并且将被取消选中时,此操作才有效。如果单击了未选中的项目,它仍将为该项目设置索引 谢谢 标准单选按钮的行为与您描述的不同。选中一个单选按钮后,将保持选中状态
谢谢 标准单选按钮的行为与您描述的不同。选中一个单选按钮后,将保持选中状态,直到选中同一组中的另一个单选按钮为止 然而,尽管如此,您仍然可以通过少量的手动操作来实现您的要求:
type
TMyForm = class(TForm)
RadioGroup1: TRadioGroup;
procedure FormShow(Sender: TObject);
private
{ Private declarations }
OriginalWndProcs: array[0..2] of TWndMethod;
procedure RadioButtonWndProc1(var Message: TMessage);
procedure RadioButtonWndProc2(var Message: TMessage);
procedure RadioButtonWndProc3(var Message: TMessage);
procedure RadioButtonWndProc(const Index: Integer; var Message: TMessage);
public
{ Public declarations }
end;
procedure TMyForm.RadioButtonWndProc1(var Message: TMessage);
begin
RadioButtonWndProc(0, Message);
end;
procedure TMyForm.RadioButtonWndProc2(var Message: TMessage);
begin
RadioButtonWndProc(1, Message);
end;
procedure TMyForm.RadioButtonWndProc3(var Message: TMessage);
begin
RadioButtonWndProc(2, Message);
end;
procedure TMyForm.FormShow(Sender: TObject);
var
NewWndProcs: array[0..2] of TWndMethod;
I: Integer;
begin
NewWndProcs[0] := RadioButtonWndProc1;
NewWndProcs[1] := RadioButtonWndProc2;
NewWndProcs[2] := RadioButtonWndProc3;
for I := 0 to 2 do
begin
OriginalWndProcs[I] := RadioGroup1.Buttons[I].WindowProc;
RadioGroup1.Buttons[I].WindowProc := NewWndProcs[I];
end;
end;
procedure TMyForm.RadioButtonWndProc(const Index: Integer; var Message: TMessage);
begin
if (Message.Msg = CN_COMMAND) and
(TWMCommand(Message).NotifyCode = BN_CLICKED) and
(RadioGroup1.Buttons[Index].Checked) then
begin
RadioGroup1.Buttons[Index].Checked := False;
Exit;
end;
OriginalWndProcs[Index](Message);
end;
更新:通过将
TRadioButton
对象直接传递到RadioButtonWndProc()
而无需使用中间代理方法,上述代码可以稍微简化:
type
TMyForm = class(TForm)
RadioGroup1: TRadioGroup;
procedure FormShow(Sender: TObject);
private
{ Private declarations }
OriginalWndProcs: array[0..2] of TWndMethod;
procedure RadioButtonWndProc(var Message: TMessage);
public
{ Public declarations }
end;
procedure TMyForm.FormShow(Sender: TObject);
var
I: Integer;
Btn: TRadioButton;
M: TWndMethod;
begin
for I := 0 to 2 do
begin
Btn := RadioGroup1.Buttons[I];
Btn.Tag := I;
OriginalWndProcs[I] := Btn.WindowProc;
M := RadioButtonWndProc;
TMethod(M).Data := Btn; // <-- makes Self in RadioButtonWndProc() point to the Button instead of the Form...
Btn.WindowProc := M;
end;
end;
procedure TMyForm.RadioButtonWndProc(var Message: TMessage);
var
Btn: TRadioButton;
begin
Btn := TRadioButton(Self);
if (Message.Msg = CN_COMMAND) and
(TWMCommand(Message).NotifyCode = BN_CLICKED) and
(Btn.Checked) then
begin
Btn.Checked := False;
Exit;
end;
MyForm.OriginalWndProcs[Btn.Tag](Message); // <-- note, using the global Form pointer to reach Form members...
end;
尽管如此,我还是不推荐这种UI设计。这根本不是用户期望单选按钮的行为方式。更好的UI选择是使用
TComboBox
,其中第四项用于不选择任何内容。一个t组合框
比多个单选按钮占用更少的空间,而且它仍然提供用户期望的单一选择行为。标准单选按钮的行为与您描述的不同。选中一个单选按钮后,将保持选中状态,直到选中同一组中的另一个单选按钮为止
然而,尽管如此,您仍然可以通过少量的手动操作来实现您的要求:
type
TMyForm = class(TForm)
RadioGroup1: TRadioGroup;
procedure FormShow(Sender: TObject);
private
{ Private declarations }
OriginalWndProcs: array[0..2] of TWndMethod;
procedure RadioButtonWndProc1(var Message: TMessage);
procedure RadioButtonWndProc2(var Message: TMessage);
procedure RadioButtonWndProc3(var Message: TMessage);
procedure RadioButtonWndProc(const Index: Integer; var Message: TMessage);
public
{ Public declarations }
end;
procedure TMyForm.RadioButtonWndProc1(var Message: TMessage);
begin
RadioButtonWndProc(0, Message);
end;
procedure TMyForm.RadioButtonWndProc2(var Message: TMessage);
begin
RadioButtonWndProc(1, Message);
end;
procedure TMyForm.RadioButtonWndProc3(var Message: TMessage);
begin
RadioButtonWndProc(2, Message);
end;
procedure TMyForm.FormShow(Sender: TObject);
var
NewWndProcs: array[0..2] of TWndMethod;
I: Integer;
begin
NewWndProcs[0] := RadioButtonWndProc1;
NewWndProcs[1] := RadioButtonWndProc2;
NewWndProcs[2] := RadioButtonWndProc3;
for I := 0 to 2 do
begin
OriginalWndProcs[I] := RadioGroup1.Buttons[I].WindowProc;
RadioGroup1.Buttons[I].WindowProc := NewWndProcs[I];
end;
end;
procedure TMyForm.RadioButtonWndProc(const Index: Integer; var Message: TMessage);
begin
if (Message.Msg = CN_COMMAND) and
(TWMCommand(Message).NotifyCode = BN_CLICKED) and
(RadioGroup1.Buttons[Index].Checked) then
begin
RadioGroup1.Buttons[Index].Checked := False;
Exit;
end;
OriginalWndProcs[Index](Message);
end;
更新:通过将
TRadioButton
对象直接传递到RadioButtonWndProc()
而无需使用中间代理方法,上述代码可以稍微简化:
type
TMyForm = class(TForm)
RadioGroup1: TRadioGroup;
procedure FormShow(Sender: TObject);
private
{ Private declarations }
OriginalWndProcs: array[0..2] of TWndMethod;
procedure RadioButtonWndProc(var Message: TMessage);
public
{ Public declarations }
end;
procedure TMyForm.FormShow(Sender: TObject);
var
I: Integer;
Btn: TRadioButton;
M: TWndMethod;
begin
for I := 0 to 2 do
begin
Btn := RadioGroup1.Buttons[I];
Btn.Tag := I;
OriginalWndProcs[I] := Btn.WindowProc;
M := RadioButtonWndProc;
TMethod(M).Data := Btn; // <-- makes Self in RadioButtonWndProc() point to the Button instead of the Form...
Btn.WindowProc := M;
end;
end;
procedure TMyForm.RadioButtonWndProc(var Message: TMessage);
var
Btn: TRadioButton;
begin
Btn := TRadioButton(Self);
if (Message.Msg = CN_COMMAND) and
(TWMCommand(Message).NotifyCode = BN_CLICKED) and
(Btn.Checked) then
begin
Btn.Checked := False;
Exit;
end;
MyForm.OriginalWndProcs[Btn.Tag](Message); // <-- note, using the global Form pointer to reach Form members...
end;
尽管如此,我还是不推荐这种UI设计。这根本不是用户期望单选按钮的行为方式。更好的UI选择是使用
TComboBox
,其中第四项用于不选择任何内容。一个TComboBox
比多个单选按钮占用更少的空间,而且它仍然提供用户期望的单一选择行为。这不是Windows单选按钮控件的工作方式。在这种情况下,您确定它是为了规避默认的平台行为吗?我认为,您要么必须为TRadioGroup创建子类,要么在面板中创建一个带有单选按钮的自定义控件。这是一种自定义行为,因此需要自定义组件。组合框怎么样?这不是Windows单选按钮控件的工作方式。在这种情况下,您确定它是为了规避默认的平台行为吗?我认为,您要么必须为TRadioGroup创建子类,要么在面板中创建一个带有单选按钮的自定义控件。这是一种自定义行为,因此需要自定义组件。一个组合框怎么样?当表单有一个无线组时,此代码有效。你能告诉我,当我有超过一个以上的广播组时,如何实施同样的计划吗。Thanks@Amazing. 您针对多个放射组的第一个解决方案对我有效。谢谢!我同意你对combobox的设计。然而,遗憾的是,我只能更改现有项目中的逻辑,而不能更改组件。你能告诉我,当我有超过一个以上的广播组时,如何实施同样的计划吗。Thanks@Amazing. 您针对多个放射组的第一个解决方案对我有效。谢谢!我同意你对combobox的设计。然而,遗憾的是,我只能更改现有项目中的逻辑,而不能更改组件。