【问题标题】:Delphi FMX TListview - DynamicAppearance mode - Access Violation problemDelphi FMX TListview - DynamicAppearance 模式 - 访问冲突问题
【发布时间】:2020-10-30 15:23:24
【问题描述】:

设置 TListview,ItemAppearance = DynamicAppearance

在 OnClickItemEX 中,假设有 2 个文本对象。单击两个 TextObjects - 确定。单击其中 2 个之间的空格 - 访问冲突。

如果单击项目未覆盖的任何位置,则对于最简单的设置将导致访问冲突。

如果我只使用 OnButtonClick 而不使用 OnClickItemEX,则没有这样的 AV。

我该如何解决这个问题?请参阅下面的最小工作示例。 (我不确定以这种方式附加它是否正确,因为我没有看到用于上传这个迷你项目的 zip 文件的附件选项)。

unit bug_main;

interface


type
  TForm1 = class(TForm)
    ListView1: TListView;
    Button1: TButton;
    FDMemTable1: TFDMemTable;
    BindSourceDB1: TBindSourceDB;
    FDMemTable1CustomerID: TIntegerField;
    FDMemTable1CustomerName: TStringField;
    BindSourceDB2: TBindSourceDB;
    BindingsList1: TBindingsList;
    procedure Button1Click(Sender: TObject);
    procedure ListView1ItemClickEx(const Sender: TObject; ItemIndex: Integer;
      const LocalClickPos: TPointF; const ItemObject: TListItemDrawable);
  private
    FLinkFillControlToField : TLinkFillControlToField;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
begin
  with FDMemTable1 do
  begin
    Open;

    Append;
    FieldByName('CustomerID').AsInteger := 1;
    FieldByName('CustomerName').AsString := 'ABC';
    Post;

    Append;
    FieldByName('CustomerID').AsInteger := 2;
    FieldByName('CustomerName').AsString := 'XYZ';
    Post;
  end;

  if not Assigned(FLinkFillControlToField) then
  begin
    FLinkFillControlToField := TLinkFillControlToField.Create(BindingsList1);
    FLinkFillControlToField.Control := listview1;

    with FLinkFillControlToField do
    begin
      Category := 'Quick Bindings';
      Track := False;
      Direction := linkDataToControl;
      AutoActivate := False;
      AutoFill := True;
      BindSourceDB1.DataSource.Enabled := True;
      FillDataSource := BindSourceDB1;
    end;
  end;

  with FLinkFillControlToField do
  begin
    with FillExpressions.AddExpression do
    begin
      SourceMemberName := 'CustomerID';
      ControlMemberName := 'Text1';
    end;
    with FillExpressions.AddExpression do
    begin
      SourceMemberName := 'CustomerName';
      ControlMemberName := 'Text2';
    end;
  end;
  FLinkFillControlToField.Active := True;
end;

procedure TForm1.ListView1ItemClickEx(const Sender: TObject; ItemIndex: Integer;
  const LocalClickPos: TPointF; const ItemObject: TListItemDrawable);
begin
  if itemobject.Name = 'Text1' then
  begin
    showmessage('clicked on Text1');
  end else if itemobject.Name = 'Text2' then
  begin
    showmessage('clicked on Text2');
  end;
end;

end.


object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 404
  ClientWidth = 763
  FormFactor.Width = 320
  FormFactor.Height = 480
  FormFactor.Devices = [Desktop]
  DesignerMasterStyle = 0
  object ListView1: TListView
    ItemAppearanceClassName = 'TDynamicAppearance'
    ItemEditAppearanceClassName = 'TDynamicAppearance'
    HeaderAppearanceClassName = 'TListHeaderObjects'
    FooterAppearanceClassName = 'TListHeaderObjects'
    Position.X = 16.000000000000000000
    Position.Y = 24.000000000000000000
    Size.Width = 561.000000000000000000
    Size.Height = 353.000000000000000000
    Size.PlatformDefault = False
    ItemAppearanceObjects.ItemObjects.ObjectsCollection = <
      item
        AppearanceObjectName = 'Text1'
        AppearanceClassName = 'TTextObjectAppearance'
        Appearance.Width = 223.000000000000000000
        Appearance.Height = 44.000000000000000000
      end
      item
        AppearanceObjectName = 'Text2'
        AppearanceClassName = 'TTextObjectAppearance'
        Appearance.Width = 208.000000000000000000
        Appearance.Height = 44.000000000000000000
        Appearance.PlaceOffset.X = 326.000000000000000000
      end>
    ItemAppearanceObjects.ItemEditObjects.ObjectsCollection = <
      item
        AppearanceObjectName = 'Text1'
        AppearanceClassName = 'TTextObjectAppearance'
      end>
    OnItemClickEx = ListView1ItemClickEx
  end
  object Button1: TButton
    Position.X = 592.000000000000000000
    Position.Y = 24.000000000000000000
    Size.Width = 161.000000000000000000
    Size.Height = 57.000000000000000000
    Size.PlatformDefault = False
    Text = 'Button1'
    OnClick = Button1Click
  end
  object FDMemTable1: TFDMemTable
    FetchOptions.AssignedValues = [evMode]
    FetchOptions.Mode = fmAll
    ResourceOptions.AssignedValues = [rvSilentMode]
    ResourceOptions.SilentMode = True
    UpdateOptions.AssignedValues = [uvCheckRequired, uvAutoCommitUpdates]
    UpdateOptions.CheckRequired = False
    UpdateOptions.AutoCommitUpdates = True
    Left = 576
    Top = 128
    object FDMemTable1CustomerID: TIntegerField
      FieldName = 'CustomerID'
    end
    object FDMemTable1CustomerName: TStringField
      FieldName = 'CustomerName'
      Size = 30
    end
  end
  object BindSourceDB1: TBindSourceDB
    DataSet = FDMemTable1
    ScopeMappings = <>
    Left = 576
    Top = 192
  end
  object BindSourceDB2: TBindSourceDB
    DataSet = FDMemTable1
    ScopeMappings = <>
    Left = 576
    Top = 248
  end
  object BindingsList1: TBindingsList
    Methods = <>
    OutputConverters = <>
    Left = 20
    Top = 5
  end
end

【问题讨论】:

  • 请编辑您的帖子并添加发生访问冲突的代码行。要知道这一点,请在调试器下运行您的应用程序(当然构建配置必须是“调试”)。
  • 您应该返回并删除您之前关于此问题的问题。执行此操作的链接位于标签下方。否则,您需要删除这个并返回并编辑另一个并等待它重新打开,如help center 中所述。你不能同时拥有它们。
  • fpiette,谢谢 - 将来,我将包括 AV 出现的行。肯,我已经删除了原来的那个。谢谢大家的指点。

标签: delphi firemonkey tlistview


【解决方案1】:

如果您在 ListView1ItemClickEx 方法的第一行设置断点,然后运行应用程序并在两个项目之间单击,您将看到没有 ItemObject,因为您没有单击项目 (你在他们之间点击)。这会导致 ItemObject 为 nil,然后您尝试从该未分配对象中读取 Text 值,从而导致 AV。

您可以通过检查以确保在使用 ItemObject 之前为其分配了一个值来纠正此问题。

procedure TForm1.ListView1ItemClickEx(const Sender: TObject; ItemIndex: Integer;
  const LocalClickPos: TPointF; const ItemObject: TListItemDrawable);
begin
  if ItemObject <> nil then
  begin
    if itemobject.Name = 'Text1' then
    begin
      ShowMessage('clicked on Text1');
    end else if itemobject.Name = 'Text2' then
    begin
      ShowMessage('clicked on Text2');
    end;
  end else
    ShowMessage('ItemObject is not assigned');
end;

学习使用调试器单步调试代码将使您能够自己解决这类简单问题。在您的程序员工具箱中没有比一个好的调试器更好的工具了,Delphi 的调试器非常好。

【讨论】:

  • 感谢您的指点。我遇到了 coder 的代码块,看了很多次在第一行崩溃的调试器,却没有意识到 ItemObject 可能是 nil。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-01
  • 1970-01-01
相关资源
最近更新 更多