3

我正在研究 Delphi 7。我有一个 TListBox 和一个 TStringGrid 有两列(没有固定的行或列)。我在 TListBox 中有如下数据:

可用元素 - a123 (a123) 可用元素 - a1234 (a1234) 可用元素 - a12345 (a12345)

TStringGrid 具有以下数据:

列 1 列 2

a1 可用元素 - a1 a2 可用元素 - a12

如果我选择 TListbox 中的第一项,即 a123 并执行以下按钮单击事件过程,那么最后一项数据,即 a12345 将被移动到网格中。

任何人都可以把重点放在我在下面的代码中做错了什么。以下代码将 TListbox 中的已选择项移动到 TStringgird 的两列:

procedure TForm1.btnMoveLeftClick(Sender: TObject);
var
  sString : String;
  i : Integer;
begin
  for i := 0 to ListBox1.Items.Count - 1 do
  begin
      {-- Is this status selected? --}
      if ListBox1.Selected[i] then
      begin
        sString := Trim(ListBox1.Items[i]);

        {-- Delete selected status. --}
          ListBox1.Items.Delete (i);

        if ((grdVFormDetails.RowCount >= 1) And (Trim(grdVFormDetails.Cells[0, 0]) <> EmptyStr)) then
          grdVFormDetails.RowCount := grdVFormDetails.RowCount+1;

        grdVFormDetails.Cols[1].Add(Copy(sString, 1, Pos('(', sString) - 1));

        sString := Copy(sString, Pos('(', sString) + 1, Length(sString));
        sString := Copy(sString, Pos('(', sString) + 1, Length(sString) - 1);

        grdVFormDetails.Cols[0].Add(sString);


        break;
      end;
  end;
end;
4

4 回答 4

2

永远不要在 FOR 循环中删除 TList 的项目。

这一行的问题:

  ListBox1.Items.Delete (i);

循环从 i:=0 变为 2。Item - 0 被选中并删除它。下一次重复我们得到了什么?i=1 但这里只剩下 2 个项目而不是 3 个(所有后续项目都移动了),并且 i 指向最后一个项目而不是第二个项目。在 i=3 的下一次重复中,我们将得到“索引超出范围”错误。您应该仅在 FOR 循环之后删除 Item 以避免此问题。

procedure TForm1.btnMoveLeftClick(Sender: TObject);
var
  sString : String;
  i : Integer;
  k: integer;
begin
  k:=-1; 
  for i := 0 to ListBox1.Items.Count - 1 do
  begin
      {-- Is this status selected? --}
      if ListBox1.Selected[i] then
      begin
        sString := Trim(ListBox1.Items[i]);

        {-- Delete selected status. --}
          k:=i;         

        if ((grdVFormDetails.RowCount >= 1) And (Trim(grdVFormDetails.Cells[0, 0]) <> EmptyStr)) then
          grdVFormDetails.RowCount := grdVFormDetails.RowCount+1;

        grdVFormDetails.Cols[1].Add(Copy(sString, 1, Pos('(', sString) - 1));

        sString := Copy(sString, Pos('(', sString) + 1, Length(sString));
        sString := Copy(sString, Pos('(', sString) + 1, Length(sString) - 1);

        grdVFormDetails.Cols[0].Add(sString);


        break;
      end;
  end;
  if k>=0 then  ListBox1.Items.Delete (k);

end;
于 2012-12-12T06:38:03.080 回答
1

假设,您想像这样解析输入字符串:

'Some text (comment) etc. (12345)'

进入从输入字符串的开头到第一个左括号(从结尾开始)修剪字符串的部分,以获得如下值:

'Some text (comment) etc.'

以及输入字符串最后一个括号内的字符串:

'12345'

如果是这样,您可以使用下面的代码。请注意,预计列表框项目会以右括号终止。如果需要,您可以检查commented version此代码或下载sample project

这是将焦点项从列表框移动到字符串网格的部分

procedure TForm1.MoveLeftButtonClick(Sender: TObject);
var
  S: string;
  I: Integer;
  ItemID: string;
  ItemText: string;
begin
  if ListBox1.ItemIndex = -1 then
    Exit;

  S := ListBox1.Items[ListBox1.ItemIndex];
  for I := Length(S) - 1 downto 1 do
  begin
    if S[I] = '(' then
    begin
      ItemID := Trim(Copy(S, I + 1, Length(S) - I - 1));
      ItemText := Trim(Copy(S, 1, I - 1));
      with StringGrid1 do
      begin
        if (Cells[0, RowCount - 1] <> '') and
          (Cells[1, RowCount - 1] <> '')
        then
          RowCount := RowCount + 1;
        Cells[0, RowCount - 1] := ItemID;
        Cells[1, RowCount - 1] := ItemText;
      end;
      ListBox1.Items.Delete(ListBox1.ItemIndex);
      Break;
    end;
  end;
end;

这是将所选行从字符串网格移动到列表框的部分:

procedure TForm1.MoveRightButtonClick(Sender: TObject);
var
  I: Integer;
  RowIndex: Integer;
begin
  RowIndex := StringGrid1.Selection.Top;
  if (StringGrid1.Cells[0, RowIndex] <> '') and
    (StringGrid1.Cells[1, RowIndex] <> '') then
  begin
    ListBox1.Items.Add(
      Trim(StringGrid1.Cells[1, RowIndex]) + ' (' +
      Trim(StringGrid1.Cells[0, RowIndex]) + ')'
    );
    for I := RowIndex to StringGrid1.RowCount - 2 do
      StringGrid1.Rows[I].Assign(StringGrid1.Rows[I + 1]);
    if StringGrid1.RowCount > 1 then
      StringGrid1.RowCount := StringGrid1.RowCount - 1
    else
    begin
      StringGrid1.Cells[0, 0] := '';
      StringGrid1.Cells[1, 0] := '';
    end;
  end;
end;
于 2012-12-12T19:15:21.747 回答
0

我目前没有安装 Delphi,但据我所知,如果 ListBox1.Selected[i] 那么不会给你正确的结果。您需要首先获取该项目,他们检查该项目是否被选中。

于 2012-12-12T06:08:15.863 回答
0

如果您在 ListBox 中没有多选,最好使用 ItemIndex 属性,它为您提供所选项目的索引,因此您不必循环检查列表中的所有项目。

像这样:

procedure TForm1.btnMoveLeftClick(Sender: TObject);
var
  sString : String;
  i : Integer;
begin
  if ListBox1.ItemIndex <> -1 then
  begin
    sString := Trim(ListBox1.Items[ListBox1.ItemIndex]);
    //do all your processing here
    //and at the end:
    ListBox1.Items.Delete(ListBox1.ItemIndex);
  end
end;
于 2012-12-12T06:33:35.113 回答