DataGridView – Sequência de Movimento (Após tecla ENTER)
A DataGridView tem como movimento
após a tecla ENTER, de linha em linha, e não de coluna em coluna. Quando se está
a preencher registos, em que se preenche um registo de cada vez, é prático que o
utilizador após pressionar a tecla ENTER desloque a selecção para a coluna seguinte
e não para o próximo registo (próxima linha).
Para conseguirmos alterar este comportamento
podemos, no evento KeyDown, verificar qual a tecla pressionada e alterá-la. No entanto,
e se a célula estiver a ser editada, é necessário fazer o
override à ProcessCmdKey.
Fica um exemplo de como fazer:
Protected Overrides
Function ProcessCmdKey(ByRef msg
As System.Windows.Forms.Message, ByVal
keyData As System.Windows.Forms.Keys)
As Boolean
'
Verifica se a tecla pressionada foi a ENTER e se a célula está a ser editada
If
keyData = Keys.Enter And
Me.DataGridView1.IsCurrentCellInEditMode Then
'
Executa um TAB
SendKeys.Send("{TAB}")
' Ignora a tecla
pressionada
Return True
Else
' Executa o processo normal
Return
MyBase.ProcessCmdKey(msg, keyData)
End If
End Function
' Quando é pressionada uma tecla
Private Sub DataGridView1_KeyDown(ByVal
sender As Object,
ByVal e As System.Windows.Forms.KeyEventArgs)
Handles DataGridView1.KeyDown
'
Verifica se a tecla é a ENTER
If
e.KeyCode = Keys.Enter Then
'
Desabilita a tecla pressionada
e.SuppressKeyPress = True
With
Me.DataGridView1
' Caso seja a ultima coluna
salta para a primeira da próxima linha
If .CurrentCell.ColumnIndex
= .ColumnCount - 1 Then
' Caso não seja
a última linha
If .CurrentRow.Index < .RowCount - 1 Then
.CurrentCell = .Item(0, .CurrentRow.Index + 1)
End If
Else
' Move para a próxima coluna
.CurrentCell = .Item(.CurrentCell.ColumnIndex + 1, .CurrentRow.Index)
End If
End With
End If
End Sub
@@IDENTITY – Verificando Registo Inserido
Quando se inserem registos, é frequente
necessitarmos do último número de identificação inserido (ID) para mostrarmos ao
utilizador ou para utilizarmos na inserção de outros registos. Por exemplo se inserirmos
um novo utilizador e de seguida usarmos o seu número de registo para inserir a sua
lista de favoritos, temos de efectuar os seguintes passos:
1 – Inserir o registo do utilizador
2 – Verificar-mos qual o registo inserido
(ID)
3 – Inserir os favoritos utilizando
o ID recolhido
Para simplificar este processo podemos
utilizar o comando T-SQL -
@@IDENTITY - que retorna o valor gerado pelo
SQL Statement. Ou seja, no momento que inserimos o registo, verificamos
qual o número do registo inserido.
Fica aqui um exemplo de como simplificar
este processo:
' Texto de ligação à base de dados
Dim myConnectionString As String = _
"Data Source=.\SQLEXPRESS;AttachDbFilename='c:\MYDATABASE.MDF';"
& _
";Integrated Security=True;User Instance=True"
'
Comando que irá inserir dados na tabela "MyTable" em que o campo "username" será
' passados através de parâmetros e retornará
o ID do registo inserido
Dim SQL As
String = "INSERT INTO myTable([username]) VALUES
(@username); Select @@IDENTITY;"
'
Cria uma nova ligação à base de dados
Dim connection As
New SqlConnection(myConnectionString)
'
Criação do comando indicando a instrução e a ligação
Dim command As
New SqlCommand(SQL, connection)
command.Parameters.Add("@username", SqlDbType.VarChar).Value =
"teste"
connection.Open()
' Insere o registo e guarda na variável
IdRegistoInserido o ID
Dim IdRegistoInserido As Integer = command.ExecuteScalar()
Debug.WriteLine("Registo Inserido:
" + IdRegistoInserido.ToString)
' Fecha a ligação e limpa as variáveis
connection.Close()
connection = Nothing
command = Nothing
Deste modo reduzimos
um processo, de verificação do registo inserido, melhorando a performace da aplicação.
PS: Como sempre, qualquer
dúvida, comentário ou correcção ao artigo é sempre bem vinda!
O VB.NET tem uma propriedade nos controlos que permite-os redimensionar e posicionar no formulário através da opção Anchor. Este ancoramento permite que um controlo aumente/diminua ou desloque-se quando o formulário é redimensionado, melhorando bastante esteticamente e funcionalmente a aplicação.
O Visual Basic 6 não tem esta possibilidade de uma forma automática sendo necessário recorrer a cálculos para o fazer. Uma das opções mais comuns que os programadores utilizam para ultrapassar este processo demorado e normalmente complexo é retirar a possibilidade de aumentar o tamanho do formulário. Mas isto não é algo que o utilizador esteja habituado em ambiente Windows nem é algo que traga valor acrescentado à aplicação.
Uma das hipóteses que resolve este problema é utilizando as classes clsAutoPositioner.cls e clsAutoPositionerItem.cls. Estas classes são de código livre, encontram-se disponíveis na Internet e permitem efectuar com grande facilidade este processo. Podem ver o exemplo inicial (Figura 1) e o resultado final (Figura 2) .
(Figura 1)
(Figura 2) Para as utilizarem é necessário criar duas classes com o seguinte código:
clsAutoPositioner.cls
‘ ***
‘ *** Início da classe clsAutoPositioner
‘ ***
Option Explicit
Dim m_oAssignments As New Collection
Public Function AddAssignment(ctl As Object, ctlRelative As Object, tPosType As tPOSITION_TYPE)
Dim x As New clsAutoPositionerItem
Set x.oCTL = ctl
Set x.oREL = ctlRelative
x.tPosType = tPosType
Select Case x.tPosType
Case tCONTAINER_RELATIVE_POS_RIGHT
x.lValue = x.oREL.Width - x.oCTL.Left
Case tCONTAINER_RELATIVE_POS_BOTTOM
x.lValue = x.oREL.Height - x.oCTL.Top
Case tCONTAINER_WIDTH_DELTA_RIGHT
x.lValue = x.oREL.Width - (x.oCTL.Left + x.oCTL.Width)
Case tCONTAINER_HEIGHT_DELTA_BOTTOM
x.lValue = x.oREL.Height - (x.oCTL.Top + x.oCTL.Height)
Case tCONTROL_RELATIVE_SAME_POS_VERTICAL
x.lValue = x.oCTL.Left - x.oREL.Left
Case tCONTROL_RELATIVE_SAME_POS_HORIZONTAL
x.lValue = x.oCTL.Top - x.oREL.Top
End Select
m_oAssignments.Add x
End Function
Public Function RefreshPositions()
Dim i As Long
Dim x As clsAutoPositionerItem
Dim erg As Long
For i = 1 To m_oAssignments.Count
Set x = m_oAssignments.Item(i)
Select Case x.tPosType
Case tCONTAINER_RELATIVE_POS_RIGHT
erg = x.oREL.Width - x.lValue
If (erg > 0) Then x.oCTL.Left = erg
Case tCONTAINER_RELATIVE_POS_BOTTOM
erg = x.oREL.Height - x.lValue
If (erg > 0) Then x.oCTL.Top = erg
Case tCONTAINER_WIDTH_DELTA_RIGHT
erg = x.oREL.Width - x.oCTL.Left - x.lValue
If (erg > 0) Then x.oCTL.Width = erg
Case tCONTAINER_HEIGHT_DELTA_BOTTOM
erg = x.oREL.Height - x.oCTL.Top - x.lValue
If (erg > 0) Then
x.oCTL.Height = erg
Else
erg = erg
End If
Case tCONTROL_RELATIVE_SAME_POS_VERTICAL
erg = x.oREL.Left + x.lValue
x.oCTL.Left = erg
Case tCONTROL_RELATIVE_SAME_POS_HORIZONTAL
erg = x.oREL.Top + x.lValue
x.oCTL.Top = erg
End Select
Next
End Function
clsAutoPositionerItem.cls
‘ ***
‘ *** Início da classe clsAutoPositionerItem
‘ ***
Public Enum tPOSITION_TYPE
tCONTAINER_RELATIVE_POS_RIGHT
tCONTAINER_RELATIVE_POS_BOTTOM
tCONTAINER_WIDTH_DELTA_RIGHT
tCONTAINER_HEIGHT_DELTA_BOTTOM
tCONTROL_RELATIVE_SAME_POS_VERTICAL
tCONTROL_RELATIVE_SAME_POS_HORIZONTAL
End Enum
Public oCTL As Object
Public <?xml namespace="" ns="urn:schemas-microsoft-com:office:smarttags" prefix="st1" ?>oRELAs Object
Public tPosType As tPOSITION_TYPE
Public lValue As tPOSITION_TYPE
Para as implementar, e após a criação destas classes num projecto, deverão utilizar o seguinte código (com as adaptações necessárias):
‘ Declaração de uma variável a nível do form privada
Private m_oAutoPos As New clsAutoPositioner
‘ No evento load do form define-se quais os controlos e que são afectados
‘ e que acção é efectuada (posicionamento e/ou redimensionamento)
Private Sub Form_Load()
With m_oAutoPos
‘ posição relativo à direita
.AddAssignment Me.Command1, Me, tCONTAINER_RELATIVE_POS_RIGHT
' Redimensionamento horizontal
.AddAssignment Me.Command2, Me, tCONTAINER_WIDTH_DELTA_RIGHT
‘ Redimensionamento vertical
.AddAssignment Me.Command3, Me, tCONTAINER_HEIGHT_DELTA_BOTTOM
' Posição relativo em baixo
.AddAssignment Me.Command4, Me, tCONTAINER_RELATIVE_POS_BOTTOM
' Redimensionamento horizontal e vertical
.AddAssignment Me.Command5, Me, tCONTAINER_WIDTH_DELTA_RIGHT
.AddAssignment Me.Command5, Me, tCONTAINER_HEIGHT_DELTA_BOTTOM
End With
End Sub
‘ Quando é alterado o tamanho do form
Private Sub Form_Resize()
m_oAutoPos.RefreshPositions
End Sub
‘ Limpa da memória a variável
Private Sub Form_Unload(Cancel As Integer)
Set m_oAutoPos = Nothing
End Sub
Estas classes e este processo permitem melhorar a aplicação e dar ao utilizador algo que normalmente está habituado em ambiente Windows. É verdade que no VB.NET esta funcionalidade está disponível através de uma das propriedades dos controlos, mas no VB6, e com poucas linhas de código, pode-se também implementar.
PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!
Os relatórios são parte importante de uma aplicação e a utilização dos Crystal Reports, disponíveis na maioria nas versões do Visual Studio 2005, ajuda muito neste processo. É uma ferramenta poderosa, embora com diversas limitações na versão .NET, mas mesmo assim com inúmeras possibilidades e simplicidade de utilização.
O CystalReportViewer é uma ferramenta do Crystal Report que permite pré-visualizar o relatório antes de ser impresso ou exportado para diversos formatos disponíveis, como é o caso de *.pdf, *.xls, *.doc, etc. No entanto o CystalReportViewer é totalmente em Inglês e não existe a possibilidade de modifica-lo em design mode ou modo de edição.
O CystalReportViewer é composto pelos seguintes componentes:
ReportGroupTree – Árvore de relatórios
PageView – Onde se encontra o relatório
Splitter – Divisão entre o PageView e ReportGroupTree
StatusBar – Barra onde são mostradas algumas informações sobre o relatório
ToolStrip – Barra de Ferramentas onde se encontram os botões

Em modo runtime ou quando o programa está a executar, é possível personalizar grande parte dos componentes do CystalReportViewer. Ficam aqui alguns exemplos de personalizações possíveis, mostrando um pouco o que se pode e como se pode modificá-lo.
Esconder o botão “Main Menu”
Os relatórios aparecem por defeito com um TabControl e com uma TabPage por cada relatório visível. Estas TabPages servem para selecionar o relatório mas na grande maioria das vezes existem apenas um relatório. Nestes casos podemos “esconder” o botão e embora não seja possível na realidade esconder, é possível reduzir o tamanho de modo a este não ser visível.
' Faz um ciclo em todos os controlos do CrystalReportViewer1
For Each ctrl As Control In Me.CrystalReportViewer1.Controls
' Se o controlo for do tipo PageView, ou seja, onde
' se encontra os relatórios e o TabControl
If TypeOf ctrl Is PageView Then
' Atribui a uma variável o primeiro controlo
Dim tabCtrl As TabControl = CType(ctrl.Controls(0), TabControl)
' Define o tamanho como fixo
tabCtrl.SizeMode = TabSizeMode.Fixed
' Define o tamanho em altura para 1
tabCtrl.ItemSize = New Size(0, 1)
Exit For
End If
Next
Alterar o nome do botão “Main Menu”
Este exemplo é semelhante ao anterior, apenas mudando o tipo de controlo. Desta vez, e para alterar o nome de “Main Menu” para outro à nossa escolha, devemos selecionar uma TabPage do TabControl.
' Faz um ciclo em todos os controlos do CrystalReportViewer1
For Each ctrl As Control In Me.CrystalReportViewer1.Controls
' Se o controlo for do tipo PageView, ou seja, onde
' se encontra os relatórios e o TabControl
If TypeOf ctrl Is PageView Then
' Atribui a uma variável o primeiro controlo da primeira TabPage
Dim tabPag As TabPage = CType(ctrl.Controls(0), TabControl).TabPages(0)
' Altera o nome visível
tabPag.Text = "Relatório"
Exit For
End If
Next
Adicionar controlos à Barra de Ferramentas
De modo a personalizar o CystalReportViewer é possível adicionar controlos, remove-los, modificar os existentes, etc. Este exemplo mostra com inserir um ToolStripButton e uma ToolStripLabel à barra de ferramentas.
For Each ctrl As Control In Me.PtCrystalReportViewer2.Controls
If TypeOf ctrl Is Windows.Forms.ToolStrip Then
Dim ts As ToolStrip = CType(ctrl, ToolStrip)
' Cria um novo botão e define algumas propriedades
Dim btnSave As New ToolStripButton
btnSave.Text = "Gravar no Disco"
btnSave.BackColor = Color.SeaGreen
btnSave.ForeColor = Color.White
' Adiciona o botão
ts.Items.Add(btnSave)
' Cria uma nova label e define o texto
Dim lblLink As New ToolStripLabel
lblLink.Text = "http://vbtuga.blogspot.com"
' Define como link e alinha-a à direita
lblLink.IsLink = True
lblLink.Alignment = ToolStripItemAlignment.Right
' Adiciona a ToolStripLabel
ts.Items.Add(lblLink)
' Define quando for efectuado um clique em cada
' um dos objectos irá ser executado o sub DoWork
AddHandler btnSave.Click, AddressOf DoWork
AddHandler lblLink.Click, AddressOf DoWork
Exit For
End If
Next
Depois para executar o código quando for clicado nos novos controlos:
' Verifica qual controlo em que foi efectuado o clique
Private Sub DoWork(ByVal sender As System.Object, ByVal e As System.EventArgs)
If TypeOf sender Is ToolStripButton Then
' Se for no botão
Debug.WriteLine("Pressionado o botão 'Gravar'")
ElseIf TypeOf sender Is ToolStripLabel Then
' Se for no label
Debug.WriteLine("Carregado no link ...")
End If
End Sub
CystalReportViewer personalizado em Português
Finalmente, e utilizando um pouco do que foi mostrado anteriormente, e incluindo mais algumas funcionalidades como renomear todos os ToolTips (textos de ajuda), remover algumas opções, criar uma nova barra de estado em Português (indicação da página e total de páginas) são algumas das alterações que estão efectuadas.
Existem ainda algumas personalizações possíveis em design mode como o StatusBarStyle e StatusBarStyle (System, Professional) e DisplayMainMenu, que permite esconder o botão “Main Menu” quando o relatório for iniciado.
Podem testar, verificar o código, solicitar ou apresentar melhorias ao controlo personalizado:
Dowload (inclui dll e projecto de demonstração): CrystalReportViewerPT
Nota: Este controlo encontrasse em testes e é apenas uma demonstração, pelo que deverá ser testado e validado antes da sua utilização.
PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!
O
overrides ou sobreposição é uma propriedade ou procedimento/função herdado da
classe base. Ou seja a possibilidade de alterar acções ou propriedades da classe,
mas com uma capacidade mais abrangente e com muito menos limitações. Existem algumas
operações que só podem ser feitas desta forma.
Por exemplo, a tecla TAB não é possível
detectar ou modificar nos eventos KeyUp,
KeyDown ou
KeyPress de qualquer controlo. Para se efectuar desta forma era necessário
utilizar o PreviewKeyDown e o
KeyDown em conjunto, o que além de não ser prático e mais confuso. Este
código simplesmente não trabalha:
' No controlo TextBox1
quando a tecla está pressionada (em baixo)
Private Sub
TextBox1_KeyDown(ByVal sender
As System.Object, _
ByVal e
As System.Windows.Forms.KeyEventArgs)
Handles TextBox1.KeyDown
' Caso a tecla seja TAB
If e.KeyCode = Keys.Tab
Then
' Ignora a tecla
pressionada
e.SuppressKeyPress =
True
End
If
End Sub
Para conseguir capturar a tecla antes
de ela actuar e de uma forma simples pode-se usar, por exemplo, a função
ProcessTabKey. Desta forma já é possível modificar o comportamento da tecla
TAB e é executada independentemente do controlo seleccionado.
Neste caso estamos a bloquear a utilização
da tecla TAB quando o TextBox1 estiver seleccionado.
' Quando é pressionada a tecla TAB
Protected Overrides
Function ProcessTabKey(ByVal
forward As Boolean)
As Boolean
' Se o controlo TextBox1 estives
seleccionado
If TextBox1.Focused
Then
' Ignora a tecla
pressionada
Return
True
Else
' Executa o TAB
para o próximo controlo
Return
MyBase.ProcessTabKey(forward)
End
If
End Function
Nos
forms com muitos controlos, especialmente quando servem para registo de dados,
é pratico utilizar as teclas para saltar de controlo em controlo. A tecla que faz
esta função é a tecla TAB ou Shift+TAB, que salta para o próximo ou anterior, de
acordo com TabIndex definido. O
TabIndex é uma propriedade, disponível na maioria dos controlos, que define
qual a ordem de tabulação a executar. Ou seja, quando o
form inicia é seleccionado o TabIndex
com menor valor (normalmente o 0) e ao carregarmos na tecla TAB irá saltar para
o próximo (normalmente o 1).
Mas a tecla TAB não é na realidade
muito prática e muitos programadores, para melhorar a navegabilidade, utilizam a
tecla Enter ou as cursoras
KeyUp ou KeyDdown. Para simplificar
este processo pode-se utilizar o overrides
de funções, neste caso utilizando o ProcessCmdKey.
Por exemplo, para saltar de controlo
em controlo utilizando as teclas cursoras, pode-se utilizar o seguinte código:
‘ Verifica quando é pressionado
uma tecla
Protected Overrides
Function ProcessCmdKey(ByRef
msg As System.Windows.Forms.Message,
ByVal keyData As System.Windows.Forms.Keys)
As Boolean
'
Se a tecla for a cursora Up ou Down
If keyData = Keys.Up
Or keyData = Keys.Down Then
‘
Selecciona o próximo controlo (de acordo com o TabIndex)
Me.SelectNextControl(Me.ActiveControl,
(keyData = Keys.Down), True,
True, True)
End
If
Return MyBase.ProcessCmdKey(msg, keyData)
End Function
Mas podem-se também alterar algumas
das propriedades de cada objecto/classe. O seguinte exemplo mostra como alterar
o função do método ToString().
' Construção da Classe
de Carros
Public Class
Carro
' Sempre que é executado o método ToString()
é mostrado
' a Marca – Modelo e não a simples conversão
para string
Public Overrides
Function ToString() As
String
Return
Me._Marca & " - " +
Me._Modelo
End Function
' Define uma propriedade para a Marca
Private _Marca
As String
Public Property
Marca() As String
Get
Return
_Marca
End
Get
Set(ByVal
value As String)
_Marca = value
End
Set
End Property
' Define uma propriedade para o Modelo
Private _Modelo
As String
Public Property
Modelo() As String
Get
Return
_Modelo
End
Get
Set(ByVal
value As String)
_Modelo = value
End
Set
End Property
End Class
Depois, e para mostrar o funcionamento
da alteração do overrides da função ToString()
' Cria uma nova instância da classe
Carro
Dim clsCarro
As New Carro
' Define a Marca e o Modelo do
exemplo
clsCarro.Marca = "Ford"
clsCarro.Modelo = "Fiesta"
' Mostra o resultado que neste
caso é "Ford - Fiesta" mas sem a
' utilização do Overrides apareceria
WindowsApplication1.Carro
Debug.WriteLine(clsCarro.ToString)
Em resumo e de uma forma genérica,
o overrides permite alterar propriedades
ou procedimentos/funções de uma classe e efectuar algumas operações apenas possíveis
desta forma. No entanto é necessário ter algum cuidado na sua utilização, pois alterar
funções que já se conhece poderá originar alguns problemas no código.
PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!