Veremos como adicionar uma barra de progresso (ou qualquer outro componente Delphi) a um controle ListView. A maioria dos gerenciadores de download, utilizam um ListView para visualização do andamento do carregamento para cada item. O ListView exibe uma lista de items de várias maneiras.
Um ProgressBar exibe uma barra de progresso simples. Barras de progresso proporcionam aos usuários visualização sobre o progresso de um procedimento dentro de uma aplicação. Veremos como colocar uma barra de progresso em uma coluna do ListView.
ProgressBar em ListView
Quando atribuímos vsReport à propriedade ViewStyle de um ListView, cada item aparece em sua própria linha com as informações organizadas em colunas. A coluna mais à esquerda, contém o pequeno ícone e o rótulo e as colunas subseqüentes contêm subitens conforme especificados pela aplicação. Provavelmente todo dia vemos isto ao utilizarmos o Windows Explorer em modo de visão Details.
Suponhamos que temos um ListView em um formulário com vsReport em ViewStyle. Duas colunas são definidas utilizando a propriedade Columns: a primeira coluna contém o nome do item, enquanto a segunda coluna deveria conter um indicador de progresso.
Quando clicarmos o botão Adicionar um novo item com uma barra de progresso deveria ser adicionado à lista:
procedure TForm1.AddItemButtonClick(Sender: TObject);
const
pbColumnIndex = 1;
pbMax = 100;
var
li: TListItem;
lv: TListView;
pb: TProgressBar;
pbRect : TRect;
begin
lv := ListViewEx1;
li := lv.Items.Add;
li.Caption := 'Item ' + IntToStr(lv.Items.Count);
pb := TProgressBar.Create(nil);
pb.Parent := lv;
li.Data := pb;
pbRect := li.DisplayRect(drBounds);
pbRect.Left := pbRect.Left +
lv.Columns[-1 + pbColumnIndex].Width;
pbRect.Right := pbRect.Left +
lv.Columns[pbColumnIndex].Width;
pb.BoundsRect := pbRect;
end; //AddItemButtonClick
Quando clicamos no botão um novo item de lista (TListItem) é acrescentado ao controle ListView (chamado ListViewEx1). Uma barra de progresso é criada, uma referência para a barra de progresso é adicionada à propriedade Data do item de lista e, finalmente, uma barra de progresso é colocada na coluna especificada por pbColumnIndex. Alguns cálculos são utilizados para fazer a barra de progresso aparecer no lugar certo.
Quando quisermos remover um item da lista, precisamos ter certeza de que a memória da barra de progresso “anexada” seja liberada e todas as barras de progresso sob a selecionada são movidas uma posição para cima (como acontece com todos os itens restantes de um ListView):
procedure TForm1.RemoveItemButtonClick( Sender: TObject);
var
lv: TListView;
li: TListItem;
i, idx: integer;
pb: TProgressBar;
begin
lv := ListViewEx1;
li := lv.Selected;
if li <> nil then
begin
idx := li.Index;
TProgressBar(li.Data).Free;
lv.Items.Delete(idx);
for i := idx to -1 + lv.Items.Count do
begin
li := lv.Items.Item[i];
pb := TProgressBar(li.Data);
pb.Top := pb.Top -
(pb.BoundsRect.Bottom -
pb.BoundsRect.Top);
end;
end;
end; //RemoveItemButtonClick
Apenas para testarmos, adicionaremos algum código dentro do evento OnTimer de um Timer, para ter algum progresso nas barras (colocar um Timer em um formulário e utilizar o código abaixo para o evento OnTimer). Obviamente, em aplicações reais atualizaríamos a barra de progresso de um item com base em algum critério, só precisamos localizar “a” barra de progresso (“armazenada“ na propriedade Data de um item):
procedure TForm1.Timer1Timer(
Sender: TObject);
var
idx: integer;
pb: TProgressbar;
lv: TListView;
begin
lv := ListViewEx1;
if lv.Items.Count = 0 then Exit;
idx := Random(lv.Items.Count);
pb := TProgressBar(lv.Items[idx].Data);
if pb.Position < pb.Max then
pb.StepIt
else
pb.Position := 0;
end;//Timer1Timer
Rodamos a aplicação, clicamos no botão Adicionar várias vezes e vemos como se comporta o progresso. Agora, tentemos redimensionar qualquer coluna... uuoopps! Quando redimensionamos as colunas necessárias para reposicionar a barra de progresso, ListView não fornece nenhum evento para tratar o redimensionando de colunas!
TListViewEx - ListView com eventos de redimensionamento de colunas
A solução para tratar o redimensionamento de colunas, consiste em utilizar um ListView derivado: TListViewEx. O TListViewEx (componente que esta disponível junto com o exemplo do artigo) é um descendente de TListView com os eventos BeginColumnResize, ColumnResize e EndColumnResize publicados. Agora, com o poder do TListViewEx, podemos controlar facilmente o redimensionamento de colunas. Veremos como tratar o evento OnEndColumnResize para ajustar a largura e a margem esquerda das barras de progresso:
procedure TForm1.ListViewEx1EndColumnResize(
sender: TCustomListView;
columnIndex,
columnWidth: Integer);
var
lv: TListViewEx;
idx: integer;
pb: TProgressBar;
begin
lv := ListViewEx1;
if columnIndex = 0 then
begin
for idx := 0 to -1 + lv.Items.Count do
begin
pb := TProgressBar(lv.Items[idx].Data);
pb.Left := columnWidth;
end;
end;
if columnIndex = 1 then
begin
for idx := 0 to -1 + lv.Items.Count do
begin
pb := TProgressBar(lv.Items[idx].Data);
pb.Width := columnWidth;
end;
end;
end;