Italian B4A - Problemi Map & List

Xela

Member
Licensed User
Longtime User
Salve a tutti

Mi sono incartato e non riesco ad uscirne.
Sono nella fase finale di un'App per tablet che deve raccogliere gli ordini al punto vendita per poi passarli al magazzino.
Nella fase di acquisizione mi servo di una Map dove di volta in volta salvo le righe con le informazioni del prodotto ordinato.
Nel momento della chiusura dell'ordine devo effettuare una "verifica" che se approvata il mio consente di salvare il tutto in un db sqlite in un server.
La verifica consiste nel:
Eliminare eventuali prodotti "cancellati"
Ordinare i prodotti in sequenza nell'ordine con cui sono stati inseriti.
Raggruppare i prodotti uguali comprensivi delle eventuali variazioni
Visualizzare i prodotti ragruppati per un controllo da parte dell'ordinante.
Nel caso di variazioni ricaricare la lista originaria per consentirne le modifiche.

Qui allego un estratto del progetto dove riscontro dei problemi.
In sintesi modificando una Map di appoggio x crearmi una Map raggruppata mi si modifica anche la Map originaria e non riesco a capire il xkè.

Altra curiosità: non c'è qualcosa di più semplice e meno macchinoso di una mappa per gestire una lista di dati?
(in VbNet mi creo un array che aggancio a una struttura pre-definita e per consultazioni o modifiche richiamo l' Array(index).nomecampo)

Gazie per l'aiuto
 

Attachments

  • ProvaMap.zip
    15.7 KB · Views: 26

Sagenut

Expert
Licensed User
Longtime User
Non ho controllato bene tutto il codice perchè i nomi delle variabili sono troppo simili e fanno venire il mal di testa ;) ma credo che il problema sia che con
B4X:
For I = 0 To MapRowApp.Size -1
    Dim sSelRowA As RowList
    sSelRowA.Initialize
    sSelRowA = MapRowApp.Get(I)
    MapRowList.Put(I, sSelRowA)
Next
sSelRowA diventa un riferimento del Type contenuto in MapRowApp.Get(I), non ne diventa una copia a sè stante.
Quindi è come lavorare sempre con il Type originario.
MapRowList conterrà i riferimenti ai Type di MapRowApp, quindi ogni modifica agirà su entrambi perchè puntano allo stesso oggetto (Type).
Puoi provare ad aggiungere una sub tipo questa
B4X:
Private Sub CopyType (source As RowList, target As RowList)
    target.PrgPie  = source.PrgPie
    target.PrgAgg  = source.PrgAgg
    target.sCod = source.sCod
    target.sDes = source.sDes
    target.nQta = source.nQta
    target.nTot  = source.nTot
    target.bAct  = source.bAct
    target.sKey = source.sKey
End sub
e dove ti serve una nuova copia di un type, indipendente, chiama

B4X:
CopyType(MapRowApp.Get(I), sSelRowA)
In questo modo sSelRowA sarà uguale come contenuto al type in MapRowApp.Get(I), ed eventuali modifiche a sSelRowA agiranno solo su di esso.
Lascio a te il divertimento di fare tutte le chiamate corrette con i nomi variabili che per te probabilmente sono più familiari. 🤪
Sperando di non aver fatto casino, fai sapere se risolvi.
Il ciclo diventerebbe così
B4X:
For I = 0 To MapRowApp.Size -1
    Dim sSelRowA As RowList
    sSelRowA.Initialize
    CopyType(MapRowApp.Get(I), sSelRowA)
    MapRowList.Put(I, sSelRowA)
Next
Magari ci sono soluzioni migliori ma ora mi è venuta così.
 
Last edited:
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Non ho scaricato il progetto, ma ciò che ha scritto @Sagenut è corretto.

In tutti i linguaggi di programmazione ad oggetti, quando scrivi:
OggettoA = OggettoB
essi è come se fossero lo stesso oggetto, quelle saranno due variabili che punteranno alla medesima "zona dati", allo stesso, unico oggetto. Quindi modificando parte di OggettoA, avrai modificato la stessa parte di OggettoB.

Creare una funzione per duplicare realmente un oggetto, come ha fatto @Sagenut, risolve il problema, ma è anche una scocciatura, sia perché devi scrivere codice aggiuntivo, sia perché se dovessi modificare la struttura dell'oggetto, poi dovrai modificare anche quella funzione.
Puoi usare: CopyObject.
Nota che, come è scritto in quel thread, non tutti i tipi di dati sono supportati.
 
Last edited:
Upvote 0

Xela

Member
Licensed User
Longtime User
Non ho controllato bene tutto il codice perchè i nomi delle variabili sono troppo simili e fanno venire il mal di testa ;) ma credo che il problema sia che con
B4X:
For I = 0 To MapRowApp.Size -1
    Dim sSelRowA As RowList
    sSelRowA.Initialize
    sSelRowA = MapRowApp.Get(I)
    MapRowList.Put(I, sSelRowA)
Next
sSelRowA diventa un riferimento del Type contenuto in MapRowApp.Get(I), non ne diventa una copia a sè stante.
Quindi è come lavorare sempre con il Type originario.
MapRowList conterrà i riferimenti ai Type di MapRowApp, quindi ogni modifica agirà su entrambi perchè puntano allo stesso oggetto (Type).
Puoi provare ad aggiungere una sub tipo questa
B4X:
Private Sub CopyType (source As RowList, target As RowList)
    target.PrgPie  = source.PrgPie
    target.PrgAgg  = source.PrgAgg
    target.sCod = source.sCod
    target.sDes = source.sDes
    target.nQta = source.nQta
    target.nTot  = source.nTot
    target.bAct  = source.bAct
    target.sKey = source.sKey
e dove ti serve una nuova copia di un type, indipendente, chiama
[CODE=b4x]CopyType(MapRowApp.Get(I), sSelRowA)
In questo modo sSelRowA sarà uguale come contenuto al type in MapRowApp.Get(I), ed eventuali modifiche a sSelRowA agiranno solo su di esso.
Lascio a te il divertimento di fare tutte le chiamate corrette con i nomi variabili che per te probabilmente sono più familiari. 🤪
Sperando di non aver fatto casino, fai sapere se risolvi.
Il ciclo diventerebbe così
B4X:
For I = 0 To MapRowApp.Size -1
    Dim sSelRowA As RowList
    sSelRowA.Initialize
    CopyType(MapRowApp.Get(I), sSelRowA)
    MapRowList.Put(I, sSelRowA)
Next
Magari ci sono soluzioni migliori ma ora mi è venuta così.
Grazie per il prezioso aiuto
Rivedrò x l'ennesima volta il codice e apporterò i tuoi suggerimenti.

Ti terrò informato dell'evolversi del problema.

Rimane aperta la mia curiosità:
non c'è qualcosa di più semplice e meno macchinoso di una mappa per gestire una lista di dati?
tipo: Object(index).ItemName = Value

Grazie ancora
 
Upvote 0

Elric

Well-Known Member
Licensed User
B4X:
Private Sub CopyType (source As RowList, target As RowList)
    target.PrgPie  = source.PrgPie
    target.PrgAgg  = source.PrgAgg
    target.sCod = source.sCod
    target.sDes = source.sDes
    target.nQta = source.nQta
    target.nTot  = source.nTot
    target.bAct  = source.bAct
    target.sKey = source.sKey
End sub
Metodo che usavo anche io finché non ho scoperto
B4X:
Sub Clone(o As Object) As Object 'ignore
    Dim ser As B4XSerializator
    Return ser.ConvertBytesToObject(ser.ConvertObjectToBytes(o))
End Sub
Fonte: https://www.b4x.com/android/forum/t...-easy-way-to-clone-objects.101838/post-639370
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
non c'è qualcosa di più semplice e meno macchinoso di una mappa per gestire una lista di dati?
tipo: Object(index).ItemName = Value
Ordine (mio?) delle migliori strutture "complesse", dalla migliore e più utile:
Map
List
Array

Il tuo esempio:
Object(index).ItemName = Value
Object dovrebbe essere un Array (di nome diverso, perché "Object" è una parola chiave riservata), contenente oggetti di tipo custom view.
Quindi, chiamiamo l'Array MioArr anziché Object e avresti:
B4X:
Type MioTipo(Name As String, Indirizzo As String, ...)
Dim MioArr(100) As MioTipo
'Riempimento dell'Array con oggetti MioTipo
'...
MioArr(5).Name = "Pippo"

Ma:
List è migliore di Array, è più flessibile e consente anche di ordinare i dati (in particolare, ha anche il metodo SortType - vedi help contestuale).
Map è ancora più utile, in quanto puoi "indicizzarla", ovvero puntare ad uno dei suoi elementi, in base ad una chiave, che non deve essere necessariamente un Int, come con gli Array, ma ad esempio un ID alfanumerico di un cliente o magari NomeCognome (String) del cliente o perfino oggetti). Map, però, non ha metodi di sorting, che ovviamente puoi implementare ed anche trovare qui sul sito.

Una differenza secondo me fondamentale tra Array e List è che in B4X non esiste "Redim Preserve", per cui se ridimensioni l'Array, perdi tutto il suo contenuto.
List ha molti metodi, tra i quali Add, che aumenta la dimensione della List (quindi senza dover avere un "Redim Preserve").
 
Last edited:
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Aggiungo una cosetta utilissima, quando usi List o Map contenenti degli oggetti (compresi oggetti di tipo custom):
esiste il casting in linea.

Se, seguendo l'esempio preDecente, anziché usare l'Array MioArr usassi mapClienti, potresti usare:
B4X:
mapClienti.Get(IDCliente).As(MioTipo).Indirizzo = "xxxxxxxxxxx"
ovvero effettuare il casting di un elemento della Map nel tipo MioTipo in un sola riga, senza bisogno di una variabile di comodo.
 
Upvote 0

Xela

Member
Licensed User
Longtime User
Grazie per i Vs suggerimenti.
ho fatto un paio di prove e sembrano funzionare alla grande
Ora invece di usare:
B4X:
    'Prima
    For I = 0 To MapRowList.Size -1
        Dim sAppRow As RowApp
        sAppRow.Initialize
        sAppRow = MapRowList.Get(I)
        If sAppRow.bAct = True Then
            MapRowApp.Put(MapRowApp.Size, sAppRow)
        End If
    Next
    
    'Ora
    For I = 0 To MapRowList.Size -1
        If MapRowList.Get(I).As(RowList).bAct = True Then
            MapRowApp.Put(MapRowApp.Size, MapRowList.Get(I))
        End If
    Next

'e  'Prima
    For I = 0 To MapRowApp.Size -1
        Dim sSelRowA As RowApp
        sSelRowA.Initialize
        sSelRowA = MapRowApp.Get(I)
        MapRowList.Put(I, sSelRowA)
    Next

  'Ora
    For I = 0 To MapRowApp.Size -1
        MapRowList.Put(I, CopyObject(MapRowApp.Get(I)))
    Next

Molto più snello e "pulito"

Domani se riesco apporto le modifiche all'intero progetto cosi verifico se i dati nelle varie Map mi si duplicano ancora.

Grazie a tutti
 
Upvote 0
Top