Delphi:在运行时获取访问冲突错误

0 delphi access-violation

我对 Delphi 还很陌生,我正在尝试使用不同的单位来存储 TLists 和 TObjects,以及基于以前的组合框选择生成其他组合框选项。我在运行后立即收到以下错误消息:

项目 Project1.exe 引发异常类 $C0000005,并带有消息“0x004087d7 处的访问冲突:读取地址 0x00000000”

模块“Project1.exe”中地址 00408813 处的访问冲突。读取地址 00000000。

我已经跟踪了调试工具中的步骤,但我不明白为什么它不起作用。我用谷歌搜索了这个问题并找到了一些解决方案,但似乎没有任何适用于我当前的问题。

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.
Run Code Online (Sandbox Code Playgroud)

Rem*_*eau 5

在 中cbCPUChange(),您TCPU错误地访问了对象。

该表达式TCPU(fMain.cbCPU.ItemIndex)列表索引类型转换为对象指针。您需要改为使用ItemIndex来访问 ComboBox 的Objects[]属性,该属性TCPU由填充了对象cbCPUpopulate()

此外,不需要fMainTfMain类的方法内部使用全局变量。改用方法的隐式Self指针。

尝试更像这样的事情:

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;
Run Code Online (Sandbox Code Playgroud)

附带说明一下TCPUTMobo、 和TRAM类型的声明不属于该MainForm单元。它们应该在实际创建这些类型的对象列表的其他单元中声明,例如:TCPUCPUs单元中,TMoboMotherboards单元中等:

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.
Run Code Online (Sandbox Code Playgroud)