LazStats: Remove Cancel button from CanonUnit, improved usability of arrow buttons, create text report in TStringlist, not in OutputFrm. Add help to help file.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7362 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2020-04-07 21:08:21 +00:00
parent 481f65a802
commit ff026810af
4 changed files with 501 additions and 464 deletions

View File

@ -66,84 +66,66 @@ object CannonFrm: TCannonFrm
end
end
object ResetBtn: TButton
AnchorSideRight.Control = CancelBtn
AnchorSideRight.Control = ComputeBtn
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 104
Left = 192
Height = 25
Top = 346
Width = 54
Anchors = [akRight, akBottom]
AutoSize = True
BorderSpacing.Left = 12
BorderSpacing.Left = 8
BorderSpacing.Top = 8
BorderSpacing.Right = 12
BorderSpacing.Right = 8
BorderSpacing.Bottom = 8
Caption = 'Reset'
OnClick = ResetBtnClick
TabOrder = 3
end
object CancelBtn: TButton
AnchorSideRight.Control = ComputeBtn
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 170
Height = 25
Top = 346
Width = 62
Anchors = [akRight, akBottom]
AutoSize = True
BorderSpacing.Left = 12
BorderSpacing.Top = 8
BorderSpacing.Right = 12
BorderSpacing.Bottom = 8
Caption = 'Cancel'
ModalResult = 2
TabOrder = 4
end
object ComputeBtn: TButton
AnchorSideRight.Control = ReturnBtn
AnchorSideRight.Control = CloseBtn
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 244
Left = 254
Height = 25
Top = 346
Width = 76
Anchors = [akRight, akBottom]
AutoSize = True
BorderSpacing.Left = 12
BorderSpacing.Left = 8
BorderSpacing.Top = 8
BorderSpacing.Right = 12
BorderSpacing.Right = 8
BorderSpacing.Bottom = 8
Caption = 'Compute'
OnClick = ComputeBtnClick
TabOrder = 5
TabOrder = 4
end
object ReturnBtn: TButton
object CloseBtn: TButton
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 332
Left = 338
Height = 25
Top = 346
Width = 61
Width = 55
Anchors = [akRight, akBottom]
AutoSize = True
BorderSpacing.Left = 12
BorderSpacing.Left = 8
BorderSpacing.Top = 8
BorderSpacing.Right = 8
BorderSpacing.Bottom = 8
Caption = 'Return'
ModalResult = 1
TabOrder = 6
Caption = 'Close'
ModalResult = 11
TabOrder = 5
end
object HelpBtn: TButton
Tag = 111
AnchorSideRight.Control = ResetBtn
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 41
Left = 133
Height = 25
Top = 346
Width = 51
@ -151,7 +133,7 @@ object CannonFrm: TCannonFrm
AutoSize = True
BorderSpacing.Left = 8
BorderSpacing.Top = 8
BorderSpacing.Right = 12
BorderSpacing.Right = 8
BorderSpacing.Bottom = 8
Caption = 'Help'
OnClick = HelpBtnClick
@ -161,7 +143,7 @@ object CannonFrm: TCannonFrm
AnchorSideLeft.Control = Owner
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = ReturnBtn
AnchorSideBottom.Control = CloseBtn
Left = 0
Height = 8
Top = 330
@ -235,6 +217,7 @@ object CannonFrm: TCannonFrm
Constraints.MinHeight = 220
ItemHeight = 0
MultiSelect = True
OnSelectionChange = VarListSelectionChange
TabOrder = 0
end
object LeftIn: TBitBtn
@ -461,6 +444,8 @@ object CannonFrm: TCannonFrm
BorderSpacing.Right = 8
BorderSpacing.Bottom = 16
ItemHeight = 0
MultiSelect = True
OnSelectionChange = VarListSelectionChange
TabOrder = 3
end
object RightList: TListBox
@ -478,6 +463,8 @@ object CannonFrm: TCannonFrm
Anchors = [akTop, akLeft, akRight, akBottom]
BorderSpacing.Top = 2
ItemHeight = 0
MultiSelect = True
OnSelectionChange = VarListSelectionChange
TabOrder = 6
end
end

View File

@ -1,3 +1,5 @@
// File for testing: cansas.laz
unit CanonUnit;
{$mode objfpc}{$H+}
@ -19,9 +21,8 @@ type
HelpBtn: TButton;
Panel1: TPanel;
ResetBtn: TButton;
CancelBtn: TButton;
ComputeBtn: TButton;
ReturnBtn: TButton;
CloseBtn: TButton;
CorsChk: TCheckBox;
InvChk: TCheckBox;
EigenChk: TCheckBox;
@ -47,9 +48,11 @@ type
procedure ResetBtnClick(Sender: TObject);
procedure RightInClick(Sender: TObject);
procedure RightOutClick(Sender: TObject);
procedure VarListSelectionChange(Sender: TObject; User: boolean);
private
{ private declarations }
FAutoSized: Boolean;
procedure UpdateBtnStates;
public
{ public declarations }
end;
@ -60,54 +63,57 @@ var
implementation
uses
Math;
Math,
Utils;
{ TCannonFrm }
procedure TCannonFrm.ResetBtnClick(Sender: TObject);
VAR i : integer;
var
i: integer;
begin
VarList.Clear;
LeftList.Clear;
RightList.Clear;
LeftOut.Enabled := false;
LeftIn.Enabled := true;
RightOut.Enabled := false;
RightIn.Enabled := true;
for i := 1 to NoVariables do
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]);
UpdateBtnStates;
end;
procedure TCannonFrm.RightInClick(Sender: TObject);
VAR i, index : integer;
var
i: integer;
begin
index := VarList.Items.Count;
i := 0;
while i < index do
while i < VarList.Items.Count do
begin
if (VarList.Selected[i]) then
if VarList.Selected[i] then
begin
RightList.Items.Add(VarList.Items.Strings[i]);
RightList.Items.Add(VarList.Items[i]);
VarList.Items.Delete(i);
index := index - 1;
i := 0;
end
else i := i + 1;
end else
i := i + 1;
end;
RightOut.Enabled := true;
UpdateBtnStates;
end;
procedure TCannonFrm.RightOutClick(Sender: TObject);
VAR index : integer;
var
i: integer;
begin
index := RightList.ItemIndex;
if index < 0 then
i := 0;
while i < RightList.Items.Count do
begin
RightOut.Enabled := false;
exit;
if RightList.Selected[i] then
begin
VarList.Items.Add(RightList.Items[i]);
RightList.Items.Delete(i);
i := 0;
end else
i := i + 1;
end;
VarList.Items.Add(RightList.Items.Strings[index]);
RightList.Items.Delete(index);
UpdateBtnStates;
end;
procedure TCannonFrm.FormActivate(Sender: TObject);
@ -117,12 +123,11 @@ begin
if FAutoSized then
exit;
w := MaxValue([HelpBtn.Width, ResetBtn.Width, CancelBtn.Width, ComputeBtn.Width, ReturnBtn.Width]);
w := MaxValue([HelpBtn.Width, ResetBtn.Width, ComputeBtn.Width, CloseBtn.Width]);
HelpBtn.Constraints.MinWidth := w;
ResetBtn.Constraints.MinWidth := w;
CancelBtn.Constraints.MinWidth := w;
ComputeBtn.Constraints.MinWidth := w;
ReturnBtn.Constraints.MinWidth := w;
CloseBtn.Constraints.MinWidth := w;
Constraints.MinWidth := Width;
Constraints.MinHeight := Height;
@ -133,7 +138,6 @@ end;
procedure TCannonFrm.FormCreate(Sender: TObject);
begin
Assert(OS3MainFrm <> nil);
if OutputFrm = nil then Application.CreateForm(TOutputFrm, OutputFrm);
end;
procedure TCannonFrm.FormShow(Sender: TObject);
@ -149,7 +153,8 @@ begin
end;
procedure TCannonFrm.ComputeBtnClick(Sender: TObject);
label cleanup;
const
SEPARATOR = '===========================================================================';
var
i, j, k, count, a_size, b_size, no_factors, novars, IER: integer;
outline, cellstring, gridstring: string;
@ -165,11 +170,23 @@ var
selected : IntDyneVec;
RowLabels, ColLabels : StrDyneVec;
CanLabels : StrDyneVec;
NCases : integer;
title : string;
errorcode : boolean = false;
NCases: integer = 0;
errorcode: boolean = false;
lReport: TStrings;
begin
if LeftList.Items.Count = 0 then
begin
MessageDlg('No left-hand variable selected.', mtError, [mbOK], 0);
exit;
end;
if RightList.Items.Count = 0 then
begin
MessageDlg('No right-hand variable selected.', mtError, [mbOK], 0);
exit;
end;
k := 0;
no_factors := 0;
pcnt_extracted := 0.0;
@ -249,7 +266,9 @@ begin
end;
end;
end;
for i := 0 to b_size - 1 do // identify left variables
// identify left variables
for i := 0 to b_size - 1 do
begin
cellstring := RightList.Items.Strings[i];
for j := 1 to NoVariables do
@ -264,19 +283,23 @@ begin
end;
// build list of all variables selected
for i := 1 to a_size do selected[i-1] := a_vars[i-1];
for i := 1 to b_size do selected[i-1 + a_size] := b_vars[i-1];
for i := 1 to a_size do
selected[i-1] := a_vars[i-1];
for i := 1 to b_size do
selected[i-1 + a_size] := b_vars[i-1];
lReport := TStringList.Create;
try
lReport.Add('CANONICAL CORRELATION ANALYSIS');
lReport.Add('');
OutputFrm.RichEdit.Clear;
OutputFrm.RichEdit.Lines.Add('CANONICAL CORRELATION ANALYSIS');
OutputFrm.RichEdit.Lines.Add('');
// Get means, standard deviations, etc. for total matrix
Correlations(novars,selected,bigmat,mean,variance,stddev,errorcode,Ncases);
count := Ncases;
if (IER = 1)then
begin
ShowMessage('Zero variance found for a variable-terminating');
goto cleanup;
MessageDlg('Zero variance found for a variable-terminating', mtError, [mbOK], 0);
exit;
end;
//partition matrix into quadrants
@ -298,24 +321,25 @@ begin
if CorsChk.Checked then
begin
title := 'Left Correlation Matrix';
MAT_PRINT(raa,a_size,a_size,title,RowLabels,RowLabels,NCases);
MatPrint(raa, a_size, a_size, title, RowLabels, RowLabels, NCases, lReport);
title := 'Right Correlation Matrix';
MAT_PRINT(rbb,b_size,b_size,title,ColLabels,ColLabels,NCases);
MatPrint(rbb, b_size, b_size, title, ColLabels, ColLabels, NCases, lReport);
title := 'Left-Right Correlation Matrix';
MAT_PRINT(rab,a_size,b_size,title,RowLabels,ColLabels,NCases);
OutputFrm.ShowModal;
OutputFrm.RichEdit.Clear;
MatPrint(rab, a_size, b_size, title, RowLabels, ColLabels, NCases, lReport);
lReport.Add('');
lReport.Add(SEPARATOR);
lReport.Add('');
end;
// get inverses of left and right hand matrices raa and rbb
for i := 1 to a_size do
for j := 1 to a_size do
raainv[i-1,j-1] := raa[i-1,j-1];
SVDinverse(raainv,a_size);
SVDinverse(raainv, a_size);
if InvChk.Checked then
begin
title := 'Inverse of Left Matrix';
MAT_PRINT(raainv,a_size,a_size,title,RowLabels,RowLabels,NCases);
MatPrint(raainv, a_size, a_size, title, RowLabels, RowLabels, NCases, lReport);
end;
for i := 1 to b_size do
@ -325,24 +349,26 @@ begin
if InvChk.Checked then
begin
title := 'Inverse of Right Matrix';
MAT_PRINT(rbbinv,b_size,b_size,title,ColLabels,ColLabels,NCases);
MatPrint(rbbinv, b_size, b_size, title, ColLabels, ColLabels, NCases, lReport);
end;
// get products of raainv x rab and the rbbinv x rba matrix
MatAxB(first_prod,rbbinv,rba,b_size,b_size,b_size,a_size,errorcode);
MatAxB(second_prod,raainv,rab,a_size,a_size,a_size,b_size,errorcode);
title := 'Right Inverse x Right-Left Matrix';
MAT_PRINT(first_prod,b_size,a_size,title,ColLabels,RowLabels,NCases);
MatPrint(first_prod, b_size, a_size, title, ColLabels, RowLabels, NCases, lReport);
title := 'Left Inverse x Left-Right Matrix';
MAT_PRINT(second_prod,a_size,b_size,title,RowLabels,ColLabels,NCases);
MatPrint(second_prod, a_size, b_size, title, RowLabels, ColLabels, NCases, lReport);
//get characteristic equations matrix (product of last two product matrices
//The product should yeild rows and cols representing the smaller of the two sets
MatAxB(char_equation,first_prod,second_prod,b_size,a_size, a_size,b_size,errorcode);
title := 'Canonical Function';
MAT_PRINT(char_equation,b_size,b_size,title,CanLabels,CanLabels,NCases);
OutputFrm.ShowModal;
OutputFrm.RichEdit.Clear;
MatPrint(char_equation, b_size, b_size, title, CanLabels, CanLabels, NCases, lReport);
lReport.Add('');
lReport.Add(SEPARATOR);
lReport.Add('');
// now get roots and vectors of the characteristic equation using
// NonSymRoots routine
@ -357,13 +383,11 @@ begin
no_factors := b_size;
nonsymroots(char_equation, b_size, no_factors, minroot, eigenvectors, roots,
pcnt_trace, trace, pcnt_extracted);
outline := format('Trace of the matrix:=%10.4f',[trace]);
OutputFrm.RichEdit.Lines.Add(outline);
outline := format('Percent of trace extracted: %10.4f',[pcnt_extracted]);
OutputFrm.RichEdit.Lines.Add(outline);
lReport.Add('Trace of the matrix: %10.4f', [trace]);
lReport.Add('Percent of trace extracted: %10.4f', [pcnt_extracted]);
// Normalize smaller set weights and coumpute larger set weights
MATTRN(eigentrans,eigenvectors,b_size,b_size);
MatTrn(eigentrans, eigenvectors, b_size, b_size);
MatAxB(tempmat,eigentrans,rbb,b_size,b_size,b_size,b_size,errorcode);
MatAxB(theta,tempmat,eigenvectors,b_size,b_size,b_size,b_size,errorcode);
for j := 1 to b_size do
@ -443,24 +467,21 @@ begin
end;
// Print remaining results
OutputFrm.RichEdit.Lines.Add('');
OutputFrm.RichEdit.Lines.Add('');
outline := ' Canonical R Root % Trace Chi-Sqr D.F. Prob.';
OutputFrm.RichEdit.Lines.Add(outline);
lReport.Add(' Canonical R Root % Trace Chi-Sqr D.F. Prob. ');
lReport.Add('-- ----------- -------- --------- --------- ---- --------');
for i := 1 to b_size do
begin
outline := format('%2d %10.6f %8.3f %7.3f %8.3f %2d %8.3f',
[i, sqrt(roots[i-1]), roots[i-1], pcnt_trace[i-1], root_chi[i-1], root_df[i-1], chi_prob[i-1]]);
OutputFrm.RichEdit.Lines.Add(outline);
end;
lReport.Add('%2d %11.6f %8.3f %9.3f %9.3f %4d %8.3f',
[i, sqrt(roots[i-1]), roots[i-1], pcnt_trace[i-1], root_chi[i-1], root_df[i-1], chi_prob[i-1]]
);
chisqr := -ln(Lambda) * (count - 1.0 - 0.5 * (a_size + b_size - 1.0));
chiprob := 1.0 - chisquaredprob(chisqr,a_size * b_size);
OutputFrm.RichEdit.Lines.Add('');
OutputFrm.RichEdit.Lines.Add('Overall Tests of Significance:');
OutputFrm.RichEdit.Lines.Add(' Statistic Approx. Stat. Value D.F. Prob.>Value');
outline := format('Wilk''s Lambda Chi-Squared %10.4f %3d %6.4f',
[chisqr,a_size * b_size,chiprob]);
OutputFrm.RichEdit.Lines.Add(outline);
lReport.Add('');
lReport.Add('Overall Tests of Significance:');
lReport.Add('');
lReport.Add(' Statistic Approx. Stat. Value D.F. Prob > Value');
lReport.Add('------------------------- -------------- ---------- ----- ------------');
lReport.Add('Wilk''s Lambda Chi-Squared %10.4f %3d %12.4f', [chisqr, a_size * b_size, chiprob]);
s := b_size;
m := 0.5 * (a_size - b_size - 1);
n := 0.5 * (count - b_size - a_size - 2);
@ -468,80 +489,88 @@ begin
df1 := s * (2.0 * m + s + 1.0);
df2 := 2.0 * ( s * n + 1.0);
ftestprob := probf(f,df1,df2);
outline := format('Hotelling-Lawley Trace F-Test %10.4f %2.0f %2.0f %6.4f',
[f, df1,df2, ftestprob]);
OutputFrm.RichEdit.Lines.Add(outline);
lReport.Add('Hotelling-Lawley Trace F-Test %10.4f %2.0f %2.0f %12.4f', [f, df1,df2, ftestprob]);
df2 := s * (2.0 * n + s + 1.0);
f := (Pillia / (s - Pillia)) * ( (2.0 * n + s +1.0) / (2.0 * m + s + 1.0) );
ftestprob := probf(f,df1,df2);
outline := format('Pillai Trace F-Test %10.4f %2.0f %2.0f %6.4f',
[f, df1,df2, ftestprob]);
OutputFrm.RichEdit.Lines.Add(outline);
lReport.Add('Pillai Trace F-Test %10.4f %2.0f %2.0f %12.4f', [f, df1,df2, ftestprob]);
Roys := Roys * (count - 1 - a_size + b_size)/ a_size ;
df1 := a_size;
df2 := count - 1 - a_size + b_size;
ftestprob := probf(Roys,df1,df2);
outline := format('Roys Largest Root F-Test %10.4f %2.0f %2.0f %6.4f',
[Roys, df1, df2, ftestprob]);
OutputFrm.RichEdit.Lines.Add(outline);
OutputFrm.ShowModal;
OutputFrm.RichEdit.Clear;
lReport.Add('Roys Largest Root F-Test %10.4f %2.0f %2.0f %12.4f', [Roys, df1, df2, ftestprob]);
lReport.Add('');
lReport.Add(SEPARATOR);
lReport.Add('');
if EigenChk.Checked then
begin
title := 'Eigenvectors';
MAT_PRINT(eigenvectors,b_size,b_size,title,CanLabels,CanLabels,NCases);
OutputFrm.ShowModal();
OutputFrm.RichEdit.Clear;
MatPrint(eigenvectors, b_size, b_size, title, CanLabels, CanLabels, NCases, lReport);
lReport.Add('');
lReport.Add(SEPARATOR);
lReport.Add('');
end;
title := 'Standardized Right Side Weights';
MAT_PRINT(norm_a,a_size,b_size,title,RowLabels,CanLabels,NCases);
MatPrint(norm_a, a_size, b_size, title, RowLabels, CanLabels, NCases, lReport);
title := 'Standardized Left Side Weights';
MAT_PRINT(norm_b,b_size,b_size,title,ColLabels,CanLabels,NCases);
OutputFrm.ShowModal;
OutputFrm.RichEdit.Clear;
MatPrint(norm_b, b_size, b_size, title, ColLabels, CanLabels, NCases, lReport);
lReport.Add('');
lReport.Add(SEPARATOR);
lReport.Add('');
title := 'Raw Right Side Weights';
MAT_PRINT(raw_a,a_size,b_size,title,RowLabels,CanLabels,NCases);
MatPrint(raw_a, a_size, b_size, title, RowLabels, CanLabels, NCases, lReport);
title := 'Raw Left Side Weights';
MAT_PRINT(raw_b,b_size,b_size,title,ColLabels,CanLabels,NCases);
OutputFrm.ShowModal;
OutputFrm.RichEdit.Clear;
MatPrint(raw_b, b_size, b_size, title, ColLabels, CanLabels, NCases, lReport);
lReport.Add('');
lReport.Add(SEPARATOR);
lReport.Add('');
title := 'Right Side Correlations with Function';
MAT_PRINT(a_cors,a_size,b_size,title,RowLabels,CanLabels,NCases);
MatPrint(a_cors, a_size, b_size, title, RowLabels, CanLabels, NCases, lReport);
title := 'Left Side Correlations with Function';
MAT_PRINT(b_cors,b_size,b_size,title,ColLabels,CanLabels,NCases);
OutputFrm.ShowModal;
OutputFrm.RichEdit.Clear;
MatPrint(b_cors, b_size, b_size, title, ColLabels, CanLabels, NCases, lReport);
lReport.Add('');
lReport.Add(SEPARATOR);
lReport.Add('');
if RedundChk.Checked then
begin
outline := 'Redundancy Analysis for Right Side Variables';
OutputFrm.RichEdit.Lines.Add(outline);
OutputFrm.RichEdit.Lines.Add('');
outline := ' Variance Prop. Redundancy';
OutputFrm.RichEdit.Lines.Add(outline);
lReport.Add('Redundancy Analysis for Right Side Variables');
lReport.Add('');
lReport.Add(' Variance Prop. Redundancy ');
lReport.Add('---------- --------------- ---------------');
for i := 1 to b_size do
begin
outline := format('%10d %10.5f %10.5f',[i,pv_a[i-1],rd_a[i-1]]);
OutputFrm.RichEdit.Lines.Add(outline);
end;
OutputFrm.RichEdit.Lines.Add('');
outline := 'Redundancy Analysis for Left Side Variables';
OutputFrm.RichEdit.Lines.Add(outline);
outline := ' Variance Prop. Redundancy';
OutputFrm.RichEdit.Lines.Add(outline);
lReport.Add('%8d %15.5f %12.5f', [i, pv_a[i-1], rd_a[i-1]]);
lReport.Add('');
lReport.Add('Redundancy Analysis for Left Side Variables');
lReport.Add('');
lReport.Add(' Variance Prop. Redundancy ');
lReport.Add('---------- --------------- ------------');
for i := 1 to b_size do
begin
outline := format('%10d %10.5f %10.5f',[i,pv_b[i-1],rd_b[i-1]]);
OutputFrm.RichEdit.Lines.Add(outline);
end;
OutputFrm.ShowModal;
OutputFrm.RichEdit.Clear;
lReport.Add('%8d %15.5f %12.5f', [i, pv_b[i-1], rd_b[i-1]]);
lReport.Add('');
lReport.Add(SEPARATOR);
lReport.Add('');
end;
//------------- Now, clean up memory mess ----------------------------
cleanup:
DisplayReport(lReport);
finally
lReport.Free;
Selected := nil;
ColLabels := nil;
RowLabels := nil;
@ -580,38 +609,59 @@ cleanup:
rab := nil;
rbb := nil;
raa := nil;
end;
end;
procedure TCannonFrm.LeftInClick(Sender: TObject);
VAR i, index : integer;
var
i: integer;
begin
index := VarList.Items.Count;
i := 0;
while i < index do
while i < VarList.Items.Count do
begin
if (VarList.Selected[i]) then
if VarList.Selected[i] then
begin
LeftList.Items.Add(VarList.Items.Strings[i]);
LeftList.Items.Add(VarList.Items[i]);
VarList.Items.Delete(i);
index := index - 1;
i := 0;
end
else i := i + 1;
end else
i := i + 1;
end;
LeftOut.Enabled := true;
UpdateBtnStates;
end;
procedure TCannonFrm.LeftOutClick(Sender: TObject);
VAR index : integer;
var
i: integer;
begin
index := LeftList.ItemIndex;
if index < 0 then
i := 0;
while i < LeftList.Items.Count do
begin
LeftOut.Enabled := false;
exit;
if LeftList.Selected[i] then
begin
VarList.Items.Add(LeftList.Items[i]);
LeftList.Items.Delete(i);
i := 0;
end else
i := i + 1;
end;
VarList.Items.Add(LeftList.Items.Strings[index]);
LeftList.Items.Delete(index);
UpdateBtnStates;
end;
procedure TCannonFrm.VarListSelectionChange(Sender: TObject; User: boolean);
begin
UpdateBtnStates;
end;
procedure TCannonFrm.UpdateBtnStates;
var
lSelected: Boolean;
begin
lSelected := AnySelected(Varlist);
LeftIn.Enabled := lSelected;
RightIn.Enabled := lSelected;
LeftOut.Enabled := AnySelected(LeftList);
RightOut.Enabled := AnySelected(RightList);
end;
initialization