Italian (B4J) Creare un form per data entry

PatrikCavina

Active Member
Licensed User
Buongiorno a tutti,
Volevo chiedere, a chi più esperto di me, quel'è il miglior approccio per creare un form per l'inserimento dati all'interno di un database.
Per esempio:
Il programma che sto facendo ora, si collega a tre tabelle diverse, in tutte le tabelle ho la necessita di inserire dei records.

Quindi chiedo, se sia meglio:
  • Creare un'unica classe la quale posso costruire un form in base ai campi dati e precedentemente settatti. Quindi creerei prima una mappa con i nomi delle colonne e il relativo nodo e il posizionamento di tali nodi, sarebbero fatti dalla classe.
  • Creare una classe per ogni tabella del database che carichi il suo layout corrispondente, quindi creare anche un layout per ogni tabella
  • Creare una classe generica che carichi il layout della tabella selezionata e poi "smistare" gli eventi con "Case" e "If". Anche questa soluzione necessita la creazione di un layout per ogni tabella
Grazie in anticipo
 

LucaMs

Expert
Licensed User
Direi creare un form al quale passi una Map contenente struttura e dati della tabella ed in base a questi dati creare le view a runtime.
 

udg

Expert
Licensed User
Se le tabelle sono in relazione tra loro ricorda di utilizzare le transaction in modo che ad esempio un inserimento riesca su tutte oppure nessuna.
caso tipico master-detail, dove certamente non desideri rischiare di inserire dettagli in assenza di un master cui si riferiscono.

Da un punto di vista ui ti ha già risposto Luca.
Quando hai dubbi, immagina di essere l'utente e pensa alla soluzione chebti farebbe più comodo..
 

PatrikCavina

Active Member
Licensed User
Grazie per le riposte e per i consigli.
Chiedo, una soluzione tipo questa potrebbe andare?
Magari ci sono metodi più veloci e puliti

-Main
B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Type Settings(DbTableName As String, ColsToNode As Map)
    Private SetMole As Settings
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Main") 'Load the layout file.
    InitializeNode
    MainForm.Show
End Sub

Private Sub InitializeNode
    SetMole.Initialize
    SetMole.DbTableName = "Mole"
    SetMole.ColsToNode.Initialize
 
    SetMole.colstoNode.put("ID",                            "NULL")
    SetMole.colstoNode.put("Codice",                         "TXF" )
    SetMole.colstoNode.put("Descrizione",                    "TXF" )
    SetMole.colstoNode.put("Legante",                        "CMBX" )
    SetMole.colstoNode.put("Volume",                         "TXF" )
    SetMole.colstoNode.put("Area",                            "TXF" )
    SetMole.colstoNode.put("Concentrazione",                 "TXF" )
    SetMole.colstoNode.put("Densità",                        "TXF" )
    SetMole.colstoNode.put("Disegno",                        "TXF" )
    SetMole.colstoNode.put("Note",                           "TXA" )
    SetMole.colstoNode.put("Corpo",                            "TXF" )
    SetMole.colstoNode.put("Stampo",                        "TXF" )
    SetMole.colstoNode.put("Tappi",                          "TXF" )
    SetMole.colstoNode.put("°C Forno",                       "TXF" )
    SetMole.colstoNode.put("°C Stampo",                      "TXF" )
    SetMole.colstoNode.put("Tempo Cottura (min)",            "TXF" )
    SetMole.colstoNode.put("Tempo Cottura Sing. (min)",      "TXF" )
    SetMole.colstoNode.put("Pressione Caldo (Kg/cm^2)",       "TXF" )
    SetMole.colstoNode.put("Pressione Freddo (Kg/cm^2)",      "TXF" )
    SetMole.colstoNode.put("Carati Totali (Kt)",            "TXF" )
    SetMole.colstoNode.put("Diamante Totale (Kt)",            "TXF" )
    SetMole.colstoNode.put("Tipo Diamante",                  "TXF" )
    SetMole.colstoNode.put("Grana",                          "TXF" )
    SetMole.colstoNode.put("Grafite",                        "TXF" )
    SetMole.colstoNode.put("Data Inserimento",                "LB")
    SetMole.colstoNode.put("Data Ultima Modifica",            "LB")
End Sub
Passando poi l'oggetto setMole alla classe che costruirà il form, che chiamerò Aggiungi:

-Aggiungi:

B4X:
Sub Class_Globals
    Private fx As JFX
    Private CurrentSettings As Settings
    Private Nodes As Map 'Contiene i nodi inseriti
    Private FieldsName As List
 
    Private scrollPane As ScrollPane
    Private LargerLabelWidth As Double
End Sub

Public Sub Initialize(tPane As TabPane, Set As Settings)
    CurrentSettings = Set
    tPane.LoadLayout("Aggiungi","Aggiungi "&CurrentSettings.DbTableName)
    InitializeComponents
    InitializeNode
End Sub

Private Sub InitializeComponents
    Nodes.Initialize
    FieldsName = 'Nomi delle colonne
    LargerLabelWidth = 'Con una funzione ricavo il testo con dimensione maggiore
End Sub

Private Sub InitializeNode
    scrollPane.LoadLayout("Scroll",0,0)
    SetNode
End Sub

Private Sub SetNode
    Dim p As Pane = scrollPane.InnerNode
    For i = 0 To FieldsName.Size-1
     
        Dim Field As String = FieldsName.Get(i)
        Dim typeNode As Node = ConvertTextToNode(Field,CurrentSettings.ColsToNode.Get(Field))
     
        Dim top As Double = 30 'Start top
        Dim height As Double = 20

        If Not(typeNode.IsInitialized) Then Continue
     
        If Nodes.Size <> 0 Then
            Dim lastNode As Node = Nodes.GetValueAt(Nodes.Size-1)
            Dim lastHeight As Double = lastNode.PrefHeight
            top = top + lastNode.Top + lastHeight
        End If
             
        Nodes.Put(Field,typeNode)
     
        If typeNode Is TextArea Then
            height = 600
        End If
     
        Dim lb As Label
        lb.Initialize("")
        lb.Text = Field
     
        p.AddNode(lb,20,top,LargerLabelWidth,30)
        p.AddNode(typeNode,LargerLabelWidth+30,top,1200,height)
    Next
    p.PrefHeight = lastNode.PrefHeight*2 + lastNode.Top + height*2
End Sub

Private Sub ConvertTextToNode(Tag As String, TextNode As String) As Node
    Dim nResult As Node
    If TextNode = "TXF" Then
        Dim txf As TextField
        txf.Initialize("TextField")
        txf.Tag = Tag
        nResult = txf
 
    Else If TextNode = "CMBX" Then
        Dim cmbx As ComboBox
        cmbx.Initialize("ComboBox")
        cmbx.Tag = Tag
     
        If Tag = "Legante" Then
            Dim legantiList As List = 'mi collego alla seconda tabella e ne ricavo solo i nomi
            cmbx.Items.AddAll(legantiList)
             
        Else If Tag = "Elementi" Then
            Dim elementiList As List = 'mi collego alla terza tabella e ne ricavo solo i nomi
            cmbx.Items.AddAll(elementiList)
             
        End If
        nResult = cmbx
 
    Else If TextNode = "TXA" Then
        Dim txa As TextArea
        txa.Initialize("TextArea")
        txa.Tag = Tag
        nResult = txa
 
    Else If TextNode = "LB" Then
        Dim lb As Label
        lb.Initialize("")
        lb.Tag = Tag
        If Tag = "Data Inserimento" Or Tag = "Data Ultima Modifica" Then
            DateTime.DateFormat = "dd/MM/yyyy"
            lb.Text = DateTime.Date(DateTime.Now)
        End If
        nResult = lb
    End If
 
    Return nResult
End Sub
 

LucaMs

Expert
Licensed User
Il mio occhio oggi non vuole faticare tanto (nemmeno l'altro e soprattutto i due neuroni :D).

Mi sembra che vada bene, scorrendolo velocemente. L'unica cosa è che è sempre meglio evitare "literal" ("TXF", "LB", ...) ed usare variabili o, in questo caso, costanti.
 

PatrikCavina

Active Member
Licensed User
Grazie @LucaMs per il consiglio. Però non capisco una cosa:
Se sostituisco i literal e uso costanti, mi ritrovo ad inizializzare due volte i nodi, nel main e nella classe aggiungi, o sbaglio?
Per associare invece un nodo ad ogni campo è meglio dichiararne uno alla volta es:
B4X:
Private nodo1 as TextField
Private nodo2 as TextField
Private nodo3 as Label
Private nodo4 as ComboBox
Oppure attraverso degli array?
Quindi:
B4X:
Private txf(2) as TextField 'Che comprende nodo1 e nodo2
Private lb(1) as Label
Private cmbx(1) as ComboBox
 

LucaMs

Expert
Licensed User
Il mio suggerimento di evitare i literal era in generale, benché mi sia venuto in mente scorrendo il tuo codice.
In generale, ha diversi vantaggi, tra i quali quello di non dover andare a sostituire i literal in futuro:
SetMole.colstoNode.put("ID", "NULL")
SetMole.colstoNode.put(
"Codice", "TXF" )
SetMole.colstoNode.put(
"Descrizione", "TXF" )
SetMole.colstoNode.put(
"Legante", "CMBX" )
SetMole.colstoNode.put(
"Volume", "TXF" )
SetMole.colstoNode.put(
"Area", "TXF" )
SetMole.colstoNode.put(
"Concentrazione", "TXF" )
SetMole.colstoNode.put(
"Densità", "TXF" )
SetMole.colstoNode.put(
"Disegno", "TXF" )
SetMole.colstoNode.put(
"Note", "TXA" )
SetMole.colstoNode.put(
"Corpo", "TXF" )
SetMole.colstoNode.put(
"Stampo", "TXF" )
Se in futuro tu decidessi di usare un codice diverso al posto di "TXF", dovresti andare a riscrivere ognuno di quei "TXF" (certo, molto spesso sarà possibile effettuare la sostituzione grazie alle funzionalità dell'IDE). Avendo invece qualcosa tipo:
Public Const V_TEXTFIELD As String = "TXF" (ma anche Int, volendo), dovresti sostituire il testo soltanto qui.

Altro vantaggio è che non devi ricordare a memoria quale fosse il codice utilizzato, perché il suggerimento dell'IDE, quando inizi a digitare v_ ti aiuterebbe.
Infine (forse) sono utili quando vuoi passare degli argomenti il cui contenuto deve essere uno tra quelli prestabiliti (per questo sarebbero ancora meglio gli Enum ma in b4x non ci sono).


Per creare un form dinamicamente, meglio degli array ma senza impostare inizialmente il numero di elementi, verrano cambiati a runtime; cioè:

Dim tfv() As TextField.

Poi, quando il form riceverà i dati e costruirà il layout, ridimensionerai tfv() con il numero di TextField che ti servirà.
 
Last edited:
Top