VB Prático - Tornado o MSFlexGrid editável


Vamos começar mostrando o projeto que será o objetivo deste artigo já em execução. Observe a tela abaixo:

Você esta vendo um formulário com o controle MSFlexGrid exibindo as colunas onde deverão ser informados o número , nome , o bimestre e a ano de referência e as notas das disciplinas: Matemática, Física, Química , Português e Inglês .

Você sabia que o controle MSFlexGrid não permite a edição das células diretamente no Grid ? Não sabia ? Pois é , não tem jeito ... Bem , nos vamos dar um jeito..

O projeto

O formulário principal do nosso projeto possui um menu com as seguintes opções:

Percebeu que não existe botão para incluir nem alterar os dados !! Fazemos isto diretamente no grid , digitando os dados nas células correspondentes. É só posicionar o cursor na célula e começar a digitar os valores correspondentes. A cor amarela da caixa de texto indica que você esta editando uma 'célula' . A mudança para a célula seguinte é automática. Para editar você escolhe a célula e clica sobre ela ou pressiona ENTER ou tecla F2. Veja tela abaixo:

E se você errar o valor da nota informando um valor maior que 10 ou menor que 0 ? O Sistema faz a crítica e exibe uma mensagem informando o erro. E tem mais , as notas maiores que 5 são exibidas na cor azul e as menores que 5 na cor vermelha. Veja abaixo:

Quer visualizar a impressão ? É só selecionar a opção no menu Impressão. Veja o resultado:

Você pode excluir as linhas desejadas selecionando-as e pressionando a tecla Delete ou usando a opção Excluir linhas Selecionadas do menu Arquivo. 

E os dados informados ? Onde serão armazenados ? Bem , o projeto , usando uma filosofia de economia de recursos e pela sua própria simplicidade armazena os dados em um arquivo texto - Boletim.txt . Quando você encerrar o aplicativo o sistema lhe dará uma mensagem solicitando o salvamento ou não dos dados. Veja tela a seguir:

Para encerra esta exposição , ao clicar no hiperlinks para a URL o sistema tentará abrir a página informada , se clicar no endereço eletrônico exibido o sistema chamara seu editor de e-mails padrão.

Agora vamos mostrar como fazer esta 'mágica' comentando as partes mais importantes do código usado no projeto.

O projeto Comentado

O formulário principal foi chamado de - Ogrid. Eí-lo abaixo:

Temos aqui: um controle MSFlexGrid (grid_boletim)  , um controle caixa de texto (text1) , três labels : label1(Boletim Escolar 2001 - JcmSoft) , label2 e label3 , um controle image (figura do menino) e um menu criado no Menu Editor (Opção Tool do menu do VB).

A seção General Declarations do formulário contém o código onde declaramos as variáveis e as API´s usadas no projeto

Option Explicit

'declarações a api para exibir a caixa de dialog da impressora
Private Declare Function PrinterProperties Lib "winspool.drv" _
(ByVal hwnd As Long, ByVal hPrinter As Long) As Long

Private Declare Function OpenPrinter Lib "winspool.drv" _
Alias "OpenPrinterA" (ByVal pPrinterName As String, _
phPrinter As Long, pDefault As PRINTER_DEFAULTS) As Long

Private Declare Function ClosePrinter Lib "winspool.drv" _
(ByVal hPrinter As Long) As Long

Private Type PRINTER_DEFAULTS
pDatatype As Long ' String
pDevMode As Long
pDesiredAccess As Long
End Type

Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
Private Const PRINTER_ACCESS_ADMINISTER = &H4
Private Const PRINTER_ACCESS_USE = &H8
Private Const PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or _
PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)

'------------------API para executar browser/E-mail-------------------------------------------------
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, _
ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long


'---------declarações do sistema-------------------------------------
Private ArquivoDados As String ' Arquivo com os dadaos do grid
Const NovaLinha As String = ">*" ' Indica uma nova linha
Private ControlVisible As Boolean ' Se o controle esta visivel ou nao
Private LastRow As Long ' Ultima linha em que se editou
Private LastCol As Long ' ultima coluna em que se editou

No evento Form_Load , temos o seguinte código:

Private Sub Form_Load()
Dim i As Long
Dim caminho As String
caminho = App.Path

With Label2
  .AutoSize = True
  .ForeColor = vbBlue
  .Font.Underline = True
  .Caption = "http://www.geocities.com/macoratti"
End With

With Label3
  .AutoSize = True
  .ForeColor = vbBlue
  .Font.Underline = True
  .Caption = "macoratti@riopreto.com.br"
End With

ArquivoDados = caminho & IIf(Right$(caminho, 1) = "\", "", "\") & "Boletim.txt"
OcultarControles
CabecalhoGrid
LerDados

End Sub

Aqui configuramos as labels usadas nos hiperlinks . definimos o arquivo de dados e chamamos as procedures  que irão fazer o programa rodar.

Como fazemos a edição no grid ? Para isto usamos o controle caixa de texto - text1 - e quando o cursor estiver selecionando uma célula ao pressionar a tecla Enter ou F2 ou clicar na célula escolhida , para simular uma edição da célula , fazemos o seguinte:

A partir dai tudo se passa para o usuário como se ele estivesse digitando diretamente na célula , mas na verdade esta digitando na caixa de texto. Ao encerrar a entrada de dados apenas atribuimos o informado na caixa de texto para célula correspondente no grid. 

Abaixo temos o código envolvido na seguinte sequência:

Private Sub Grid_Boletim_KeyPress(KeyAscii As Integer)
Select Case KeyAscii
' Editar ao teclar ENTER
Case vbKeyReturn
   KeyAscii = 0
   ExibirCelula
' Cancelar ao pressionar ESC
Case vbKeyEscape
  KeyAscii = 0
  AtribuiValorCelula
' Editar ao pressinar qualquer tecla
Case 32 To 255
  ExibirCelula
  With Text1
     If .Visible Then
      .Text = Chr$(KeyAscii)
      .SelStart = Len(.Text) + 1
    End If
  End With
End Select
End Sub

Abaixo a procedure ExibirCelula:

Private Sub ExibirCelula()
Static OK As Boolean
'
' Se for celula fixa , sair
If Grid_boletim.Col <= Grid_boletim.FixedCols - 1 Or Grid_boletim.Row <= Grid_boletim.FixedRows - 1 Then
   Exit Sub
End If

If OK Then Exit Sub
OK = True
'
OcultarControles
'
LastRow = Grid_boletim.Row
LastCol = Grid_boletim.Col
'
' Nova Celula
With Grid_boletim
  If .TextMatrix(LastRow, 0) = NovaLinha Then
    .Rows = .Rows + 1
    .TextMatrix(LastRow, 0) = LastRow
    .TextMatrix(.Rows - 1, 0) = NovaLinha
  End If
End With
'
Select Case LastCol
Case Else

Text1.Move Grid_boletim.CellLeft - Screen.TwipsPerPixelX, Grid_boletim.CellTop + 550 - Screen.TwipsPerPixelY, Grid_boletim.CellWidth + Screen.TwipsPerPixelX * 2, Grid_boletim.CellHeight + Screen.TwipsPerPixelY * 2
Text1.Text = Grid_boletim.Text

If Len(Grid_boletim.Text) = 0 Then
   If LastRow > 1 Then
       Text1.Text = Grid_boletim.TextMatrix(LastRow - 1, LastCol)
   End If
End If

Text1.Visible = True

If Text1.Visible Then
  Text1.ZOrder
  Text1.SetFocus
End If
End Select
'
ControlVisible = True
'
OK = False
End Sub

As rotinas para Ler os dados e Gravar os dados utilizam os velhos comandos : Open, Line Input , Print.

Private Sub LerDados()
' Ler dados e preencher o grid
Dim nFic As Long
Dim r As Long
Dim c As Long
Dim texto As String
'
' se nao existe o arquivo sai
If Len(Dir$(ArquivoDados)) = 0 Then
   MsgBox "O arquivo de dados não foi localizado !!!"
   Exit Sub
End If
'
r = Grid_boletim.Rows - 2
nFic = FreeFile
Open ArquivoDados For Input As nFic

Do While Not EOF(nFic)
r = r + 1
Grid_boletim.Rows = r + 2
Grid_boletim.TextMatrix(r, 0) = r
For c = 1 To Grid_boletim.Cols - 1
  If Not EOF(nFic) Then
     Line Input #nFic, texto
     Grid_boletim.TextMatrix(r, c) = texto
  Else
     Exit For
  End If
Next
Loop
Close nFic
'
With Grid_boletim
  .TextMatrix(.Rows - 1, 0) = NovaLinha
  LastRow = .Rows - 1
  LastCol = 1
  .Col = LastCol
  .Row = LastRow
  .RowSel = LastRow
  .ColSel = LastCol
End With
End Sub


Private Sub GravarDados()
' Gravar os dados do grid
Dim nFic As Long
Dim r As Long
Dim c As Long
'
nFic = FreeFile
Open ArquivoDados For Output As nFic
' Não guardar a ultima lina
For r = 1 To Grid_boletim.Rows - 2
   For c = 1 To Grid_boletim.Cols - 1
        Print #nFic, Grid_boletim.TextMatrix(r, c)
   Next
Next
Close nFic
End Sub

Para visualizar e imprimir o grid usamos a mesma procedure - ImprimeGrid - somente alterando o objeto : de form para printer. Ah, antes de imprimir usamos uma API para exibir a caixa de diálogo da impressora padrão.  O código da impressão é o seguinte:

Private Sub ImprimeGrid(ByVal ptr As Object, ByVal flx As MSFlexGrid, ByVal xmin As Single, ByVal ymin As Single)
Const GAP = 60

Dim xmax As Single
Dim ymax As Single
Dim X As Single
Dim c As Integer
Dim r As Integer

With ptr.Font
  .Name = Grid_boletim.Font.Name
  .Size = Grid_boletim.Font.Size
End With

With Grid_boletim
' verificar a largura.
xmax = xmin + GAP
For c = 0 To .Cols - 1
   xmax = xmax + .ColWidth(c) + 2 * GAP
Next c

' imprime cada linha
ptr.CurrentY = ymin
For r = 0 To .Rows - 1
 ' desenha uma linha acima desta linha.
   If r > 0 Then ptr.Line (xmin, ptr.CurrentY)-(xmax, ptr.CurrentY)
   ptr.CurrentY = ptr.CurrentY + GAP

  ' Imprime o conteudo da linha
  X = xmin + GAP
  For c = 0 To .Cols - 1
     ptr.CurrentX = X
     ptr.Print BoundedText(ptr, .TextMatrix(r, c), .ColWidth(c));
     X = X + .ColWidth(c) + 2 * GAP
  Next c
  ptr.CurrentY = ptr.CurrentY + GAP

  ' Vai para proxima linha
  ptr.Print
Next r
ymax = ptr.CurrentY

' desenha uma caixa
ptr.Line (xmin, ymin)-(xmax, ymax), , B

' Desenha linhas
  X = xmin
  For c = 0 To .Cols - 2
    X = X + .ColWidth(c) + 2 * GAP
    ptr.Line (X, ymin)-(X, ymax)
  Next c
End With
End Sub

A chamada a API é feita pela função abaixo:

Public Function DisplayPrinterProperties(DeviceName As String) As Boolean

'Exibe a caixa de dialogo da impressora
'PARAMETRO: DeviceName: O nome da impressora padrao
'COMO CHAMAR : DisplayPrinterProperties Printer.DeviceName

On Error GoTo ErrorHandler
Dim lAns As Long, hPrinter As Long
Dim typPD As PRINTER_DEFAULTS

typPD.pDatatype = 0
typPD.pDesiredAccess = PRINTER_ALL_ACCESS
typPD.pDevMode = 0
lAns = OpenPrinter(Printer.DeviceName, hPrinter, typPD)
If lAns <> 0 Then
   lAns = PrinterProperties(Me.hwnd, hPrinter)
   DisplayPrinterProperties = lAns <> 0
End If

ErrorHandler:
If hPrinter <> 0 Then ClosePrinter hPrinter

End Function

Abordamos aqui somente alguns dos aspectos envolvidos no projeto (não comentamos os formulários frmabout nem o formulário frmvisualiza) , é claro que você poderá expandir e melhorá-lo adequando as suas necessidades , se for o caso. 

Em todo o caso clique  no link para pegar o projeto completo: OGrid.zip ( 10 Kb ) 

Tchau


Copyright (c) 2001 - José Carlos Macoratti e amigos da web