I'm pretty new to Delphi and am attempting to use different units to store TLists and TObjects, as well as generate other combobox options based on previous combobox selections. I am receiving the following error messages immediately after running:
Project Project1.exe raised exception class $C0000005 with message 'access violation at 0x004087d7: read of address 0x00000000
Access violation at address 00408813 in module 'Project1.exe'. Read of address 00000000.
I've traced through the steps in the debugging tool but I can't see why it won't work. I have googled the issue and have found a few solutions but nothing that seems like it applies to my current problem.
unit MainForm;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TfMain = class(TForm)
lCPU: TLabel;
cbCPU: TComboBox;
lGPU: TLabel;
cbGPU: TComboBox;
lMotherboard: TLabel;
cbMotherboard: TComboBox;
lRAM: TLabel;
cbRAM: TComboBox;
eCompatible: TEdit;
lCompatible: TLabel;
eCost: TEdit;
lCost: TLabel;
Label11: TLabel;
lbCPU: TListBox;
lbMotherboard: TListBox;
lbGPU: TListBox;
lbRAM: TListBox;
procedure FormShow(Sender: TObject);
procedure cbCPUChange(Sender: TObject);
private
{ Private declarations }
public
// procedure cbCPUpopulate();
end;
type TGPU = class(TObject)
public
name : string;
vram : integer;
clock : integer;
price : string;
end;
type TCPU = class(TObject)
public
name : string;
cores : integer;
clock : real;
intel : boolean;
amd : boolean;
price : string;
end;
type TMobo = class(TObject)
public
name : string;
intel : boolean;
amd : boolean;
price : string;
end;
type TRAM = class(TObject)
public
name : string;
memory : integer;
clock : integer;
price : string;
end;
var
fMain: TfMain;
implementation
{$R *.dfm}
uses CPUs, GPUs, Motherboards;
procedure TfMain.cbCPUChange(Sender: TObject);
var
i : integer;
mobo : TMobo;
begin
if TCPU(fMain.cbCPU.ItemIndex).intel = true then begin
for i := 0 to Motherboards.MoboPartsList.Count-1 do begin
mobo := TMobo(Motherboards.MoboPartsList.Items[i]);
if mobo.intel = true then begin
fMain.cbMotherboard.Items.AddObject(mobo.name, mobo);
end;
end;
end;
end;
procedure cbCPUpopulate();
var
i : integer;
CPU : TCPU;
begin
for i := 0 to CPUs.CPUPartsList.Count-1 do begin
CPU := TCPU(CPUs.CPUPartsList.Items[i]);
fMain.cbCPU.Items.AddObject(CPU.name, CPU);
end;
end;
procedure TfMain.FormShow(Sender: TObject);
begin
Motherboards.MakeMoboList;
CPUs.MakeCPUList();
GPUs.popgpulist();
cbCPUpopulate;
end;
end.
In cbCPUChange()
, you are accessing the TCPU
objects incorrectly.
The expression TCPU(fMain.cbCPU.ItemIndex)
is type-casting a list index into an object pointer. You need to instead use the ItemIndex
to access the ComboBox's Objects[]
property, which is filled with TCPU
objects by cbCPUpopulate()
.
Also, there is no need to use the fMain
global variable from inside a method of the TfMain
class. Use the method's implicit Self
pointer instead.
Try something more like this:
procedure TfMain.cbCPUChange(Sender: TObject);
var
i : integer;
mobo : TMobo;
begin
cbMotherboard.Items.BeginUpdate;
try
cbMotherboard.Items.Clear;
i := cbCPU.ItemIndex;
if i < 0 then Exit;
if TCPU(cbCPU.Items.Objects[i]).intel then begin
for i := 0 to Motherboards.MoboPartsList.Count-1 do begin
mobo := TMobo(Motherboards.MoboPartsList.Items[i]);
if mobo.intel then begin
cbMotherboard.Items.AddObject(mobo.name, mobo);
end;
end;
end;
finally
cbMotherboard.Items.EndUpdate;
end;
end;
On a side note, the declarations of the TCPU
, TMobo
, and TRAM
types do not belong in the MainForm
unit. They should be declared in the other units that are actually creating object lists of those types, eg: TCPU
in the CPUs
unit, TMobo
in the Motherboards
unit, etc:
unit MainForm;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TfMain = class(TForm)
lCPU: TLabel;
cbCPU: TComboBox;
lGPU: TLabel;
cbGPU: TComboBox;
lMotherboard: TLabel;
cbMotherboard: TComboBox;
lRAM: TLabel;
cbRAM: TComboBox;
eCompatible: TEdit;
lCompatible: TLabel;
eCost: TEdit;
lCost: TLabel;
Label11: TLabel;
lbCPU: TListBox;
lbMotherboard: TListBox;
lbGPU: TListBox;
lbRAM: TListBox;
procedure FormShow(Sender: TObject);
procedure cbCPUChange(Sender: TObject);
private
{ Private declarations }
procedure cbCPUpopulate;
public
end;
var
fMain: TfMain;
implementation
{$R *.dfm}
uses
CPUs, GPUs, Motherboards;
procedure TfMain.cbCPUChange(Sender: TObject);
var
i : integer;
mobo : Motherboards.TMobo;
begin
cbMotherboard.Items.BeginUpdate;
try
cbMotherboard.Items.Clear;
i := cbCPU.ItemIndex;
if i < 0 then Exit;
if CPUs.TCPU(cbCPU.Items.Objects[i]).intel then begin
for i := 0 to Motherboards.MoboPartsList.Count-1 do begin
mobo := Motherboards.TMobo(Motherboards.MoboPartsList.Items[i]);
if mobo.intel then begin
cbMotherboard.Items.AddObject(mobo.name, mobo);
end;
end;
end;
finally
cbMotherboard.Items.EndUpdate;
end;
end;
procedure TfMain.cbCPUpopulate;
var
i : integer;
CPU : CPUs.TCPU;
begin
for i := 0 to CPUs.CPUPartsList.Count-1 do begin
CPU := CPUs.TCPU(CPUs.CPUPartsList.Items[i]);
cbCPU.Items.AddObject(CPU.name, CPU);
end;
end;
procedure TfMain.FormShow(Sender: TObject);
begin
Motherboards.MakeMoboList;
CPUs.MakeCPUList;
GPUs.popgpulist;
cbCPUpopulate;
end;
end.
User contributions licensed under CC BY-SA 3.0