VB - Usando DBGrid no modo não vinculado (Unbound mode)


O controle DBGrid pode ser usado no modo vinculado (Unbound) e no modo não vinculado(DataMode=1). O modo vinculado é o mais utilizado , neste modo o controle é conectado a uma fonte de dados geralmente a conexão feita com um controle de dados vinculados de onde se obtêm a fonte de dados. (Definimos a propriedade DataSource do DBGrid para um objeto de dados vinculados como um Data Control).

O modo não vinculado é pouco usado e não muito documentado. Neste modo não existe uma conexão do controle a uma fonte de dados. E se você decidir usar este modo terá que fornecer via código todo o tratamento e manutenção dos dados. Para usar o DBGrid no modo não vinculado definimos a propriedade DataMode igual a 1.

Embora de mais trabalho ao programador o DBGrid no modo vinculado é uma ferramenta muito útil para tratar dados dinâmicos de uma maneira mais eficiente e rápida que no modo vinculado.

No artigo -  Trabalhando com o DBGrid no modo Desvinculado - já dei umas pinceladas sobre o assunto. Hoje vamos ir mais fundo...

Neste artigo vou mostrar como usar o controle DBGrid no modo não vinculado através de um exemplo simples onde iremos usar um arquivo texto a partir do qual os dados serão lidos e gravados . Este arquivo será a nossa fonte de dados. Lembre-se que ao encerrar sua aplicação e fechar o Grid os dados que estão na memória serão perdidos se não forem gravados. Iremos usar um vetor para carregar os dados do arquivo texto e a seguir preencher o DBGrid com os dados. talvez este não seja o melhor caminho a escolher dependendo da quantidade de dados que você tenha que manter. Se você pretende preencher um grid com 1.000.000 de linhas e outras 5.000 colunas provavelmente você terá problemas de memória com sua aplicação. (Geralmente usa-se um banco de dados para armazenar as informações mas por questão de simplicidade irei usar um arquivo texto.)

Para poder trabalhar com o DBGrid no modo não vinculado você terá que conhecer os eventos que deverá tratar via código. Os principais eventos são :

Vejamos o método UnBoundReadData em mais detalhes : Sua sintaxe é :

Private Sub DBGrid1_UnboundReadData(ByVal RowBuf As MSDBGrid.RowBuffer, StartLocation As Variant, ByVal ReadPriorRows As Boolean)
End Sub

- RowBuffer - é um objeto OLE definido pelo Grid e usado para trocar dados entre o grid e os eventos de dados não vinculados. A seguir veremos suas propriedades que você pode visualizar através do Object Browser (Menu View - Object Browser ou F2)

DBGrid - Métodos do modo não vinculado RowBuffer - Membros da classe RowBuffer

- RowCount - Long - retorna o número de linhas que o evento espera processar.
-
ColumnCount - Integer - retorna o número de colunas no buffer. Este propriedade é somente leitura
-
ColumnName(Col) String - retorna o nome da coluna do grid indicada pelo parâmetro Col. Este propriedade é somente leitura
-
Bookmark Variant - define e/ou retorna o bookmark para a linha especificada no buffer. A linha RowBuffer row é passada como argumento.
-
Value(Row, Col) Variant - usada para especiricar o valor do dado associado com a linha e a coluna RowBuffer.

No evento UnBoundReadData , o objeto RowBuffer é criado pelo grid com valores e bookmarks definidos como Null. RowBuf é passado para o evento com a expectativa de que o evento definirá os valores e bookmarks necessários.

Nos eventos UnboundAddData e UnboundWriteData , os dados que o usuário alterou é tratado em RowBuf.Value(0,Col). Qualquer coluna com dados não alterados tera RowBuf.Value(0,Col) igual a Null. O programador salva os valores alterados (não Null) na fonte de dados (geralmente em um vetor). Somente valores não nulos indica alteração de dados.

- StartLocation - variant - define a linha 'antes' dos dados desejados. O valor depende do argumento : ReadPriorRows.

- ReadPriorRows - boolean - indica a direção na qual o grid esta requisitando os dados. Se o grid determinar um StartLocation para a linha 46 , um RowCount igual 5 e se a propriedade ReadPriorRows for definida como True, então o evento UnboundReadData irá retornar a seguinte informação no RowBuffer:

   RowBuf.Value(0, col) = dados para a linha 45
   RowBuf.Value(1, col) = dados para a linha 44
   RowBuf.Value(2, col) = dados para a linha 43
   RowBuf.Value(3, col) = dados para a linha 42
   RowBuf.Value(4, col) = dados para a linha 41

Se o valor de ReadPriorRows no entanto for definido como false, então o evento irá retornar os seguintes valores para RowBuffer

RowBuf.Value(0, col) = dados para a linha 47
RowBuf.Value(1, col) = dados para a linha 48
RowBuf.Value(2, col) = dados para a linha 49
RowBuf.Value(3, col) = dados para a linha 50
RowBuf.Value(4, col) = dados para a linha 51


Nota: O que é um bookmark no modo não vinculado ? São dados do tipo variant usados pelo grid para identificar de forma única uma linha dentro dos dados a serem exibidos. Geralmente eles são fornecidos pelos eventos UnboundReadData and UnboundAddData e são passados para o grid e a partir do grid. O grid trata os bookmarks como pacotes de informação binárias que não podem ser interpretadas. Para o Grid um bookmark é um pedaço de dados que contém um número específico em uma dada ordem.

Usando o DBGrid no modo não vinculado ( Unbound mode)

Nosso objetivo será ler os dados de um arquivo texto chamado livros.txt e exibir estes dados em um DBGrid usando o modo não vinculaod. Vamos implementar as seguintes funcionalidades em nosso projeto:

  1. Ler e exibir dados
  2. Salvar dados
  3. Alterar dados
  4. Excluir dados

Inicie um novo projeto no VB e inclua o componente DBGrid no seu projeto. A seguir inclua no formulário padrão um controle DBGrid , dois botões de comando e três caixas de texto, conforme layout abaixo:

O conteúdo do arquivo texto a ser exibido contém dados de livros e seus autores: Titulo ,ISBN e URL. O arquivo livros.txt é exibido abaixo:

4
"ASP , ADO , Banco de dados na Internet","85-85943-96-3","www.macoratti.net"
"Visual Basic Total","85-7001-735-9","www.editoracampus.com.br"
"Visual Basic Banco de dados","85-373-794-5","www.macoratti.net"
"Oracle e Visual Basic","85-789-345-67","www.oracle.com"
"VB e MySQL","85-471-24268-3","www.mysql.com"

Ao executar a aplicação teremos o seguinte resultado:

Para incluir um registro no arquivo e exibir no grid basta digitar as informações nas caixas de texto e clicar em - Incluir registro. Os registros serão salvos quando o usuário sair da aplicação.

Vejamos a seguir o código comentado do projeto:

- Na seção General Declarations do formulário form1.frm temos as definições das variáveis e tipos que serão usados no projeto:

Option Explicit

'define o tipo de dados que vamos ler
Private Type LivroInfo
     Titulo As String
      ISBN As String
      URL As String
End Type

'
define o total de linhas no arquivo a ler
Private TotalLivros As Integer
' define o vetor como do tipo LivroInfo
Private LivrosInfo() As LivroInfo

- A seguir nos eventos do formulário - form1.frm:

Private Sub Form_Activate()
     txtTitulo.SetFocus
End Sub

' carrega os dados
Private Sub Form_Load()
     CarregaDados
End Sub

 

A rotina CarregaDados é mostrada abaixo: Ela abre o arquivo livros.txt  e preenche o vetor com os dados.

'carrega os dados do arquivo
Private Sub CarregaDados()
Dim fnum As Integer
Dim fnome As String
Dim i As Integer

fnum = FreeFile
'abre o arquivo texto com os dados a exibir no grid
fnome = App.Path & "\livros.txt"
Open fnome For Input As #fnum

Input #fnum, TotalLivros
'redimensiona o vetor com o total de linhas encontrados no arquivo texto
ReDim LivrosInfo(0 To TotalLivros)

'preenche o vetor com os dados do arquivo texto
For i = 0 To TotalLivros
   With LivrosInfo(i)
      Input #fnum, .Titulo, .ISBN, .URL
   End With
Next i

'fecha o arquivo texto lido
Close #fnum
End Sub

O código associado ao evento Click do botão - Incluir registro - é dado a seguir. Ele redimensiona o vetor usado para conter o dado.

' inclui um novo registro no arquivo
Private Sub cmdInclui_Click()
TotalLivros = TotalLivros + 1

'redimensiona o vetor com o novo total de linhas do arquivo
ReDim Preserve LivrosInfo(0 To TotalLivros)

'escreve no arquivo texto o registro
With LivrosInfo(TotalLivros)
   .Titulo = txtTitulo.Text
   .ISBN = txtISBN.Text
   .URL = txtURL.Text
End With

'atualiza o grid com exibição dos novos dados
DBGrid1.Refresh
End Sub

Agora o evento UnboundReadData que lê os dados para exibição no grid.

' Carrega os dados no controle dbgrid
Private Sub DBGrid1_UnboundReadData(ByVal RowBuf As MSDBGrid.RowBuffer, PosicaoInicial As Variant, ByVal LeLinha As Boolean)

Dim dr As Integer
Dim linha_num As Integer
Dim r As Integer
Dim linhas_retornadas As Integer

' verifica qual a direção da leitura
If LeLinha Then
   dr = -1
Else
   dr = 1
End If

' verifica se a PosicaoInicial é nulo
If IsNull(PosicaoInicial) Then
  ' Le do fim ou do inicio dos dados
   If LeLinha Then
    ' le de a partir do final
      linha_num = RowBuf.RowCount - 1
   Else
     ' le a partir do inicio
     linha_num = 0
   End If
Else
  ' verifica onde comecamos a leitura
  linha_num = CLng(PosicaoInicial) + dr
End If

' copia os dados do vetor para dentro do buffer = RowBuf.
linhas_retornadas = 0

For r = 0 To RowBuf.RowCount - 1
  ' nao le além do final dos dados
  If linha_num < 0 Or linha_num > TotalLivros Then Exit For

  ' copia os dados para o buffer da linha
  With LivrosInfo(linha_num)
     RowBuf.Value(r, 0) = .Titulo
     RowBuf.Value(r, 1) = .ISBN
     RowBuf.Value(r, 2) = .URL
   End With

  ' usa linha_num como um bookmark.
  RowBuf.Bookmark(r) = linha_num

  linha_num = linha_num + dr
  linhas_retornadas = linhas_retornadas + 1
Next r

' define o numero de linhas retornardo
RowBuf.RowCount = linhas_retornadas
End Sub

agora o código do evento UnboundAddData que inclui uma linha no arquivo.


    
' Inclui uma nova entrada
Private Sub DBGrid1_UnboundAddData(ByVal RowBuf As MSDBGrid.RowBuffer, NewRowBookmark As Variant)
    
    ' atualiza o total de linhas e define o novo tamanho do vetor
    TotalLivros = TotalLivros + 1
    ReDim Preserve LivrosInfo(0 To TotalLivros)

    ' define o bookmark para a nova entrada
    NewRowBookmark = TotalLivros

    ' Salva os novos dados
    With LivrosInfo(TotalLivros)
        If Not IsNull(RowBuf.Value(0, 0)) Then
            .Titulo = RowBuf.Value(0, 0)
        Else
            .Titulo = DBGrid1.Columns(0).DefaultValue
        End If
        If Not IsNull(RowBuf.Value(0, 1)) Then
            .ISBN = RowBuf.Value(0, 1)
        Else
            .ISBN = DBGrid1.Columns(1).DefaultValue
        End If
        If Not IsNull(RowBuf.Value(0, 2)) Then
            .URL = RowBuf.Value(0, 2)
        Else
            .URL = DBGrid1.Columns(2).DefaultValue
        End If
    End With
End Sub

 

o código do evento UnboundDeleteRow que exclui uma linha do arquivo.

' exclui a entrada
Private Sub DBGrid1_UnboundDeleteRow(Bookmark As Variant)
Dim r As Integer

    ' preenche a linha excluida.
    For r = Bookmark + 1 To TotalLivros
        LivrosInfo(r - 1) = LivrosInfo(r)
    Next r

    'atualiza o novo valor total de linhas do arquivo texto
    TotalLivros = TotalLivros - 1
End Sub

a rotina do evento UnboundWriteData que escreve os dados no grid.

' salva os dados atualizados pelo controle
Private Sub DBGrid1_UnboundWriteData(ByVal RowBuf As MSDBGrid.RowBuffer, WriteLocation As Variant)
' atualiza somente os valores que foram alterados
  With LivrosInfo(CInt(WriteLocation))
     If Not IsNull(RowBuf.Value(0, 0)) Then .Titulo = RowBuf.Value(0, 0)
     If Not IsNull(RowBuf.Value(0, 1)) Then .ISBN = RowBuf.Value(0, 1)
     If Not IsNull(RowBuf.Value(0, 2)) Then .URL = RowBuf.Value(0, 2)
  End With
End Sub
 

O código associado ao evento Unload do formulário. Este código será acionado quando o usuário fechar o formulário o clicar no botão Sair. Ele dispara a rotina SalvaDados que irá gravar no arquivo textos os dados incluídos.

 
' Salva os dados
Private Sub Form_Unload(Cancel As Integer)
   If (MsgBox("Deseja Salvar dados !", vbYesNo, "Salva dados") = vbYes) Then
        SalvaDados
End If
End Sub
 
Finalmente o código da rotina SalvaDados que grava os dados no arquivo texto livros.txt.
 
' Salva os dados no arquivo
Private Sub SalvaDados()
Dim fnum As Integer
Dim fnome As String
Dim i As Integer

    'abre o arquivo texto
    fnum = FreeFile
    fnome = App.Path & "\livros.txt"
    Open fnome For Output As #fnum

    'escreve o novo total de linhas do arquivo
    Write #fnum, TotalLivros
    
    'escreve os dados no arquivo texto
    For i = 0 To TotalLivros
        With LivrosInfo(i)
            Write #fnum, .Titulo, .ISBN, .URL
        End With
    Next i

    'fecha o arquivo
    Close #fnum
End Sub

 

 
Com isto terminamos este artigo , nele você aprendeu a como usar o DBGrid no modo não vinculado. 
 
Baixe aqui o projeto completo : DBGridUB.zip
 
Para saber mais sobre o assunto visite:
 
- FILE: DBGRIDUB.EXE Uses DBGRID in an Unbound Mode
- www.vb-helper.com
- Baixe o exemplo da microsoft sobre DBGrid não vinculado em :DBGRIDUB.EXE
 
Até a próxima dica VB... 

José Carlos Macoratti