Le avventure in VB.Net di un principiante ex-VB6 - 16
a cura di Oscar Zanin e Diego Cattaruzza (requisiti: Visual Basic Express e SqlServer)Premessa
Nell'articolo precedente si era terminato lo sviluppo della FrmRicerca. In questo articolo si esporrà lo sviluppo della FrmBanche, un'altra delle form associate a una sola tabella del database, mostrando solo le differenze tra questa e la FrmStati, in modo da far capire quanto poco cambia, essendo invariati i fondamenti strategici.
In seguito, si proprorrà lo sviluppo di altre due form, come 'compito a casa'.Il disegno della FrmBanche
Come ormai si dovrebbe aver imparato, si aggiunge una Kripton Form al progetto PrimiPassi, con il nome FrmBanche.
L'aspetto finale, terminato il disegno, dovrà essere simile a quello esposto in figura.
La prima, ovvia, differenza con la FrmStati è costituita dal numero dei campi della tabella e quindi dal numero dei controlli presenti sulla form:
- KryptonManager, già presente
- GlobalPaletteMode = Office 2007 - Blue
- KryptonPanel, già presente
- eliminato
- FrmBanche
- BackColor = (Web) LightBlue
- FormBorderStyle = FixedDialog
- Icon = Archivio.ico (dalla cartella Immagini)
- MaximizeBox = False
- Size = 520; 360
- Text = Anagrafica Banche
- Trasciniamo un controllo ToolStrip (del tutto simile a quello presente in FrmStati)
- Name = TbrStrumenti
- ImageScalingSize = 32; 32 (dimensione in pixel delle immagini che utilizzeremo)
a esso aggiungiamo nell'ordine:
- un Button
- Name = BtnEsci
- Image = Pulsanti_Uscita dalle risorse del progetto
- Text = Esci
- un Separator
- un Button
- Name = BtnNuovo
- Image = Pulsanti_Nuovo dalle risorse del progetto
- Text = Nuovo record
- un Button
- Name = BtnModifica
- Image = Pulsanti_Modifica dalle risorse del progetto
- Text = Modifica record
- un Button
- Name = BtnCancella
- Image = Pulsanti_Cancella dalle risorse del progetto
- Text = Cancella record
- un Separator
- un Button
- Name = BtnCerca
- Image = Pulsanti_Cerca dalle risorse del progetto
- Text = Cerca record
- un Separator
- un Button
- Name = BtnConferma
- Image = Pulsanti_Conferma dalle risorse del progetto
- Text = Conferma operazione
- un Button
- Name = BtnAnnulla
- Image = Pulsanti_Annulla dalle risorse del progetto
- Text = Annulla operazione
- un Separator
- un Button
- Name = BtnPrimo
- Image = Pulsanti_Primo dalle risorse del progetto
- Text = Sposta sul primo record
- un Button
- Name = BtnPrec
- Image = Pulsanti_Precedente dalle risorse del progetto
- Text = Sposta sul record precedente
- un Button
- Name = BtnSucc
- Image = Pulsanti_Successivo dalle risorse del progetto
- Text = Sposta sul record successivo
- un Button
- Name = BtnUltimo
- Image = Pulsanti_Ultimo dalle risorse del progetto
- Text = Sposta sull'ultimo record
- un Separator
- un Button
- Name = BtnAggiorna
- Image = Pulsanti_Aggiorna dalle risorse del progetto
- Text = Allinea i dati con il database
- ultimo Button
- Name = BtnSblocca
- Image = Pulsanti_Sblocca dalle risorse del progetto
- Text = Sblocca record
- Trasciniamo un Panel
- Name = PnlDati
- Dock = Fill
nel quale trasciniamo:
- una Label
- AutoSize = True
- Font Size = 10
- ForeColor = Black
copiamola, incolliamola 11 volte, così non abbiamo da impostare queste tre proprietà comuni,
ma solo testo e posizione (sfruttando anche le facilitazioni offerte dall'IDE per allineare i controlli):
Text LocationBanca 13; 15Agenzia 13; 53ABI 13; 91CAB 143; 91Swift 249; 91Indirizzo 13; 147CAP 13; 185Città 143; 185Provincia 13; 223Stato 143; 223Telefono 13; 261Fax 249; 261- una TextBox
- BackColor = (Web) White
- Font Size = 10
copiamola, incolliamola 10 volte, disponiamo tutte le TextBox accanto alle Label (tranne quella con testo 'Stato'); impostiamo quindi le proprietà specifiche di ciascuna TextBox:
Name Location MaxLength SizeTxtBanca 86; 12 50 348; 23TxtAgenzia 86; 50 50 348; 23TxtAbi 86; 88 10 50; 23TxtCab 184; 88 10 50; 23TxtSwift 292; 88 15 142; 23TxtInd 86; 144 50 348; 23TxtCap 86; 182 5 50; 23TxtCitta 184; 182 50 250; 23TxtProv 86; 220 4 50; 23TxtTel 86; 258 25 149; 23TxtFax 285; 258 25 149; 23- ForeColor = Red per TxtBanca e TxtAgenzia, poiché si vuole evidenziare all'utente i campi chiave.
- una ComboBox
- Name = CmbStato
- AutoCompleteMode = SuggestAppend
- AutoCompleteSource = ListItems
- Font Size = 10
- Location = 184; 220
- Size = 250; 24
- Sorted = True
- Infine assegniamo l'ordine di tabulazione: selezioniamo il menu Visualizza/Ordine di tabulazione. Clicchiamo sui controlli nell'ordine seguente: ToolStrip, TxtBanca, TxtAgenzia, TxtAbi, TxtCab, TxtSwift, TxtInd, TxtCap, TxtCitta, TxtProv, CmbStato, TxtTel, TxtFax e infine premiamo il tasto Esc sulla tastiera per uscire dall'operazione con le modifiche impostate - vedrete che le posizioni per i controlli contenuti nel Panel vengono espresse con due numeri: il primo è quello del contenitore rispetto agli altri controlli presenti sulla Form, il secondo quello del controllo rispetto agli altri controlli presenti nel contenitore.
Il codice della FrmBanche
Le differenze tra questa form e FrmStati consistono, sostanzialmente, nell'implementazione del codice relativo ai diversi controlli presenti (molte più TextBox, e una ComboBox in più).Innanzitutto, consideriamo la CmbStato, che richiede non solo di essere caricata all'inizio, ma anche di essere aggiornata, qualora i dati presenti in tabella Stati dovessero cambiare. Per questo motivo, il suo popolamento avviene a ogni attivazione della FrmBanche, cioè nella gestione dell'evento Activated, non in quella dell'evento Load).
Private Sub FrmBanche_Activated(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Activated PopolaCombo() End SubSupponiamo di star inserendo una nuova banca sita in un nuovo stato nato dall'ennesima scissione dell'ex Jugoslavia, che non esiste ancora nella tabella Stati. Apriamo la ComboBox e naturalmente non lo troviamo. Dobbiamo inserirlo, pertanto apriamo la form degli Stati, aggiungiamo il nuovo record, torniamo alla form delle banche che ha l'inserimento in corso e questo scatena nuovamente l'evento Activated, che richiama il metodo PopolaCombo che ricompila la ComboBox con i dati aggiornati (nuovo stato compreso). Però, se non fossimo al primo accesso alla form e il ComboBox contenesse un valore, questo verrebbe perso a seguito del ripopolamento. Occorre quindi prevenire questa evenienza depositando l'eventuale valore in una apposita variabile, valoreAttuale, per riassegnarlo alla fine dell'operazione.
Private Sub PopolaCombo() Dim dstStati As DataSet Dim adpStati As SqlDataAdapter Dim cmdStati As SqlCommand Dim valoreAttuale As String = CmbStato.Text cmdStati = New SqlCommand() cmdStati.Connection = SqlHelper.ConnessioneDatabase cmdStati.CommandText = "SELECT Stato FROM Stati ORDER BY Stato" adpStati = New SqlDataAdapter(cmdStati) dstStati = New DataSet adpStati.Fill(dstStati, "Stato") CmbStato.DataSource = dstStati.Tables(0) CmbStato.DisplayMember = "Stato" CmbStato.ValueMember = "Stato" CmbStato.Text = valoreAttuale End SubLa FrmBanche è ovviamente associata alla tabella Banche, che è ordinata per Banca e Agenzia, quindi, nella gestione dell'evento Load si hanno queste istruzioni:
Private Sub FrmBanche_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ' ... Dati = New Tabella(ConnessioneDatabase, "Banche") Dati.NomeCampoModifica = "Modifica" Dati.Ordinamento = "Banca, Agenzia" ' ... End SubLa gestione del cambiamento di focus tra i controlli - nella quale viene scatenato l'evento ActiveControlChanged per impostare il messaggio di informazione nella barra di stato della FrmMain - deve ovviamente tener conto del maggior numero di controlli e prevedere l'informazione adeguata per ciascuno di essi. Si implementano quindi diversi metodi (di cui si presentano, per brevità, solo le firme):
Private Sub Pulsante_MouseEnter(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles BtnAggiorna.MouseEnter, BtnAnnulla.MouseEnter, _ BtnCancella.MouseEnter, BtnCerca.MouseEnter, _ BtnConferma.MouseEnter, BtnEsci.MouseEnter, _ BtnModifica.MouseEnter, BtnNuovo.MouseEnter, BtnPrec.MouseEnter, _ BtnPrimo.MouseEnter, BtnSblocca.MouseEnter, BtnSucc.MouseEnter, _ BtnUltimo.MouseEnter '... End Sub Private Sub Pulsante_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles BtnAggiorna.MouseLeave, BtnAnnulla.MouseLeave, _ BtnCancella.MouseLeave, BtnCerca.MouseLeave, _ BtnConferma.MouseLeave, BtnEsci.MouseLeave, BtnNuovo.MouseLeave, _ BtnModifica.MouseLeave, BtnPrec.MouseLeave, BtnPrimo.MouseLeave, _ BtnSblocca.MouseLeave, BtnSucc.MouseLeave, BtnUltimo.MouseLeave '... End Sub Private Sub CaselleDiTesto_Enter(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles TxtBanca.Enter, TxtAgenzia.Enter, _ TxtAbi.Enter, TxtCab.Enter, TxtSwift.Enter, TxtInd.Enter, _ TxtCap.Enter, TxtCitta.Enter, TxtProv.Enter, TxtTel.Enter, _ TxtFax.Enter '... End Sub Private Sub ElenchiATendina_Enter(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles CmbStato.Enter '... End SubSostanzialmente, si deve tener conto della diversa origine dei dati. Spesso la modifica è semplice, consistendo solo nel nome dei controlli, come in BtnNuovo_Click e nei metodi VisualizzaDati e CaricaRiga (che qui si omettono, per brevità):
Private Sub BtnNuovo_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles BtnNuovo.Click ' ... TxtBanca.Select() ' ... End SubMa talvolta bisogna considerare la rilevanza dei dati:
Private Sub BtnModifica_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles BtnModifica.Click ' ... TxtAbi.Select() TxtBanca.ReadOnly = True TxtAgenzia.ReadOnly = True ' ... End SubSi sposta il focus sul primo controllo editabile, impedendo l'edizione dei controlli relativi ai campi chiave.
Per altro verso, la si permette, laddove serve:Private Sub BtnConferma_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles BtnConferma.Click ' ... TxtBanca.ReadOnly = False TxtAgenzia.ReadOnly = False ' ... End Sub Private Sub BtnAnnulla_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles BtnAnnulla.Click ' ... TxtBanca.ReadOnly = False TxtAgenzia.ReadOnly = False ' ... TxtBanca.ReadOnly = False TxtAgenzia.ReadOnly = False End SubSi ragiona in modo analogo, quando si controlla la validità dell'immissione di dati:
Private Function DatiValidi() As Boolean If ConvalidaDati.Convalida(TxtBanca.Text, "Banca", _ ConvalidaDati.TipoConv.Testo, True) = False Then Messaggi.Avviso("Il campo Banca non può essere lasciato vuoto !", "Attenzione") Return False End If If ConvalidaDati.Convalida(TxtAgenzia.Text, "Agenzia", _ ConvalidaDati.TipoConv.Testo, True) = False Then Messaggi.Avviso("Il campo Agenzia non può essere lasciato vuoto !", "Attenzione") Return False End If Return True End FunctionIn questa form il pulsante di modifica ha un senso, poiché ci sono campi modificabili (la FrmStati aveva un unico campo, non modificabile) quindi ne gestiamo l'abilitazione, dove occorre:
Private Sub AbilitaPulsanti(ByVal flag As Boolean) ' ... BtnModifica.Enabled = flag ' ... End SubL'impostazione della ricerca richiede l'intervento più ragionato (bisogna cioè fare attenzione ai parametri da passare alla form di ricerca):
Private Sub BtnCerca_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles BtnCerca.Click Dim ir As InfoRicerca ir.TitoloForm = "Ricerca Banche" ir.SorgenteDati = "Banche" ir.Ordinamento = "Banca, Agenzia" ir.Criteri = New List(Of Criterio) ir.Criteri.Add(New Criterio("Banca", TipoOrigineDati.DatiTabella, "Banca", "Banca", _ SqlDbType.VarChar, False, TipoConfronto.Uguale)) ir.Criteri.Add(New Criterio("Agenzia", TipoOrigineDati.DatiTabella, "Agenzia", "Agenzia", _ SqlDbType.VarChar, False, TipoConfronto.Uguale)) ir.Criteri.Add(New Criterio("ABI", TipoOrigineDati.DatiTabella, "ABI", "ABI", _ SqlDbType.VarChar, False, TipoConfronto.Uguale)) ir.Criteri.Add(New Criterio("CAB", TipoOrigineDati.DatiTabella, "CAB", "CAB", _ SqlDbType.VarChar, False, TipoConfronto.Uguale)) ir.Criteri.Add(New Criterio("Città", TipoOrigineDati.DatiTabella, "Citta", "Citta", _ SqlDbType.VarChar, False, TipoConfronto.Uguale)) ir.Criteri.Add(New Criterio("Stato", TipoOrigineDati.DatiTabella, "Stato", "Stato", _ SqlDbType.VarChar, False, TipoConfronto.Uguale)) ir.Colonne = New List(Of Colonna) ir.Colonne.Add(New Colonna("Banca", "Banca", 290, False, True, True, SqlDbType.VarChar)) ir.Colonne.Add(New Colonna("Agenzia", "Agenzia", 290, False, True, True, SqlDbType.VarChar)) ir.Colonne.Add(New Colonna("Citta", "Città", 290, False, True, False, SqlDbType.VarChar)) ir.Colonne.Add(New Colonna("Stato", "Stato", 290, False, True, False, SqlDbType.VarChar))Come si può constatare, a parte la novità della ComboBox e della gestione del suo popolamento, tutto il resto del codice di FrmBanche è concettualmente simile a quello di FrmStati. Quindi dovreste essere in grado di implementare da voi quello delle prossime form, di cui forniamo solo le specifiche di disegno.
La form Unità di misura - disegno
L'aspetto finale che dovrà avere la form è il seguente:
- KryptonManager, già presente
- GlobalPaletteMode = Office 2007 - Blue
- KryptonPanel, già presente
- eliminato
- FrmUnMis
- BackColor = (Web) LightBlue
- FormBorderStyle = FixedDialog
- Icon = Archivio.ico (dalla cartella Immagini)
- MaximizeBox = False
- Size = 516; 119
- StartPosition = WindowsDefaultLocation
- Text = Anagrafica Unità di misura
- la ToolStrip TbrStrumenti è identica a quelle già disegnate per le form precedenti
- il Panel PnlDati è disegnato in modo analogo a quelli precedenti
- la Label
- AutoSize = True
- Font Size = 10
- ForeColor = Black
- Location = 13; 15
- Text = Unità di misura
- la TextBox
- Name = txtUM
- BackColor = (Web) White
- Font Size = 10
- ForeColor = Red (perchè?)
- Location = 121; 12
- MaxLength = 5
- Size = 48; 23
- L'ordine di tabulazione: ToolStrip, TextBox.
La form Prodotti - disegno
L'aspetto finale che dovrà avere la form è il seguente:
- KryptonManager, già presente
- GlobalPaletteMode = Office 2007 - Blue
- KryptonPanel, già presente
- eliminato
- FrmProdotti
- BackColor = (Web) LightBlue
- FormBorderStyle = FixedDialog
- Icon = Archivio.ico (dalla cartella Immagini)
- MaximizeBox = False
- Size = 516; 288
- StartPosition = WindowsDefaultLocation
- Text = Anagrafica Prodotti
- la ToolStrip TbrStrumenti è identica a quelle già disegnate per le form precedenti
- il Panel PnlDati è disegnato in modo analogo a quelli precedenti
- le sei Label hanno in comune queste proprietà:
- AutoSize = True
- Font Size = 10
- ForeColor = Black
mentre le Location sono rispettivamente:
- 13; 15
- 13; 51
- 13; 88
- 203; 87
- 13; 124
- 203; 124
- le cinque TextBox hanno in comune queste proprietà:
- BackColor = (Web) White
- Font Size = 10
mentre si differenziano per
Name Location MaxLength SizeTxtCodice 95; 12 20 170; 23TxtProd 95; 48 50 348; 23TxtQuanMag 351; 84 0 92; 23TxtPrezAcq 95; 121 0 92; 23TxtPrezVen 351; 121 0 92; 23
inoltre (e provate a immaginare perché):
- TxtCodice.ForeColor = Red
- TxtQuanMag.ForeColor = (Web) Blue
- TxtQuanMag.ReadOnly = True
- TxtQuanMag.TabStop = False
- la ComboBox:
- Name = cmbUM
- AutoCompleteMode = SuggestAppend
- AutoCompleteSource = ListItems
- Location = 95; 84
- Size = 65; 24
- Sorted = True
- le tre CheckBox hanno in comune queste proprietà:
- AutoSize = True
- Font Size = 10
- ForeColor = Black
- UseVisualStyleBackColor = True
mentre si differenziano per:
Name LocationChkAcquisto 16; 159ChkVendita 268; 159ChkStampa 16; 186
- l'ordine di tabulazione: ToolStrip, TxtCodice, TxtProd, CmbUM, TxtQuanMag, TxtPrezAcq, TxtPrezVen, ChkAcquisto, ChkVendita, ChkStampa.
In questa form avete la novità delle CheckBox e il fatto che il campo della quantità a magazzino è di sola lettura.
Le prime rappresentano uno stato di visibilità del singolo prodotto nel resto del programma; il secondo è di sola lettura in quanto il valore viene modificato da altre form tipo quella dei carichi a magazzino e dei D.d.t.
Un prodotto potrebbe essere proposto solo nei carichi di magazzino se si è spuntato solo la prima CheckBox, oppure viceversa potrebbe essere proposto nelle fatture e nella stampa dell'anagrafica dei prodotti se si spuntano la seconda e la terza CheckBox e non apparire nel carico di magazzino.Conclusione
In questo articolo è stato illustrato lo sviluppo della FrmBanche, la seconda delle form del progetto PrimiPassi associate a una sola tabella del database, e solo il disegno di altre due form, FrmUnMis e FrmProdotti, delle quali sono state fornite solo le specifiche per il disegno, mentre lo sviluppo del codice è assegnato come 'compito a casa'.In seguito, quando verrà fornito anche il codice, potrete confrontare il vostro col nostro e imparare dalle differenze, se ce ne darete conto nel companion post che accompagnerà quella puntata.
Il codice di PrimiPassi sviluppato fino a questo momento è come al solito disponibile in area download.
Anche per questa puntata, Diego mette a disposizione nel suo blog un post cui scrivere critiche, suggerimenti, richieste di chiarimento.