Italian rubrica telefonica

arenaluigi

Well-Known Member
Licensed User
Longtime User
Onestamente non riscontro il problema.

Questo è il codice:

B4X:
Dim EditText1 As EditText

'nell'evento oncreate scrivo:

Sub Activity_Create(FirstTime As Boolean)
   Activity.LoadLayout("Layout")

   EditText1.Text="però l'albero "   
End Sub

E vedo tutto correttamente.
Forse non ho capito bene qual'è il problema ?
 

fireblade

Member
Il problema è che se nella txtnome, txtcognome e anche nella txtntel inserisco il carattere apice si blocca tuto perchè da quello che ho capito il problema è sql che non gestisce il carattere apice.
Io in qualche modo vorrei disabilitare questo carattere se viene dgitato nelle text, oppure inserire al suo posto il doppio apice (virgolette)

Facendo delle ricerche ho notato che è un problema comune il fatto che SQL si pianta con il carattere apice e credo si possa risolvere anche usando l'istruzione replace.(Però purtroppo io non sono in grado)
 

arenaluigi

Well-Known Member
Licensed User
Longtime User
Sql usa gli apici per identificare una stringa, perciò in una query l'apice può rompere le balle.
Allora fai così:

B4X:
dim stringaconapice as string
dim stringaapicecorretto as string

api="L'albero"
noapi=api.Replace("'","''")
Dovresti ottenere una stringa con doppio apice da utilizzare nelle query
 

fireblade

Member
seguendo la tua dritta ho risolto in questo modo:

SQL1.ExecNonQuery("INSERT INTO tabella VALUES('" & NewID & "','" & txtnome.text.Replace("'","''") & "','" & txtcognome.text & "','"& txtntel.text & "')")

con questo codice è ok...(per provare l'ho messo solo su txtnome)
se scrivo nella txtnome "w l'italia" salva e legge correttamente.

Però non ho usato:
dim stringaconapice as string
dim stringaapicecorretto as string

e questo esempio non l'ho capito,pero ho preso spunto da replace...
api="L'albero"
noapi=api.Replace("'","''")

cmq sei proprio un maestro.
 

klaus

Expert
Licensed User
Longtime User
You can also do it that way:
SQL1.ExecNonQuery("INSERT INTO tabella VALUES(Null," & QUOTE & txtnome.text & QUOTE & "," & QUOTE & txtcognome.text & QUOTE & "," & QUOTE & txtntel.text & QUOTE & ")")
You can use double quotes in the SQL query for text values instead of single quotes.
You can use Null for the ID for automatic incrementing if ID is an INTEGER PRIMARY KEY.

Best regards.
 

fireblade

Member
You can also do it that way:
SQL1.ExecNonQuery("INSERT INTO tabella VALUES(Null," & QUOTE & txtnome.text & QUOTE & "," & QUOTE & txtcognome.text & QUOTE & "," & QUOTE & txtntel.text & QUOTE & ")")
You can use double quotes in the SQL query for text values instead of single quotes.
You can use Null for the ID for automatic incrementing if ID is an INTEGER PRIMARY KEY.

Best regards.

This code is ok for single quotes, for the automatic increment of ID
but if I try to save a name that contains double quotes crashes
 

fireblade

Member
Se avvio l'applicazione con il database completamente vuoto, con questa sub:
(richiamata dall' Activity_Create)
cursor2 = SQL1.ExecQuery("SELECT * FROM tabella")
cursor2.Position=0
txtnome.text=cursor2.getString("nome")
txtcognome.text=cursor2.getString("cognome")
txtntel.text=cursor2.getstring("telefono")

mi va in errore, diversamente se è presente almeno un record è ok
 

fireblade

Member
ho risolto in questo modo:

cursor2 = SQL1.ExecQuery("SELECT * FROM tabella")
If cursor2.RowCount > 0 Then
cursor2.Position=0
txtnome.text=cursor2.getString("nome")
txtcognome.text=cursor2.getString("cognome")
txtntel.text=cursor2.getstring("telefono")
End If
 

GaNdAlF89

Active Member
Licensed User
Longtime User
This code is ok for single quotes, for the automatic increment of ID
but if I try to save a name that contains double quotes crashes

è successo anche a me...ho risolto sostituendo gli apici con * in fase di scrittura nel database; in fase di lettura faccio l'operazione opposta, sostituisco l'asterisco con gli apici.

ho risolto in questo modo:

cursor2 = SQL1.ExecQuery("SELECT * FROM tabella")
If cursor2.RowCount > 0 Then
cursor2.Position=0
txtnome.text=cursor2.getString("nome")
txtcognome.text=cursor2.getString("cognome")
txtntel.text=cursor2.getstring("telefono")
End If

è sempre bene controllare se la query ha dato almeno un risultato, poiché se così non è, cursor2.Position=0 darà errore, visto che non c'è un record su cui impostare la 'position' :)

altra cosa, alla fine dell'If è bene chiudere il cursor, con Cursor.Close. cioè ad ogni query eseguita (che essa dia risultati o meno) deve corrispondere un'istruzione di chiusura del cursor.
 

fireblade

Member
è successo anche a me...ho risolto sostituendo gli apici con * in fase di scrittura nel database; in fase di lettura faccio l'operazione opposta, sostituisco l'asterisco con gli apici.



è sempre bene controllare se la query ha dato almeno un risultato, poiché se così non è, cursor2.Position=0 darà errore, visto che non c'è un record su cui impostare la 'position' :)

altra cosa, alla fine dell'If è bene chiudere il cursor, con Cursor.Close. cioè ad ogni query eseguita (che essa dia risultati o meno) deve corrispondere un'istruzione di chiusura del cursor.


Ok ho capito, grazie per la precisazione.
 

caciola

Member
Salve ho iniziato da poco a utilizzare B4a è sto cercando di capire il funzionamento. Mi rendo conto di provenire da un linguaggio un poco datato (ASP) che ho imparato da solo e volevo comunque iniziare a capire se potevo avvicinarmi a questo linguaggio di programmazione. Ho seguito diversi forum e video tutorial e in qualche modo ho capito più o meno il funzionamento.
Ho scaricato questa App relativa alla rubrica telefonica e l'ho modificata secondo le mie esigenze, però mi sono arenato sulla modalità di voler andare "avanti e indietro" tra i record del db.
Qualcuno sa darmi un input per capire il funzionamento?

Grazie
 

LucaMs

Expert
Licensed User
Longtime User
Ho scaricato questa App relativa alla rubrica telefonica
Non so quale sia l'app ma se usa un normale DB SQLite ti basta cercare sul forum tanti esempi al riguardo (meglio ancora scaricare i manuali pdf e gli esempi di B4A).

Da questo link:
https://www.b4x.com/android/help/sql.html#cursor

l'esempio:

Property_501.png
Position As Int

Gets or sets the current position (row).

Note that the starting position of a cursor returned from a query is -1.
The first valid position is 0.

Example:
B4X:
Dim Cursor As Cursor
Cursor = SQL1.ExecQuery("SELECT col1, col2 FROM table1")
For i = 0 To Cursor.RowCount - 1
    Cursor.Position = i
    Log(Cursor.GetString("col1"))
    Log(Cursor.GetInt("col2"))
Next
Cursor.Close

Quindi è sufficiente impostare la posizione del cursore per accedere al record che ti serve.
 

caciola

Member
Grazie LucaMs per la risposta avevo già provato con un esempio come il tuo ma mi genera errore:

Ecco il mio script:

Sub btnavanti_Click
lvdb.Clear 'need to clear the list
cursor1 = SQL1.ExecQuery("SELECT * FROM tabella")
Log(cursor1.RowCount)
For i = 0 To cursor1.RowCount - 1
cursor1.Position = i + 1
lvdb.AddSingleLine(cursor1.GetString("id")& " : " & cursor1.GetString("nominativo")
Next
cursor1.Close
End Sub

l'Errore è:
An error has occurred in sub:main_voce_result(java line 780)
java.lang.RuntimeException:
Object should first be initialized (List)
Continue?
Cosa sbaglio?



Non so quale sia l'app ma se usa un normale DB SQLite ti basta cercare sul forum tanti esempi al riguardo (meglio ancora scaricare i manuali pdf e gli esempi di B4A).

Da questo link:
https://www.b4x.com/android/help/sql.html#cursor

l'esempio:

Property_501.png
Position As Int

Gets or sets the current position (row).

Note that the starting position of a cursor returned from a query is -1.
The first valid position is 0.

Example:
B4X:
Dim Cursor As Cursor
Cursor = SQL1.ExecQuery("SELECT col1, col2 FROM table1")
For i = 0 To Cursor.RowCount - 1
    Cursor.Position = i
    Log(Cursor.GetString("col1"))
    Log(Cursor.GetInt("col2"))
Next
Cursor.Close

Quindi è sufficiente impostare la posizione del cursore per accedere al record che ti serve.
 

caciola

Member
Scusami ho eliminato alcune voci in più che generavano quell'errore. Ora l'errore che scaturisce dal click avanti è:
sub:main_btnavanti_click (java line: 435)
android.database.CursorIndexOutofBoundsException:Index 2571 requested, with a size of 2571 continue?
 

LucaMs

Expert
Licensed User
Longtime User
Dovresti mandarlo in esecuzione Debug, così avrai il numero di riga di B4A in cui c'è l'errore, altrimenti, in Release, ottieni la riga Java.

Comunque, l'errore dovrebbe essere perché la prima posizione del cursore è zero e non 1, quindi dovresti usare:

For i = 0 To cursor1.RowCount - 1
cursor1.Position = i

anziché

cursor1.Position = i + 1

(per pubblicare il codice, usa questo:
upload_2017-2-14_13-51-30.png

)
 

caciola

Member
Ho inserito il codice come mi hai suggerito tu:
Sub btnavanti_Click

Dim cursor1 As Cursor
cursor1 = SQL1.ExecQuery("SELECT * FROM tabella")
For i = 0 To cursor1.RowCount - 1
cursor1.Position = i
Log(cursor1.getString("nominativo"))
Log(cursor1.getString("direzione"))
Log(cursor1.GetString("via"))
Log(cursor1.GetString("servizio"))
Log(cursor1.GetString("interno"))
Log(cursor1.getstring("telefono"))
Log(cursor1.GetString("fax"))'
Next
cursor1.Close
End Sub

e il risultato è che non mi da più errore ma nel Logs mi fa visualizzare lo scorrere di tutti i record con i vari campi ma nell'app non passa alla record successivo cosa sto sbagliando?
Due mie ipotesi, la prima che non si ferma al record successivo e scorre tutti i record fino alla fine, la seconda che non sto richiamando la visualizzazione nei campi dell'App. Scusami se non riesco ad esprimermi nel modo corretto, spero di essere stato un poco chiaro.
 

caciola

Member
Scusami il tuo messaggio mi è arrivato dopo aver pubblicato il post. E non avevo letto la modalità di pubblicazione del codice.
 

LucaMs

Expert
Licensed User
Longtime User
Se vuoi vedere un record alla volta, magari avanti e indietro, potresti dichiarare il Cursor1 nella routine Globals, eseguire la query in una routine LeggiDaDB, impostare la Position del cursore nelle routine-evento di due button (btnAvanti - Cursor1.Position = Min(Cursor1.Position + 1, Cursor1.RowCount e analoga in un btnIndietro, con Min(0, Cursor1.Position -1)) e chiamare da dentro queste una routine che visualizzi il record nella ListView, CaricaListView(Index).
Anche dalla LeggiDaDB chiami CaricaListView, passando 0 come Index (primo record).

Scusami se non riesco ad esprimermi nel modo corretto, spero di essere stato un poco chiaro.
Come vedi, riesco a spiegarmi anche peggio - ma piccola giustificazione: ho fretta :)


P.S. Tanta era la fretta che ho fatto un mix della prima idea, ovvero mantenere a livello di modulo un Index, con la seconda, usare il Cursor1 come variabile "globale" (locale).
Usando questo secondo metodo non servirà chiamare CaricaListView(Index) ma solo CaricaListView; nella routine semplicemente leggerai i dati dalla posizione attuale del cursore e li caricherai nella ListView.
 
Last edited:

caciola

Member
Scusami se non ho risposto subito ma ho avuto un altro impegno familiare. Intanti ti ringrazio per il tempo che mi dedichi. Ritornando a noi spero di aver capito quello che mi hai spiegato.
HO inserito Cursor1 As Cursor in Sub Process_Globals (penso che potevo metterlo anche su Globals?), dopodichè dovrei creare la routine ma non ho capito se devo inserirla nella Sub btnavanti_click o nella Globals? Puoi farmi un esempio pratico perchè qui mi sono impantanato. Purtroppo ho ancora poca dimestichezza con questo sistema e sebbene cerchi di capirne la logica ho un blocco mentale, mi serve sempre vedere un esempio pratico per capirne in funzionamento. Grazie comunque.
 
Top