2011-11-24 18 views
6

Bir TListView'da varolan sütunlar arasında bir sütun eklemeye çalışıyorum. Sonunda yeni sütunu ekledim ve indeksini belirlenen değere ayarlayarak taşıdım. Bu yeni bir sütun ekleyene kadar çalışır.TListView: Bir sütun eklerseniz, VCL sütunları kaybeder

Ne yaptım: Sütunu son konumda (Columns.Add) ekleyin ve alt pozisyonu da son konuma ekleyin (Subitems.Add). Daha sonra indeksi doğru konuma ayarlayarak sütunu hareket ettiririm. Bu, eklendiği yalnızca bir sütun olduğu sürece iyi çalışır. İkinci bir yeni sütun eklerken, alt öğeler bozulur. İlk sütunun yeni alt alanı son konuma taşınır, ör. bunun gibi:

0  | 1   | new A  | new B  | 3 
Caption | old sub 1 | old sub 3 | new Sub B | new sub A 

Eğer birisi size yardımcı olabilirse çok mutlu olurum!

Örneğin, ListView'e gönderebildiğim bir komut veya mesaj olabilir, böylece yeni bir sütun ekledikten sonra kullanabileceğim sütun -> Subitem eşleştirmesi ve alt aşamaları kullanabilirim. İkinci yeni sütun ilk ile aynı şekilde. Veya bu bir TListViews sütunu -> subitem kullanımı ya da TListColumns ... hatası mıdır? Bir vcl form uygulaması için

örnek kodu (Form1.OnCreate olay atamak):

unit Unit1; 

interface 

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

type 
    TForm1 = class(TForm) 
    procedure FormCreate(Sender: TObject); 
    private 
    listview: TListView; 
    initButton: TButton; 
    addColumn: TButton; 
    editColumn: TEdit; 
    subItemCount: Integer; 
    procedure OnInitClick(Sender: TObject); 
    procedure OnAddClick(Sender: TObject); 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    listview := TListView.Create(self); 
    with listview do 
    begin 
    Left := 8; 
    Top := 8; 
    Width := self.Width - 30; 
    Height := self.Height - 100; 
    Anchors := [akLeft, akTop, akRight, akBottom]; 
    TabOrder := 0; 
    ViewStyle := vsReport; 
    Parent := self; 
    end; 

initButton := TButton.Create(self); 
with initButton do 
    begin 
    left := 8; 
    top := listview.Top + listview.Height + 20; 
    Width := 75; 
    Height := 25; 
    TabOrder := 1; 
    Caption := 'init'; 
    OnClick := OnInitClick; 
    Parent := self; 
    end; 

    editColumn := TEdit.Create(self); 
    with editColumn do 
    begin 
    left := initButton.Left + initButton.Width + 30; 
    top := listview.Top + listview.Height + 20; 
    Width := 120; 
    Height := 25; 
    TabOrder := 2; 
    Parent := self; 
    Caption := ''; 
    end; 

    addColumn := TButton.Create(self); 
    with addColumn do 
    begin 
    left := editColumn.Left + editColumn.Width + 10; 
    top := listview.Top + listview.Height + 20; 
    Width := 75; 
    Height := 25; 
    TabOrder := 1; 
    Enabled := true; 
    Caption := 'add'; 
    OnClick := OnAddClick; 
    Parent := self; 
    end; 

end; 

procedure TForm1.OnInitClick(Sender: TObject); 
var col: TListColumn; 
i, j: integer; 
item: TListItem; 
begin 
    listview.Items.Clear; 
    listview.Columns.Clear; 

    // add items 
    for I := 0 to 2 do 
    begin 
    col := ListView.Columns.Add; 
    col.Caption := 'column ' + IntToStr(i); 
    col.Width := 80; 
    end; 

    // add columns 
    for I := 0 to 3 do 
    begin 
    item := ListView.Items.Add; 
    item.Caption := 'ItemCaption'; 

    // add subitems for each column 
    for j := 0 to 1 do 
    begin 
     item.SubItems.Add('subitem ' + IntToStr(j+1)); 
    end; 
    end; 

    subItemCount := 5; 
end; 

procedure TForm1.OnAddClick(Sender: TObject); 
var number: integer; 
col: TListColumn; 
i: Integer; 
ascii: char; 
begin 
    listview.Columns.BeginUpdate; 

    number := StrToInt(editColumn.Text); 
    ascii := Chr(65 + number); 

    // create the new column 
    col := TListColumn(ListView.Columns.add()); 
    col.Width := 80; 
    col.Caption := ascii; 

    // add the new subitems 
    for I := 0 to ListView.Items.Count-1 do 
    begin 
    ListView.Items[i].SubItems.Add('subitem ' + ascii); 
    end; 

    // move it to the designated position 
    col.Index := number; 

    listview.Columns.EndUpdate; 

    Inc(subItemCount); 
end; 

end. 

teşekkür ederiz!


Düzenleme: Delphi sourcecode değiştirme Projem için bir çözüm olduğu için bunu kullanamaz rağmen Sertaç Akyüz dan önerilen düzeltme, gayet iyi çalışıyor. Hata bildirildi.

Düzenleme: İlk gönderide istem dışı bulunan ikinci soruyu kaldırdı ve yeni soru açtı (Bkz. Bağlantılı soru ve Soru düzeltme).

Güncelleme: Delphi XE2 Update 4 itibariyle sabit olarak reported bug anda kapalı.

+0

Sanırım bir yerde eksik yenileme/güncelleme var. Olduğundan emin değil. Bu, sanal mod listesi görünümlerinin parlayacağı başka bir durum gibi görünüyor. –

+0

Ama onlar sadece .Net için mevcut, değil mi? Aynı sorunu C# .Net projesiyle aldım ve belki orada kullanabilirim. – torno

+0

Hayır. Windows listesi görünümü sanal modunu destekler ve Delphi bunu çok güzel bir şekilde sarar. Çalışma zamanında sütunları manipüle ediyorsanız, kesinlikle gitmek için bir yoldur.Buradaki herkes sanal ağaç görünümünde size işaret ederdi ama ben kendimi yerel kontrolü severim. –

cevap

7

Sütunları düzenledikten sonra UpdateItems yöntemini çağırın. Örn .:

.. 
col.Index := number; 
listview.UpdateItems(0, MAXINT); 
.. 



Güncelleme: Benim testlerde

, hala bazı vesileyle yukarıda çağrıyı gerekir gibi görünüyor. Ancak asıl sorun, "Delphi liste görünümü kontrolünde bir hata var". Basit bir proje ile sorunu Kopyalama

:

  • Yeri VCL form üzerinde bir TListView kontrolü, onun ViewStyle için 'vsReport' set ve 'gerçek' olarak FullDrag ayarlayın.
  • formun OnCreate işleyicisi aşağıdaki kodu yerleştirin:
    ListView1.Columns.Add.Caption := 'col 1'; 
    ListView1.Columns.Add.Caption := 'col 2'; 
    ListView1.Columns.Add.Caption := 'col 3'; 
    ListView1.AddItem('cell 1', nil); 
    ListView1.Items[0].SubItems.Add('cell 2'); 
    ListView1.Items[0].SubItems.Add('cell 3'); 
    
  • yerleştirin form üzerinde bir TButton ve bunun OnClick işleyicisi aşağıdaki kodu koyun:
    ListView1.Columns.Add.Caption := 'col 4';
  • çalıştırın projesi ve sütun başlığını sürükleyin 'col 3' in 'col 1' ve 'col 2' arasında. Aşağıdaki resim bu anda göreceğiniz şeydir (herşey yolunda):

    list view after column drag

  • yeni bir sütun eklemek için düğmesini, şimdi liste görünümü haline gelir:

    list view after adding column

    Bildirimi 'olduğunu hücre 2 'orijinal konumunu geri aldı.

Hata: Bir TListView (TListColumn) ait

sütunlar onun FOrderTag alandaki sipariş bilgisini tutar. Bir sütunun sırasını değiştirdiğinizde (ya da Index özelliğini ayarlayarak ya da üstbilgiyi sürükleyerek), bu FOrderTag buna göre güncelleştirilir.

Şimdi, TListColumns koleksiyonuna bir sütun eklediğinizde, koleksiyon ilk önce yeni TListColumn ekler ve UpdateCols yöntemini çağırır.

procedure TListColumns.UpdateCols; 
var 
    I: Integer; 
    LVColumn: TLVColumn; 
begin 
    if not Owner.HandleAllocated then Exit; 
    BeginUpdate; 
    try 
    for I := Count - 1 downto 0 do 
     ListView_DeleteColumn(Owner.Handle, I); 

    for I := 0 to Count - 1 do 
    begin 
     with LVColumn do 
     begin 
     mask := LVCF_FMT or LVCF_WIDTH; 
     fmt := LVCFMT_LEFT; 
     cx := Items[I].FWidth; 
     end; 
     ListView_InsertColumn(Owner.Handle, I, LVColumn); 
     Items[I].FOrderTag := I; 
    end; 
    Owner.UpdateColumns; 
    finally 
    EndUpdate; 
    end; 
end; 


Yukarıdaki kod temel API liste görünümü kontrolü, tüm sütun kaldırır ve daha sonra yeniden bunları ekler: Bu D2007 VCL TListColumns arasında UpdateCols yöntemin kodudur. kodu, her eklenen sütunun FOrderTag endeksi sayacı atama şeklini Uyarı:

 Items[I].FOrderTag := I; 

Bu süre içinde bu noktada soldan sağa sütunların sırasıdır. Sütunlar, oluşturma süresinden farklı herhangi bir şekilde sipariş edildiğinde yöntem çağrılırsa, bu sipariş kaybolur. Ve öğeler pozisyonlarını buna göre değiştirmediğinden, hepsi karışır.

Fix: yöntemine aşağıdaki modifikasyon I daha fazla teste (besbelli bu düzeltme, tüm olası durumları kapsıyor 'torno görmek' değil yürütmek için ihtiyaç test olduğunca az çalışmak gibiydi

Ayrıntılar için aşağıdaki yorum):

procedure TListColumns.UpdateCols; 
var 
    I: Integer; 
    LVColumn: TLVColumn; 
    ColumnOrder: array of Integer; 
begin 
    if not Owner.HandleAllocated then Exit; 
    BeginUpdate; 
    try 
    SetLength(ColumnOrder, Count); 
    for I := Count - 1 downto 0 do begin 
     ColumnOrder[I] := Items[I].FOrderTag; 
     ListView_DeleteColumn(Owner.Handle, I); 
    end; 

    for I := 0 to Count - 1 do 
    begin 
     with LVColumn do 
     begin 
     mask := LVCF_FMT or LVCF_WIDTH; 
     fmt := LVCFMT_LEFT; 
     cx := Items[I].FWidth; 
     end; 
     ListView_InsertColumn(Owner.Handle, I, LVColumn); 
    end; 
    ListView_SetColumnOrderArray(Owner.Handle, Count, PInteger(ColumnOrder)); 

    Owner.UpdateColumns; 
    finally 
    EndUpdate; 
    end; 
end; 

size proje klasörüne 'comctrls.pas' değiştirilmiş bir kopyasını koyabilirsiniz paketleri kullanmıyorsanız. Aksi takdirde, çalışma zamanı kod düzeltme eki uygulayabilir veya bir hata raporu gönderebilir ve bir düzeltme için bekleyebilirsiniz.

+0

maalesef bu yukarıdaki satır ekleyerek sonra sorunu :(kodu ile yeniden olabilir ikinci yeni bir sütun ekledikten sonra hala anlatılan davranışı çözmez. – torno

+0

Doğru de sütun ve subitems ekleme ile? Ilk örneği denedin mi ? konumu veya kod parçacığı maalesef i 'şimdi var ve ... pazartesi günü tekrar Önerinize – torno

+0

@torno için teşekkür deneyebilirsiniz? -. Hayır, sadece tek bir sütun eklemeyi pasajı test soru olması gereken okuma iyice ... –

İlgili konular