VB .NET - Tratando imagens e eventos dinamicamente (Reserva de Assentos) - III


 Neste artigo vou mostrar como podemos tratar imagens e eventos de forma dinâmica simulando uma reserva de assentos bem como acessar o banco de dados MySQL para gravar e recuperar informações.

Vamos continuar nosso protótipo para reserva de assentos persistindo e recuperando as informações no banco de dados MySQL. (Veja a segunda parte aqui)

Neste artigo vamos ajustar a interface do usuário alterando o formulário para poder permitir que o usuário selecione uma data e uma hora para a seguir selecionar um assento e fazer a reserva.

Vamos também implementar a funcionalidade que permite ao usuário recuperar as reservas feitas para uma data e hora específica.

Lembrando que o objetivo não é criar um sistema para reserva de assentos completo mas apenas mostrar alguns recursos da linguagem VB .NET, do acesso aos dados e do MySQL.

Recursos Usados

Ajustando o projeto Windows Forms e implementando as funcionalidades

Abra o projeto criado e altere o formulário Form1.vb incluindo os seguintes controles :

Disponha os controles conforme o leiaute da figura abaixo:
 

Agora o usuário deverá selecionar uma data e uma hora e clicar no botão para carregar os dados. Se houver alguma reserva feita  então as informações devem ser recuperadas do banco de dados e exibidas ao usuário.

Se não houver nenhuma reserva feita então será apresentada apenas os assentos todos disponíveis para reserva.

A seguir o usuário pode reservar os assentos e ao clicar no botão para concluir a reserva as informações deverão ser persistidas no banco de dados MySQL. Então vejamos como ficou a implementação das funcionalidades para este cenário:

No formulário Form1.vb devemos importar o namespace do projeto Class Library:

Imports DAL

A seguir vamos definir as variáveis para as imagens que iremos usar, e, que já foram adicionadas ao Resources do projeto, convertendo-as para Bitmap:

Dim disponivelIcon As New Bitmap(My.Resources.disponivel)
Dim reservadoIcon As New Bitmap(My.Resources.reservado)
Dim indisponivelIcon As New Bitmap(My.Resources.indisponivel)
Dim semdadosIcon As New Bitmap(My.Resources.semdados)

No evento Load do formulário vamos preencher os combobox para data, horas e para os clientes:

  Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        PreencherDatas()
        PreencherHoras()
        CarregarDadosClientes()
    End Sub

A seguir o código dos métodos usados :

     Private Sub PreencherDatas()

        Dim dataInicial As Date = Date.Today.AddDays(-5)

        While dataInicial < Date.Today.AddDays(20)
            cboDatas.Items.Add(dataInicial.ToString("dd/MM/yyyy"))
            dataInicial = dataInicial.AddDays(1)
        End While
        cboDatas.SelectedIndex = 0

    End Sub
    Private Sub PreencherHoras()

        For x = 8 To 22
            Dim tm As New Date(1, 1, 1, x, 0, 0)
            cboHoras.Items.Add(tm.ToShortTimeString)
        Next

        cboHoras.SelectedIndex = 0

    End Sub
    Private Sub CarregarDadosClientes()
        Dim sql As String = "Select id, nome from clientes"
        cboClientes.DataSource = AcessoBD.GetDataTable(sql)
        cboClientes.DisplayMember = "nome"
        cboClientes.ValueMember = "id"
   End Sub

No método CarregarDadosClientes() estamos chamando o método GetDataTable() da camada de acesso a dados passando a instrução SQL para retornar todos os clientes como um DataTable.

Código para carregar as informações para uma data e hora selecionados

Após selecionar uma data e um horário o usuário deverá clicar no botão para carregar as informações pertinentes. O código do evento Click do botão é mostrado a seguir:

 Private Sub btnCarregarDados_Click(sender As Object, e As EventArgs) Handles btnCarregarDados.Click
        Dim hora As DateTime = Convert.ToDateTime(cboHoras.Text)
        Dim data As DateTime = Convert.ToDateTime(cboDatas.Text)
        Dim horaReserva As String = hora.ToString("yyyy-MM-dd HH:mm:ss")
        Dim dataReserva As String = data.ToString("yyyy-MM-dd HH:mm:ss")
        Dim sql = "Select assento, reservado from Carro1 where data=('" + dataReserva + "') AND " + "hora=('" + horaReserva + "')"
        Dim tabela As DataTable
        Try
            tabela = AcessoBD.GetDataTable(sql)
            If (tabela.Rows.Count > 0) Then
                carregaDadosCarroDataHora(tabela)
            Else
                CarregaImagens(disponivelIcon)
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub

Neste código obtemos a data e hora selecionada e convertemos para o formato yyyy-MM-dd HH:mm:ss que é o formato padrão para armazenar um DateTime no MySQL.

Depois montamos a instrução SQL para selecionar os assentos e os status para a data e hora especificada e invocamos o método GetDataTable() passando a instrução SQL.

Se houver informações para a data/hora informada então chamamos o método CarregaDadosCarroDataHora() caso contrário o método CarregaImagens() será invocado.

1- Método CarregaDadosCarroDataHora() :

     Private Sub carregaDadosCarroDataHora(tabela As DataTable)
        Dim numero_assento As Integer = 0
        Dim assento As Integer = 0
        Dim reservado As Boolean = False
        Dim c As Control
        picDisponivel.Image = My.Resources.disponivel
        picReservado.Image = My.Resources.reservado
        For Each linha As DataRow In tabela.Rows
            assento = linha.Item("assento")
            reservado = linha.Item("reservado")
            For Each c In pnlAssentos.Controls
                If TypeOf (c) Is PictureBox Then
                    AddHandler c.Click, AddressOf picboxImagem_Click

                    numero_assento = Convert.ToInt32(RemoveSubstring(CType(c, PictureBox).Name, "assento"))

                    If numero_assento = assento Then
                        If reservado Then
                            CType(c, PictureBox).Image = indisponivelIcon
                        Else
                            CType(c, PictureBox).Image = disponivelIcon
                        End If
                    Else
                        If (CType(c, PictureBox).Image IsNot indisponivelIcon) Then
                            CType(c, PictureBox).Image = disponivelIcon
                        End If
                    End If
                End If

            Next
        Next
    End Sub

Este código percorrer os dados da tabela contendo os assentos reservados e vai percorrer cada controle PictureBox do Panel do formulário obtendo o número do assento e verificando qual assento esta reservado atribuindo a imagem indisponivelIcon caso contrário para os demais controles PictureBox que não estiverem já atribuidos como indisponíveis será atribuido a imagem disponivelIcon.

Para obter o número do assento a partir do nome da PictureBox (uma lógica meio ingênua e marota) usamos o método RemoveSubstring():

  Public Shared Function RemoveSubstring(texto As String, remove As String) As String
        Dim pos As Integer = texto.IndexOf(remove)
        If pos >= 0 Then
            Return texto.Remove(pos, remove.Length)
        End If
        Return texto
    End Function

Nota: Todas as PictureBox do Panel possuem nome no formato : assentoxx onde xx representa o número do assento.

Código persistir as informações da reserva no MySQL

Após selecionar os assentos para efetivar a  reserva o usuário deve clicar no botão - Concluir Reserva.

 Private Sub btnReservar_Click(sender As Object, e As EventArgs) Handles btnReservar.Click
        Try
            GravaDadosReserva()
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub

 

Vejamos abaixo o código do método GravarDadosReserva() :

   Private Sub GravaDadosReserva()
        Dim numero_Assento As Integer = 0

        Dim clienteid As Integer = Convert.ToInt32(cboClientes.SelectedValue)

        Dim hora As DateTime = Convert.ToDateTime(cboHoras.Text)
        Dim data As DateTime = Convert.ToDateTime(cboDatas.Text)
        Dim horaReserva As String = hora.ToString("yyyy-MM-dd HH:mm:ss")
        Dim dataReserva As String = data.ToString("yyyy-MM-dd HH:mm:ss")

        Dim sql As String = ""
        Dim c As Control
        For Each c In pnlAssentos.Controls

            If TypeOf (c) Is PictureBox Then
                If CType(c, PictureBox).Tag = "reservado" Then
                    CType(c, PictureBox).Image = indisponivelIcon
                    numero_Assento = Convert.ToInt32(RemoveSubstring(CType(c, PictureBox).Name, "assento"))
                    sql = "INSERT INTO Carro1(clienteid,data,hora,assento,reservado) values (" & clienteid & ",'" & dataReserva & "','" + horaReserva & "'," & numero_Assento & "," & True & ")"
                    AcessoBD.ExecuteNonQuery(sql)
                End If
            End If
        Next
    End Sub

Neste código, após obtermos o código do cliente, a data e hora, e, após convertermos a data e hora para o formato yyyy-MM-dd HH:mm:ss, percorremos cada PictureBox para obter quais foram reservados e o seu respectivo número usando o método RemoveSubstring().

A seguir montamos a instrução SQL INSERT INTO para gravar as informações no banco de dados usando o método ExecuteNonQuery() passando a instrução sql.

Nota: Seria mais recomendado utilizar uma transação de forma a atualizar a interface do usuário somente se a transação fosse concluída com sucesso.

Executando a aplicação iremos obter o seguinte resultado:

Temos aqui 3 cenários possíveis:

1- Na primeira figura o formulário é apresentando ao usuário com as datas, horas e clientes carregados;
2- Na segunda figura,  após selecionar uma data e hora : 20/06/2017 e 17:00 ao clicar no botão para carregar dados as informações são carregas e exibidas no formulário;
3- Na terceira figura, como não existe informação de reservas para a data e hora selecionadas os assentos estão todos disponíveis e o usuário pode realizar a reserva;

Vamos confirmar verificando os dados da tabela Carro1 :

Temos 5 reservas feitas para o dia 20/06/2017 às 17:00 hs nos assentos 2,3,10,17 e 20. Vamos carregar os dados e ver se isso se reflete na interface:

Como vemos as informações sobre as reservas se refletem na interface.

Conclusão:

O nosso protótipo para reserva de assentos funciona mesmo, mas ele pode ser melhorado em muitos aspectos como:

- Criar uma camada de negócios, visto que estamos acessando a camada de acesso a dados diretamente da camada de interface;
- A utilização de instruções SQL inline (como texto) além de dificultar a manutenção abre uma brecha para injeção SQL; seria melhor usar stored procedures ou instruções parametrizadas;


Pegue o projeto completo aqui :  VBNET_ControlesDinamicos_Assentos.zip

(Disse Jesus) Todo o que o Pai me dá virá a mim; e o que vem a mim de maneira nenhuma o lançarei fora.
João 6:37

 

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Quer aprender a criar aplicações Web Dinâmicas usando a ASP .NET MVC 5 ?

 

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

 

Referências:


José Carlos Macoratti