1

基本上我想要一个由 StringList 填充的 ListView,当我选择一个 ListItem 并按下 Up 或 Down 时,它会向上或向下移动项目(在两个列表中)。

我正在使用 ListView 的 onKeyDown 来调用 MoverFAT

procedure TF_Aplicador.ListViewKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if ListView.Selected <> nil then
    if Key = VK_UP then
      MoverFAT(ListView.Selected.Index, -1)
    else if Key = VK_DOWN then
      MoverFAT(ListView.Selected.Index, 1)
    else if Key = VK_DELETE then
      DeletarFAT(ListView.Selected.Index);
end; 

问题是,向下移动时它总是选择第一个项目(在交换项目之后),向上移动就可以了。FATs 是我的 StringList,而 Atualizar() 只是让 ListView 显示 StringList 的内容。

procedure TF_Aplicador.MoverFAT(I, J: Integer);
begin
  if ((I + J) > -1) and ((I + J) < (FATs.Count)) then
  begin
    FATs.Exchange(I, I+J);
    Atualizar;
    ListView.Selected := ListView.Items[I+J];
  end;
end;
4

2 回答 2

3

我通过以下Atualizer实现重现了您的问题:

  ListView.Clear;
  for I := 0 to FATs.Count - 1 do
    ListView.AddItem(FATs[I], nil);

(如果你也给了我们,那肯定会容易得多。)

问题是 ListView 本身会尝试处理密钥,但是由于您(可能)删除了Atualizer例程中的所有项目,它不知道如何处理。

通过告诉 ListView 它不应该再通过分配来处理击键来解决它0

procedure TF_Aplicador.ListViewKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if ListView.Selected <> nil then
  begin
    case Key of
      VK_UP: MoverFAT(ListView.ItemIndex, -1);
      VK_DOWN: MoverFAT(ListView.ItemIndex, 1);
      VK_DELETE: DeletarFAT(ListView.ItemIndex);
    end;
    if Key in [VK_UP, VK_DOWN, VK_DELETE] then
      Key := 0;
  end;
end; 

附带说明:同步 StringList 和 ListView 有更好的方法。您可以利用Bummi 评论中的虚拟方法。或者您也可以交换 ListView 的项目,在这种情况下,您不再需要抑制密钥:

procedure TForm1.ListViewKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if ListView.Selected <> nil then
    case Key of
      VK_UP: MoverFAT(ListView.ItemIndex, -1);
      VK_DOWN: MoverFAT(ListView.ItemIndex, 1);
      VK_DELETE: DeletarFAT(ListView.ItemIndex);
    end;
end;

procedure ExchangeListItems(Items: TListItems; Index1, Index2: Integer);
var
  Item: TListItem;
begin
  Item := TListItem.Create(Items);
  try
    Item.Assign(Items[Index1]);
    Items[Index1].Assign(Items[Index2]);
    Items[Index2].Assign(Item);
  finally
    Item.Free;
  end;
end;

procedure TForm1.MoverFAT(I, J: Integer);
begin
  if ((I + J) > -1) and ((I + J) < (FATs.Count)) then
  begin
    FATs.Exchange(I, I + J);
    ExchangeListItems(ListView.Items, I, I + J);
  end;
end;
于 2013-04-22T18:23:53.340 回答
2

就 NGLN 已经指出的问题而言,我建议另一种方法。
不要将数据存储在 Listview 中,仅用于显示数据。只需要一个未改动的 Liestview 和 Listbox 来演示。

unit Unit6;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, StdCtrls;

type
  TForm6 = class(TForm)
    ListView: TListView;
    ListBox1: TListBox;  // just for visualization should be an Stringlist
    procedure ListViewKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormCreate(Sender: TObject);
    procedure ListViewData(Sender: TObject; Item: TListItem);
  private
    procedure MoverFAT(I, J: Integer);
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form6: TForm6;

implementation

var
  FATs: TStrings;
{$R *.dfm}

procedure TForm6.FormCreate(Sender: TObject);
var
  I: Integer;
begin
  for I := 0 to 9 do
    ListBox1.Items.Add(StringOfChar(IntToStr(I)[1], 10));
  ListView.Columns.Add.Caption := 'Test';
  ListView.ViewStyle := vsList;
  ListView.OwnerData := true;
  ListView.OnData := ListViewData;
  Listview.OnKeyDown := ListViewKeyDown;
  FATs := ListBox1.Items;
  ListView.Items.Count := FATs.Count;
end;

procedure TForm6.ListViewData(Sender: TObject; Item: TListItem);
begin
  Item.Caption := FATs[Item.Index];
end;

procedure TForm6.ListViewKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if ListView.Selected <> nil then
    if Key = VK_UP then
      MoverFAT(ListView.Selected.Index, -1)
    else if Key = VK_DOWN then
      MoverFAT(ListView.Selected.Index, 1)
end;

procedure TForm6.MoverFAT(I, J: Integer);
begin
  if ((I + J) > -1) and ((I + J) < (FATs.Count)) then
  begin
    FATs.Exchange(I, I + J);
    ListView.Invalidate;
    ListView.Selected := ListView.Items[I + J];
  end;
end;

end.
于 2013-04-22T18:34:52.353 回答