DirectSound 3D 特效相关接口: IDirectSound3DBuffer8、IDirectSound3DListener8.
IDirectSound3DBuffer8 是声源, 它可以有一个或多个; IDirectSound3DListener8 是听者, 它只能有一个.
IDirectSound3DBuffer8 通过 QueryInterface() 从次缓冲获取, 要求该次缓冲建立时必须指定 DSBCAPS_CTRL3D;
IDirectSound3DListener8 通过 QueryInterface() 从主缓冲区获取, 该主缓冲区建立时也必须指定 DSBCAPS_CTRL3D.
"声源" 和 "听者" 可以交互变换, 也可独立变换; 只变换 "听者" 时, 提供声音的缓冲区建立时也应该指定 DSBCAPS_CTRL3D.
IDirectSound3DBuffer8 其实只负责 3D 效果变换, 真正提供声音和播放控制的还是它之前的 IDirectSound3DBuffer 或 IDirectSound3DBuffer8.
IDirectSound3DBuffer8 相关方法:
{3D 音效处理模式}
GetMode()、SetMode()
DS3DMODE_NORMAL = $00000000; //普通
DS3DMODE_HEADRELATIVE = $00000001; //声源的参数是相对于听者的
DS3DMODE_DISABLE = $00000002; //禁用 3D 特效
{最大、最小距离}
GetMaxDistance()、SetMaxDistance()
GetMinDistance()、SetMinDistance()
{位置、速度、方向}
GetPosition()、SetPosition()
GetVelocity()、SetVelocity()
GetConeOrientation()、SetConeOrientation()
{声源椎参数}
GetConeAngles()、SetConeAngles()
GetConeOutsideVolume()、SetConeOutsideVolume()
{一起获取或设置参数}
GetAllParameters()、SetAllParameters()
IDirectSound3DListener8 相关方法:
{位置、速度、方向}
GetPosition()、SetPosition()
GetVelocity()、SetVelocity()
GetOrientation()、SetOrientation()
{距离因子、多普勒因子、滚降因子}
GetDistanceFactor()、SetDistanceFactor()
GetDopplerFactor()、SetDopplerFactor()
GetRolloffFactor()、SetRolloffFactor()
{一起获取或设置参数}
GetAllParameters()、SetAllParameters()
{延迟设置}
CommitDeferredSettings() //在使用系列 Set... 方法时, 如果指定了 DS3D_DEFERRED 参数, 则需用该方法提交参数设置;
//和 DS3D_DEFERRED = 1 对应的是 DS3D_IMMEDIATE = 0, 表示立即生效; 使用延迟设置更节省资源.
测试代码(测试文件须是单声道的 Wave):
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
RadioGroup1: TRadioGroup;
RadioGroup2: TRadioGroup;
GroupBox1: TGroupBox;
LabeledEdit1: TLabeledEdit;
LabeledEdit2: TLabeledEdit;
LabeledEdit3: TLabeledEdit;
LabeledEdit4: TLabeledEdit;
LabeledEdit5: TLabeledEdit;
LabeledEdit6: TLabeledEdit;
LabeledEdit7: TLabeledEdit;
LabeledEdit8: TLabeledEdit;
LabeledEdit9: TLabeledEdit;
LabeledEdit10: TLabeledEdit;
LabeledEdit11: TLabeledEdit;
LabeledEdit12: TLabeledEdit;
LabeledEdit13: TLabeledEdit;
LabeledEdit14: TLabeledEdit;
GroupBox2: TGroupBox;
LabeledEdit15: TLabeledEdit;
LabeledEdit16: TLabeledEdit;
LabeledEdit17: TLabeledEdit;
LabeledEdit18: TLabeledEdit;
LabeledEdit19: TLabeledEdit;
LabeledEdit20: TLabeledEdit;
LabeledEdit21: TLabeledEdit;
LabeledEdit22: TLabeledEdit;
LabeledEdit23: TLabeledEdit;
LabeledEdit24: TLabeledEdit;
LabeledEdit25: TLabeledEdit;
LabeledEdit26: TLabeledEdit;
LabeledEdit27: TLabeledEdit;
LabeledEdit28: TLabeledEdit;
LabeledEdit29: TLabeledEdit;
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure LabeledEdit1KeyPress(Sender: TObject; var Key: Char);
procedure LabeledEdit1Change(Sender: TObject);
procedure LabeledEdit15Change(Sender: TObject);
procedure RadioGroup1Click(Sender: TObject);
procedure RadioGroup2Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses DirectSound, ReadWave2; //ReadWave2 是前面(9)自定义的单元
var
myDSound: IDirectSound8;
buf: IDirectSoundBuffer;
buf3D: IDirectSound3DBuffer8; //3D声源
Listener: IDirectSound3DListener8;
dwApply: DWORD = DS3D_IMMEDIATE; //0
{建立 IDirectSound8、IDirectSound3DListener8}
procedure TForm1.FormCreate(Sender: TObject);
var
bufDesc: TDSBufferDesc;
bufPrimary: IDirectSoundBuffer; //这里的主缓冲区只是个临时的桥
begin
System.ReportMemoryLeaksOnShutdown := true;
DirectSoundCreate8(nil, myDSound, nil);
myDSound.SetCooperativeLevel(Handle, DSSCL_PRIORITY); //要用到主缓冲区, 所以使用 DSSCL_PRIORITY 级别
ZeroMemory(@bufDesc, SizeOf(TDSBufferDesc));
bufDesc.dwSize := SizeOf(TDSBufferDesc);
bufDesc.dwFlags := DSBCAPS_PRIMARYBUFFER or DSBCAPS_CTRL3D; //标识是主缓冲区、同时准备使用 3D 特效
bufDesc.dwBufferBytes := 0;
bufDesc.lpwfxFormat := nil;
bufDesc.guid3DAlgorithm := DS3DALG_DEFAULT; //主缓冲区在 DSBCAPS_CTRL3D 模式下可以启用这个选项
myDSound.CreateSoundBuffer(bufDesc, bufPrimary, nil);
bufPrimary.QueryInterface(IID_IDirectSound3DListener8, Listener);
//bufPrimary := nil;
end;
{建立 IDirectSoundBuffer、IDirectSound3DBuffer8, 并载入播放资源}
procedure TForm1.Button1Click(Sender: TObject);
var
wav: TReadWave;
bufDesc: TDSBufferDesc;
p1: Pointer;
n1: DWORD;
begin
Self.OnShow(nil);
wav := TReadWave.Create;
{如果打开失败或不是单声道则退出}
if not wav.OpenDialog or (wav.Format.nChannels <> 1) then
begin
wav.Free;
Exit;
end;
ZeroMemory(@bufDesc, SizeOf(bufDesc));
bufDesc.dwSize := SizeOf(bufDesc);
bufDesc.dwFlags := DSBCAPS_STATIC or DSBCAPS_CTRL3D;
bufDesc.dwBufferBytes := wav.Size;
bufdesc.lpwfxFormat := @wav.Format;
myDSound.CreateSoundBuffer(bufDesc, buf, nil);
buf.QueryInterface(IID_IDirectSound3DBuffer8, buf3D);
buf.Lock(0, 0, @p1, @n1, nil, nil, DSBLOCK_ENTIREBUFFER);
wav.Read(p1, wav.Size);
wav.Free;
buf.Unlock(p1, n1, nil, 0);
buf.Play(0, 0, DSBPLAY_LOOPING);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if buf <> nil then buf.Stop;
end;
{初始化控件及默认值}
procedure TForm1.FormShow(Sender: TObject);
var
i: Integer;
begin
Button1.Caption := '打开并播放';
Button2.Caption := '停止播放';
RadioGroup1.Caption := 'Mode:';
RadioGroup1.Items.CommaText := 'DS3DMODE_NORMAL, DS3DMODE_HEADRELATIVE, DS3DMODE_DISABLE';
RadioGroup1.ItemIndex := 0;
RadioGroup2.Caption := 'Apply:';
RadioGroup2.Items.CommaText := 'DS3D_IMMEDIATE, DS3D_DEFERRED';
RadioGroup2.ItemIndex := dwApply;
GroupBox1.Caption := '声源控制:';
LabeledEdit1.EditLabel.Caption := 'Position-X:';
LabeledEdit2.EditLabel.Caption := 'Position-Y:';
LabeledEdit3.EditLabel.Caption := 'Position-Z:';
LabeledEdit1.Text := '0.0';
LabeledEdit2.Text := '0.0';
LabeledEdit3.Text := '0.0';
LabeledEdit4.EditLabel.Caption := 'Velocity-X:';
LabeledEdit5.EditLabel.Caption := 'Velocity-Y:';
LabeledEdit6.EditLabel.Caption := 'Velocity-Z:';
LabeledEdit4.Text := '0.0';
LabeledEdit5.Text := '0.0';
LabeledEdit6.Text := '0.0';
LabeledEdit7.EditLabel.Caption := 'Orientation-X:';
LabeledEdit8.EditLabel.Caption := 'Orientation-Y:';
LabeledEdit9.EditLabel.Caption := 'Orientation-Z:';
LabeledEdit7.Text := '0.0';
LabeledEdit8.Text := '0.0';
LabeledEdit9.Text := '1.0';
LabeledEdit10.EditLabel.Caption := 'Min:';
LabeledEdit11.EditLabel.Caption := 'Max:';
LabeledEdit10.Text := '0.0';
LabeledEdit11.Text := '1000000000.0';
LabeledEdit12.EditLabel.Caption := 'Volume:';
LabeledEdit12.Text := '0';
LabeledEdit13.EditLabel.Caption := 'InsideConeAngle:';
LabeledEdit14.EditLabel.Caption := 'OutsideConeAngle:';
LabeledEdit13.Text := '360';
LabeledEdit14.Text := '360';
//
GroupBox2.Caption := '听者控制:';
LabeledEdit15.EditLabel.Caption := 'Position-X:';
LabeledEdit16.EditLabel.Caption := 'Position-Y:';
LabeledEdit17.EditLabel.Caption := 'Position-Z:';
LabeledEdit15.Text := '0.0';
LabeledEdit16.Text := '0.0';
LabeledEdit17.Text := '0.0';
LabeledEdit18.EditLabel.Caption := 'Velocity-X:';
LabeledEdit19.EditLabel.Caption := 'Velocity-Y:';
LabeledEdit20.EditLabel.Caption := 'Velocity-Z:';
LabeledEdit18.Text := '0.0';
LabeledEdit19.Text := '0.0';
LabeledEdit20.Text := '0.0';
LabeledEdit21.EditLabel.Caption := 'Orientation-xFront:';
LabeledEdit22.EditLabel.Caption := 'Orientation-yFront:';
LabeledEdit23.EditLabel.Caption := 'Orientation-zFront:';
LabeledEdit21.Text := '0.0';
LabeledEdit22.Text := '0.0';
LabeledEdit23.Text := '1.0';
LabeledEdit24.EditLabel.Caption := 'Orientation-xTop:';
LabeledEdit25.EditLabel.Caption := 'Orientation-yTop:';
LabeledEdit26.EditLabel.Caption := 'Orientation-zTop:';
LabeledEdit24.Text := '0.0';
LabeledEdit25.Text := '1.0';
LabeledEdit26.Text := '0.0';
LabeledEdit27.EditLabel.Caption := 'DistanceFactor:';
LabeledEdit28.EditLabel.Caption := 'DopplerFactor:';
LabeledEdit29.EditLabel.Caption := 'RolloffFactor:';
LabeledEdit27.Text := '1.0';
LabeledEdit28.Text := '1.0';
LabeledEdit29.Text := '1.0';
for i := 0 to self.ComponentCount - 1 do
begin
if Components[i].ClassNameIs('TLabeledEdit') then
begin
TLabeledEdit(Components[i]).OnKeyPress := LabeledEdit1.OnKeyPress;
if TLabeledEdit(Components[i]).Parent = GroupBox1 then TLabeledEdit(Components[i]).OnChange := LabeledEdit1.OnChange;
if TLabeledEdit(Components[i]).Parent = GroupBox2 then TLabeledEdit(Components[i]).OnChange := LabeledEdit15.OnChange;
end;
end;
end;
{限制测试数据}
procedure TForm1.LabeledEdit1KeyPress(Sender: TObject; var Key: Char);
begin
Self.Caption := TLabeledEdit(Sender).Name;
if not CharInSet(Key, ['-', '.', '0'..'9', #8]) then Key := #0;
end;
{声源变换时}
procedure TForm1.LabeledEdit1Change(Sender: TObject);
var
str: string;
begin
if buf3D = nil then Exit;
str := TLabeledEdit(Sender).Text;
if (str = '-') or (str = '.') or (str = '') then Exit;
buf3D.SetPosition(StrToFloat(LabeledEdit1.Text),
StrToFloat(LabeledEdit2.Text),
StrToFloat(LabeledEdit3.Text), dwApply);
buf3D.SetVelocity(StrToFloat(LabeledEdit4.Text),
StrToFloat(LabeledEdit5.Text),
StrToFloat(LabeledEdit6.Text), dwApply);
buf3D.SetConeOrientation(StrToFloat(LabeledEdit7.Text),
StrToFloat(LabeledEdit8.Text),
StrToFloat(LabeledEdit9.Text), dwApply);
buf3D.SetMinDistance(StrToFloat(LabeledEdit10.Text), dwApply);
buf3D.SetMaxDistance(StrToFloat(LabeledEdit11.Text), dwApply);
buf3D.SetConeOutsideVolume(StrToInt(LabeledEdit12.Text), dwApply);
buf3D.SetConeAngles(StrToInt(LabeledEdit13.Text), StrToInt(LabeledEdit14.Text), dwApply);
if (dwApply = DS3D_DEFERRED) and Assigned(Listener) then Listener.CommitDeferredSettings;
end;
{听者变换时}
procedure TForm1.LabeledEdit15Change(Sender: TObject);
var
str: string;
rVector: TD3DVector;
begin
if (buf = nil) or (Listener = nil) then Exit;
str := TLabeledEdit(Sender).Text;
if (str = '-') or (str = '.') or (str = '') then Exit;
Listener.SetPosition(StrToFloat(LabeledEdit15.Text),
StrToFloat(LabeledEdit16.Text),
StrToFloat(LabeledEdit17.Text), dwApply);
Listener.SetVelocity(StrToFloat(LabeledEdit18.Text),
StrToFloat(LabeledEdit19.Text),
StrToFloat(LabeledEdit20.Text), dwApply);
Listener.SetOrientation(StrToFloat(LabeledEdit21.Text),
StrToFloat(LabeledEdit22.Text),
StrToFloat(LabeledEdit23.Text),
StrToFloat(LabeledEdit24.Text),
StrToFloat(LabeledEdit25.Text),
StrToFloat(LabeledEdit26.Text), dwApply);
Listener.SetDistanceFactor(StrToFloat(LabeledEdit27.Text), dwApply);
Listener.SetDopplerFactor(StrToFloat(LabeledEdit28.Text), dwApply);
Listener.SetRolloffFactor(StrToFloat(LabeledEdit29.Text), dwApply);
if dwApply = DS3D_DEFERRED then Listener.CommitDeferredSettings;
end;
{3D 音效模式}
procedure TForm1.RadioGroup1Click(Sender: TObject);
begin
if Assigned(buf3D) then buf3D.SetMode(RadioGroup1.ItemIndex, dwApply);
if (dwApply = DS3D_DEFERRED) and Assigned(Listener) then Listener.CommitDeferredSettings;
end;
{是否延迟设置; 此变化内在的, 应该不会被觉察}
procedure TForm1.RadioGroup2Click(Sender: TObject);
var
i: Integer;
begin
if buf3D = nil then Exit;
dwApply := TRadioGroup(Sender).ItemIndex;
for i := 0 to self.ComponentCount - 1 do if Components[i].ClassNameIs('TLabeledEdit') then
TLabeledEdit(Components[i]).OnChange(TLabeledEdit(Components[i]));
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
buf := nil;
buf3D := nil;
Listener := nil;
myDSound := nil;
end;
end.
窗体设计:
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 459
ClientWidth = 759
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
OnDestroy = FormDestroy
OnShow = FormShow
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 23
Top = 40
Width = 75
Height = 49
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object Button2: TButton
Left = 104
Top = 40
Width = 75
Height = 49
Caption = 'Button2'
TabOrder = 1
OnClick = Button2Click
end
object GroupBox1: TGroupBox
Left = 8
Top = 134
Width = 353
Height = 317
Caption = 'GroupBox1'
TabOrder = 2
object LabeledEdit1: TLabeledEdit
Left = 16
Top = 42
Width = 97
Height = 21
EditLabel.Width = 61
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit1'
TabOrder = 0
OnChange = LabeledEdit1Change
OnKeyPress = LabeledEdit1KeyPress
end
object LabeledEdit2: TLabeledEdit
Left = 128
Top = 42
Width = 97
Height = 21
EditLabel.Width = 61
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit2'
TabOrder = 1
end
object LabeledEdit3: TLabeledEdit
Left = 240
Top = 42
Width = 97
Height = 21
EditLabel.Width = 61
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit3'
TabOrder = 2
end
object LabeledEdit4: TLabeledEdit
Left = 16
Top = 90
Width = 97
Height = 21
EditLabel.Width = 61
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit4'
TabOrder = 3
end
object LabeledEdit5: TLabeledEdit
Left = 128
Top = 90
Width = 97
Height = 21
EditLabel.Width = 61
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit5'
TabOrder = 4
end
object LabeledEdit6: TLabeledEdit
Left = 240
Top = 90
Width = 97
Height = 21
EditLabel.Width = 61
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit6'
TabOrder = 5
end
object LabeledEdit7: TLabeledEdit
Left = 16
Top = 138
Width = 97
Height = 21
EditLabel.Width = 61
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit7'
TabOrder = 6
end
object LabeledEdit8: TLabeledEdit
Left = 128
Top = 138
Width = 97
Height = 21
EditLabel.Width = 61
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit8'
TabOrder = 7
end
object LabeledEdit9: TLabeledEdit
Left = 240
Top = 138
Width = 97
Height = 21
EditLabel.Width = 61
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit9'
TabOrder = 8
end
object LabeledEdit10: TLabeledEdit
Left = 16
Top = 186
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit10'
TabOrder = 9
end
object LabeledEdit11: TLabeledEdit
Left = 128
Top = 186
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit11'
TabOrder = 10
end
object LabeledEdit12: TLabeledEdit
Left = 16
Top = 234
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit12'
TabOrder = 11
end
object LabeledEdit13: TLabeledEdit
Left = 16
Top = 282
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit13'
TabOrder = 12
end
object LabeledEdit14: TLabeledEdit
Left = 128
Top = 285
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit14'
TabOrder = 13
end
end
object GroupBox2: TGroupBox
Left = 390
Top = 136
Width = 355
Height = 315
Caption = 'GroupBox2'
TabOrder = 3
object LabeledEdit15: TLabeledEdit
Left = 16
Top = 42
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit15'
TabOrder = 0
OnChange = LabeledEdit15Change
end
object LabeledEdit16: TLabeledEdit
Left = 127
Top = 42
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit16'
TabOrder = 1
end
object LabeledEdit17: TLabeledEdit
Left = 240
Top = 42
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit17'
TabOrder = 2
end
object LabeledEdit18: TLabeledEdit
Left = 16
Top = 106
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit18'
TabOrder = 3
end
object LabeledEdit19: TLabeledEdit
Left = 128
Top = 106
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit19'
TabOrder = 4
end
object LabeledEdit20: TLabeledEdit
Left = 240
Top = 106
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit20'
TabOrder = 5
end
object LabeledEdit21: TLabeledEdit
Left = 16
Top = 170
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit21'
TabOrder = 6
end
object LabeledEdit22: TLabeledEdit
Left = 128
Top = 170
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit22'
TabOrder = 7
end
object LabeledEdit23: TLabeledEdit
Left = 240
Top = 170
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit23'
TabOrder = 8
end
object LabeledEdit24: TLabeledEdit
Left = 16
Top = 218
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit24'
TabOrder = 9
end
object LabeledEdit25: TLabeledEdit
Left = 128
Top = 218
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit25'
TabOrder = 10
end
object LabeledEdit26: TLabeledEdit
Left = 240
Top = 218
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit26'
TabOrder = 11
end
object LabeledEdit27: TLabeledEdit
Left = 16
Top = 282
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit27'
TabOrder = 12
end
object LabeledEdit28: TLabeledEdit
Left = 128
Top = 282
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit28'
TabOrder = 13
end
object LabeledEdit29: TLabeledEdit
Left = 240
Top = 282
Width = 97
Height = 21
EditLabel.Width = 67
EditLabel.Height = 13
EditLabel.Caption = 'LabeledEdit29'
TabOrder = 14
end
end
object RadioGroup1: TRadioGroup
Left = 200
Top = 17
Width = 281
Height = 98
Caption = 'RadioGroup1'
TabOrder = 4
OnClick = RadioGroup1Click
end
object RadioGroup2: TRadioGroup
Left = 504
Top = 17
Width = 241
Height = 96
Caption = 'RadioGroup2'
TabOrder = 5
OnClick = RadioGroup2Click
end
end
运行效果图: