Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 将自动完成字符串分配给_Delphi_Autocomplete_Controls - Fatal编程技术网

Delphi 将自动完成字符串分配给

Delphi 将自动完成字符串分配给,delphi,autocomplete,controls,Delphi,Autocomplete,Controls,我正在从此处使用autocomplete修改编辑控件: 我想从DB加载自动完成字符串。我在自动完成控件子体上声明了新属性: FACDataSource : TDataSource; FACFieldName : string; 我调用此函数来加载自动完成字符串: procedure TAutoCompleteEdit.ReadSuggestions; begin FAutoCompleteSourceList.Clear; if (not Assigned(FACDataSourc

我正在从此处使用autocomplete修改编辑控件:

我想从DB加载自动完成字符串。我在自动完成控件子体上声明了新属性:

FACDataSource : TDataSource;
FACFieldName : string;
我调用此函数来加载自动完成字符串:

procedure TAutoCompleteEdit.ReadSuggestions;
begin
  FAutoCompleteSourceList.Clear;

  if (not Assigned(FACDataSource)) or (not Assigned(FACDataSource.DataSet))       or (not ACEnabled) then
      exit;

    with FACDataSource.DataSet do
    begin
       if Active and (RecordCount > 0) and (FACFieldName <> '') then
       begin
         First;
         while not EOF do
         begin
                       FAutoCompleteSourceList.Add(FACDataSource.DataSet.FieldByName(FACFieldName).AsString);
    Next;
  end;
  if FAutoCompleteSourceList.Count > 0 then
    ACStrings := FAutoCompleteSourceList;
end;
我在以下行中获得AccessViolation:
FACList.FStrings.Assign(Value)(读取地址xxxyy)<代码>值
已定义,在该点上不是垃圾(例如,在中,我可以在调试器中查看字符串列表)。'FStrings'是一个空字符串列表

当控件被放到窗体上时,它可以正常工作。但如果我将其放置在用户输入DBGridEH单元格时显示的自定义就地编辑器中,则不会发生这种情况

inplace编辑器如下所示:

    unit UInplaceAutoCompleteEditor;

    interface
    uses UDBAutoComplete, UMyInplaceEditor, classes, windows, Controls, Buttons,     DB;

    type TInplaceAutoCompleteEditor = class(TMyInplaceEditor)
      private
       FEditor : TAutoCompleteEdit;
    FButton : TSpeedButton;
    FShowButton : boolean;
    procedure SetShowButton(value : boolean);
    public
        constructor Create(AOwner : TComponent); override;
        procedure SetFocus; override;
        destructor Destroy; override;
     protected
    procedure EditorKeyDown(Sender : TObject; var Key : Word; Shift : TShiftState);
    function GetACDataSource : TDataSource;
    procedure SetACDataSource(value : TDataSource);
    function GetACFieldName : string;
    procedure SetACFieldName(value : string);
    procedure SetACEnabled(value : boolean);
    function GetACEnabled : boolean;
  published
    property Editor : TAutoCompleteEdit read FEditor;
    property ACDataSource : TDataSource read GetACDataSource write SetACDataSource;
    property ACFieldName : string read GetACFieldName write SetACFieldName;
    property ACEnabled : boolean read GetACEnabled write SetACEnabled;
    property Button : TSpeedButton read FButton;
    property ShowButton : boolean read FShowButton write SetShowButton;
end;

  procedure Register;

implementation

  procedure Register;
  begin
    RegisterComponents('nikolaev', [ TInplaceAutoCompleteEditor ]);
  end;

{ TInplaceAutoCompleteEditor }



constructor TInplaceAutoCompleteEditor.Create(AOwner: TComponent);
begin
  inherited;
  FEditor := TAutoCompleteEdit.Create(self);
  FEditor.Parent := self;
  FEditor.Align := alClient;
  FEditor.Visible := true;
  FEditor.WantTabs := true;
  FEditor.OnKeyDown := EditorKeyDown;

  FButton := TSpeedButton.Create(self);
  FButton.Parent := self;
  FButton.Align := alRight;

  self.FOwnHeight := -1;
  self.FOwnWidth := -1;

  SetShowButton(false);
end;

destructor TInplaceAutoCompleteEditor.Destroy;
begin
  Feditor.Destroy;
  FButton.Destroy;
  inherited;
end;

procedure TInplaceAutoCompleteEditor.EditorKeyDown(Sender: TObject;
  var Key: Word; Shift: TShiftState);
begin
  if Key in [ VK_Return, VK_Tab ] then
  begin
    self.Value := FEditor.Text;
    Key := 0;
    ConfirmValue;
  end;

  if Key = VK_Escape then
  begin
    Key := 0;
    CancelValue;
  end;

  inherited;
end;



function TInplaceAutoCompleteEditor.GetACDataSource: TDataSource;
begin
  Result := FEditor.ACDataSource;
end;

function TInplaceAutoCompleteEditor.GetACEnabled: boolean;
begin
  Result := FEditor.ACEnabled;
end;

function TInplaceAutoCompleteEditor.GetACFieldName: string;
begin
  Result := FEditor.ACFieldName
end;

procedure TInplaceAutoCompleteEditor.SetACDataSource(value: TDataSource);
begin
  FEditor.ACDataSource := value;
end;

procedure TInplaceAutoCompleteEditor.SetACEnabled(value: boolean);
begin
  FEditor.ACEnabled := value;
end;

procedure TInplaceAutoCompleteEditor.SetACFieldName(value: string);
begin
  FEditor.acfieldname := value;
end;

procedure TInplaceAutoCompleteEditor.SetFocus;
begin
  inherited;
  FEditor.SetFocus;
end;

procedure TInplaceAutoCompleteEditor.SetShowButton(value: boolean);
begin
  if value <> FShowButton then
  begin
    FShowButton := value;
    FButton.Visible := value;
  end;
end;

end.
type
  TAutoCompleteEdit = class(TEdit)
  private
    FACList: TEnumString;
  ....
type
  TEnumString = class(TObject, IInterface, IEnumString)
  private
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
    ....
  end;

function TEnumString.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  if GetInterface(IID, Obj) then
    Result := 0
  else
    Result := E_NOINTERFACE;
end;

function TEnumString._AddRef: Integer; 
begin
  Result := -1;
end;

function TEnumString._Release: Integer; 
begin
  Result := -1;
end;
destructor TAutoCompleteEdit.Destroy;
begin
  FACList.Free;
  inherited;
end;
InplaceEditor用于
DBGridEH
的后代。在某些情况下,我覆盖ShowEditor和HideEditor以显示/隐藏我的编辑器

同样,autocomplete控件仅在嵌入inplaceeditor控件时引发异常


导致访问冲突的原因是什么?

问题在于,您使用的mis代码处理接口引用计数。以下是相关摘录:

type
  TEnumString = class(TInterfacedObject, IEnumString)
  ....
请注意,此类派生自
TInterfacedObject
,因此它使用引用计数管理其生存期

然后代码是这样的:

    unit UInplaceAutoCompleteEditor;

    interface
    uses UDBAutoComplete, UMyInplaceEditor, classes, windows, Controls, Buttons,     DB;

    type TInplaceAutoCompleteEditor = class(TMyInplaceEditor)
      private
       FEditor : TAutoCompleteEdit;
    FButton : TSpeedButton;
    FShowButton : boolean;
    procedure SetShowButton(value : boolean);
    public
        constructor Create(AOwner : TComponent); override;
        procedure SetFocus; override;
        destructor Destroy; override;
     protected
    procedure EditorKeyDown(Sender : TObject; var Key : Word; Shift : TShiftState);
    function GetACDataSource : TDataSource;
    procedure SetACDataSource(value : TDataSource);
    function GetACFieldName : string;
    procedure SetACFieldName(value : string);
    procedure SetACEnabled(value : boolean);
    function GetACEnabled : boolean;
  published
    property Editor : TAutoCompleteEdit read FEditor;
    property ACDataSource : TDataSource read GetACDataSource write SetACDataSource;
    property ACFieldName : string read GetACFieldName write SetACFieldName;
    property ACEnabled : boolean read GetACEnabled write SetACEnabled;
    property Button : TSpeedButton read FButton;
    property ShowButton : boolean read FShowButton write SetShowButton;
end;

  procedure Register;

implementation

  procedure Register;
  begin
    RegisterComponents('nikolaev', [ TInplaceAutoCompleteEditor ]);
  end;

{ TInplaceAutoCompleteEditor }



constructor TInplaceAutoCompleteEditor.Create(AOwner: TComponent);
begin
  inherited;
  FEditor := TAutoCompleteEdit.Create(self);
  FEditor.Parent := self;
  FEditor.Align := alClient;
  FEditor.Visible := true;
  FEditor.WantTabs := true;
  FEditor.OnKeyDown := EditorKeyDown;

  FButton := TSpeedButton.Create(self);
  FButton.Parent := self;
  FButton.Align := alRight;

  self.FOwnHeight := -1;
  self.FOwnWidth := -1;

  SetShowButton(false);
end;

destructor TInplaceAutoCompleteEditor.Destroy;
begin
  Feditor.Destroy;
  FButton.Destroy;
  inherited;
end;

procedure TInplaceAutoCompleteEditor.EditorKeyDown(Sender: TObject;
  var Key: Word; Shift: TShiftState);
begin
  if Key in [ VK_Return, VK_Tab ] then
  begin
    self.Value := FEditor.Text;
    Key := 0;
    ConfirmValue;
  end;

  if Key = VK_Escape then
  begin
    Key := 0;
    CancelValue;
  end;

  inherited;
end;



function TInplaceAutoCompleteEditor.GetACDataSource: TDataSource;
begin
  Result := FEditor.ACDataSource;
end;

function TInplaceAutoCompleteEditor.GetACEnabled: boolean;
begin
  Result := FEditor.ACEnabled;
end;

function TInplaceAutoCompleteEditor.GetACFieldName: string;
begin
  Result := FEditor.ACFieldName
end;

procedure TInplaceAutoCompleteEditor.SetACDataSource(value: TDataSource);
begin
  FEditor.ACDataSource := value;
end;

procedure TInplaceAutoCompleteEditor.SetACEnabled(value: boolean);
begin
  FEditor.ACEnabled := value;
end;

procedure TInplaceAutoCompleteEditor.SetACFieldName(value: string);
begin
  FEditor.acfieldname := value;
end;

procedure TInplaceAutoCompleteEditor.SetFocus;
begin
  inherited;
  FEditor.SetFocus;
end;

procedure TInplaceAutoCompleteEditor.SetShowButton(value: boolean);
begin
  if value <> FShowButton then
  begin
    FShowButton := value;
    FButton.Visible := value;
  end;
end;

end.
type
  TAutoCompleteEdit = class(TEdit)
  private
    FACList: TEnumString;
  ....
type
  TEnumString = class(TObject, IInterface, IEnumString)
  private
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
    ....
  end;

function TEnumString.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  if GetInterface(IID, Obj) then
    Result := 0
  else
    Result := E_NOINTERFACE;
end;

function TEnumString._AddRef: Integer; 
begin
  Result := -1;
end;

function TEnumString._Release: Integer; 
begin
  Result := -1;
end;
destructor TAutoCompleteEdit.Destroy;
begin
  FACList.Free;
  inherited;
end;
因此,我们将保留对对象的引用,而不是对接口的引用。这看起来已经很可疑了

然后我们这样做:

constructor TAutoCompleteEdit.Create(AOwner: TComponent);
begin
  inherited;
  FACList := TEnumString.Create;
  ....
end;

destructor TAutoCompleteEdit.Destroy;
begin
  FACList := nil;
  inherited;
end;
这里没有任何东西可以让这个物体活着。在代码中的其他点,我们引用
IEnumString
接口。但一旦该引用被释放,对象就会认为已经没有引用了。所以它被删除了。随后,代码引用了
FACList
,它现在指向一个已被破坏的对象


解决此问题的一个简单方法是确保
tautompleedit
控件始终包含对接口的引用:

type
  TAutoCompleteEdit = class(TEdit)
  private
    FACList: TEnumString;
    FEnumString: IEnumString;
....
constructor TAutoCompleteEdit.Create(AOwner: TComponent);
begin
  inherited;
  FACList := TEnumString.Create;
  FEnumString := FACList;
  ....
end;
通过此更改,您可以删除
tautompleedit
的析构函数,因为
FEnumString
后面的对象将被引用计数机制销毁


另一种解决方法是将
TEnumString
更改为禁用自动引用计数。看起来是这样的:

    unit UInplaceAutoCompleteEditor;

    interface
    uses UDBAutoComplete, UMyInplaceEditor, classes, windows, Controls, Buttons,     DB;

    type TInplaceAutoCompleteEditor = class(TMyInplaceEditor)
      private
       FEditor : TAutoCompleteEdit;
    FButton : TSpeedButton;
    FShowButton : boolean;
    procedure SetShowButton(value : boolean);
    public
        constructor Create(AOwner : TComponent); override;
        procedure SetFocus; override;
        destructor Destroy; override;
     protected
    procedure EditorKeyDown(Sender : TObject; var Key : Word; Shift : TShiftState);
    function GetACDataSource : TDataSource;
    procedure SetACDataSource(value : TDataSource);
    function GetACFieldName : string;
    procedure SetACFieldName(value : string);
    procedure SetACEnabled(value : boolean);
    function GetACEnabled : boolean;
  published
    property Editor : TAutoCompleteEdit read FEditor;
    property ACDataSource : TDataSource read GetACDataSource write SetACDataSource;
    property ACFieldName : string read GetACFieldName write SetACFieldName;
    property ACEnabled : boolean read GetACEnabled write SetACEnabled;
    property Button : TSpeedButton read FButton;
    property ShowButton : boolean read FShowButton write SetShowButton;
end;

  procedure Register;

implementation

  procedure Register;
  begin
    RegisterComponents('nikolaev', [ TInplaceAutoCompleteEditor ]);
  end;

{ TInplaceAutoCompleteEditor }



constructor TInplaceAutoCompleteEditor.Create(AOwner: TComponent);
begin
  inherited;
  FEditor := TAutoCompleteEdit.Create(self);
  FEditor.Parent := self;
  FEditor.Align := alClient;
  FEditor.Visible := true;
  FEditor.WantTabs := true;
  FEditor.OnKeyDown := EditorKeyDown;

  FButton := TSpeedButton.Create(self);
  FButton.Parent := self;
  FButton.Align := alRight;

  self.FOwnHeight := -1;
  self.FOwnWidth := -1;

  SetShowButton(false);
end;

destructor TInplaceAutoCompleteEditor.Destroy;
begin
  Feditor.Destroy;
  FButton.Destroy;
  inherited;
end;

procedure TInplaceAutoCompleteEditor.EditorKeyDown(Sender: TObject;
  var Key: Word; Shift: TShiftState);
begin
  if Key in [ VK_Return, VK_Tab ] then
  begin
    self.Value := FEditor.Text;
    Key := 0;
    ConfirmValue;
  end;

  if Key = VK_Escape then
  begin
    Key := 0;
    CancelValue;
  end;

  inherited;
end;



function TInplaceAutoCompleteEditor.GetACDataSource: TDataSource;
begin
  Result := FEditor.ACDataSource;
end;

function TInplaceAutoCompleteEditor.GetACEnabled: boolean;
begin
  Result := FEditor.ACEnabled;
end;

function TInplaceAutoCompleteEditor.GetACFieldName: string;
begin
  Result := FEditor.ACFieldName
end;

procedure TInplaceAutoCompleteEditor.SetACDataSource(value: TDataSource);
begin
  FEditor.ACDataSource := value;
end;

procedure TInplaceAutoCompleteEditor.SetACEnabled(value: boolean);
begin
  FEditor.ACEnabled := value;
end;

procedure TInplaceAutoCompleteEditor.SetACFieldName(value: string);
begin
  FEditor.acfieldname := value;
end;

procedure TInplaceAutoCompleteEditor.SetFocus;
begin
  inherited;
  FEditor.SetFocus;
end;

procedure TInplaceAutoCompleteEditor.SetShowButton(value: boolean);
begin
  if value <> FShowButton then
  begin
    FShowButton := value;
    FButton.Visible := value;
  end;
end;

end.
type
  TAutoCompleteEdit = class(TEdit)
  private
    FACList: TEnumString;
  ....
type
  TEnumString = class(TObject, IInterface, IEnumString)
  private
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
    ....
  end;

function TEnumString.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  if GetInterface(IID, Obj) then
    Result := 0
  else
    Result := E_NOINTERFACE;
end;

function TEnumString._AddRef: Integer; 
begin
  Result := -1;
end;

function TEnumString._Release: Integer; 
begin
  Result := -1;
end;
destructor TAutoCompleteEdit.Destroy;
begin
  FACList.Free;
  inherited;
end;
然后您需要
tautompleedit
析构函数如下所示:

    unit UInplaceAutoCompleteEditor;

    interface
    uses UDBAutoComplete, UMyInplaceEditor, classes, windows, Controls, Buttons,     DB;

    type TInplaceAutoCompleteEditor = class(TMyInplaceEditor)
      private
       FEditor : TAutoCompleteEdit;
    FButton : TSpeedButton;
    FShowButton : boolean;
    procedure SetShowButton(value : boolean);
    public
        constructor Create(AOwner : TComponent); override;
        procedure SetFocus; override;
        destructor Destroy; override;
     protected
    procedure EditorKeyDown(Sender : TObject; var Key : Word; Shift : TShiftState);
    function GetACDataSource : TDataSource;
    procedure SetACDataSource(value : TDataSource);
    function GetACFieldName : string;
    procedure SetACFieldName(value : string);
    procedure SetACEnabled(value : boolean);
    function GetACEnabled : boolean;
  published
    property Editor : TAutoCompleteEdit read FEditor;
    property ACDataSource : TDataSource read GetACDataSource write SetACDataSource;
    property ACFieldName : string read GetACFieldName write SetACFieldName;
    property ACEnabled : boolean read GetACEnabled write SetACEnabled;
    property Button : TSpeedButton read FButton;
    property ShowButton : boolean read FShowButton write SetShowButton;
end;

  procedure Register;

implementation

  procedure Register;
  begin
    RegisterComponents('nikolaev', [ TInplaceAutoCompleteEditor ]);
  end;

{ TInplaceAutoCompleteEditor }



constructor TInplaceAutoCompleteEditor.Create(AOwner: TComponent);
begin
  inherited;
  FEditor := TAutoCompleteEdit.Create(self);
  FEditor.Parent := self;
  FEditor.Align := alClient;
  FEditor.Visible := true;
  FEditor.WantTabs := true;
  FEditor.OnKeyDown := EditorKeyDown;

  FButton := TSpeedButton.Create(self);
  FButton.Parent := self;
  FButton.Align := alRight;

  self.FOwnHeight := -1;
  self.FOwnWidth := -1;

  SetShowButton(false);
end;

destructor TInplaceAutoCompleteEditor.Destroy;
begin
  Feditor.Destroy;
  FButton.Destroy;
  inherited;
end;

procedure TInplaceAutoCompleteEditor.EditorKeyDown(Sender: TObject;
  var Key: Word; Shift: TShiftState);
begin
  if Key in [ VK_Return, VK_Tab ] then
  begin
    self.Value := FEditor.Text;
    Key := 0;
    ConfirmValue;
  end;

  if Key = VK_Escape then
  begin
    Key := 0;
    CancelValue;
  end;

  inherited;
end;



function TInplaceAutoCompleteEditor.GetACDataSource: TDataSource;
begin
  Result := FEditor.ACDataSource;
end;

function TInplaceAutoCompleteEditor.GetACEnabled: boolean;
begin
  Result := FEditor.ACEnabled;
end;

function TInplaceAutoCompleteEditor.GetACFieldName: string;
begin
  Result := FEditor.ACFieldName
end;

procedure TInplaceAutoCompleteEditor.SetACDataSource(value: TDataSource);
begin
  FEditor.ACDataSource := value;
end;

procedure TInplaceAutoCompleteEditor.SetACEnabled(value: boolean);
begin
  FEditor.ACEnabled := value;
end;

procedure TInplaceAutoCompleteEditor.SetACFieldName(value: string);
begin
  FEditor.acfieldname := value;
end;

procedure TInplaceAutoCompleteEditor.SetFocus;
begin
  inherited;
  FEditor.SetFocus;
end;

procedure TInplaceAutoCompleteEditor.SetShowButton(value: boolean);
begin
  if value <> FShowButton then
  begin
    FShowButton := value;
    FButton.Visible := value;
  end;
end;

end.
type
  TAutoCompleteEdit = class(TEdit)
  private
    FACList: TEnumString;
  ....
type
  TEnumString = class(TObject, IInterface, IEnumString)
  private
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
    ....
  end;

function TEnumString.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  if GetInterface(IID, Obj) then
    Result := 0
  else
    Result := E_NOINTERFACE;
end;

function TEnumString._AddRef: Integer; 
begin
  Result := -1;
end;

function TEnumString._Release: Integer; 
begin
  Result := -1;
end;
destructor TAutoCompleteEdit.Destroy;
begin
  FACList.Free;
  inherited;
end;


最后一个选择是完全避免持有
TEnumString
,而只持有
IEnumString
引用。让引用计数像在第一个解决方案中一样管理生存期。但是,您需要实现另一个接口,该接口允许
tautompleedit
获取
TStrings
对象。

@KenWhite您的链接答案在其他方面非常好。如果你能在那里修改代码,那也许是最好的。@David:完成了,谢谢。(我选择了你的第一个建议,因为在我看来这是最干净的。)@KenWhite谢谢。我能看到这三个选项的优点,我想这就是为什么我没能把我的颜色钉在桅杆上!