3

私は Delphi 7 に取り組んでいます。1 つの TListBox と 2 つの列を持つ 1 つの TStringGrid があります (行や列が固定されていません)。次のように TListBox にデータがあります。

利用可能な要素 - a123 (a123) 利用可能な要素 - a1234 (a1234) 利用可能な要素 - a12345 (a12345)

また、TStringGrid には次のようなデータがあります。

列1 列2

a1 利用可能な要素 - a1 a2 利用可能な要素 - a12

TListbox の最初のアイテム (a123) を選択し、次のボタン クリック イベント プロシージャを実行すると、最後のアイテム データ (a12345) がグリッドに移動します。

次のコードで私が間違っていることに誰かが焦点を当てることができますか? 次のコードは、TListbox で選択した項目を TStringgird の 2 つの列に移動します。

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 に進みます。アイテム - 0 が選択され、削除されます。次の繰り返しで得たものは何ですか?i=1 ですが、ここでは 3 つではなく 2 つのアイテムしか残っておらず (後続のすべてのアイテムがシフトされています)、i は 2 番目ではなく最後のアイテムを指しています。i=3 の次の繰り返しで、「Index out of bound」エラーが発生します。この問題を回避するには、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 に答える