Cursussen/Courses Codesnippets     Top 
B4A-budget - database changes


1. Category records
In the previous section the app didn't run very well. The cbx1 combobox was not filled with category items.
Let's add some code to the CategoryPage tab to allow the user to add, change and delete category records.
These subroutines are needed to fill the CustomListView clv3 and to show the dialogs.
The public subroutines of the B4XMainPage are used to add, change or delete a record.

Private Sub fill_clv3
	clv3.Clear
	Private sql As String = "SELECT rowid, name, reference FROM category"
	Private rs1 As ResultSet = db.select_query(sql)
	Do While rs1.NextRow
		clv3.AddTextItem(rs1.GetString("name") & " " & rs1.GetString("reference"),rs1.GetString("rowid"))
	Loop
	If clv3.Size > 0 Then
		dragger.Initialize(clv3)
		dragger.AddDragButtons
	End If
End Sub


Private Sub show_add_dialog(tablename As String, title As String,title_color As Int)
	Dim fldlst As List = db.get_fieldnames(tablename)
	Dim pnl1 As Panel = setup_dialog("cat_dialog"," Add " & title,title_color)
	Dim rsub1 As ResumableSub =  catdialog.ShowCustom(pnl1, "OK", "", "CANCEL")
	ftf1.HintText = fldlst.Get(1)
	ftf1.Update
	ftf2.HintText = fldlst.Get(2)
	ftf2.update
	Wait For (rsub1) Complete (Result As Int)
	If Result = xui.dialogResponse_Positive Then
		If ftf1.Text <> "" Then
			B4XPages.MainPage.add_record(tablename, Array As String(ftf1.Text,ftf2.Text))
			reset_list(tablename)
		End If
	End If
End Sub

Private Sub show_change_dialog(tablename As String,rowid As Int, title As String, title_color As Int)
	Dim fldlst As List = db.get_fieldnames(tablename)
	Dim pnl1 As Panel = setup_dialog("cat_dialog"," Edit/Delete " & title, title_color)
	Dim rsub1 As ResumableSub =  catdialog.ShowCustom(pnl1, "SAVE", "DELETE", "CANCEL")
	Private sql As String = "SELECT rowid, "
	For i = 1 To fldlst.Size-1				' fldlst.get(0) = rowid
		If i < fldlst.Size-1 Then
			sql = sql & fldlst.Get(i) & ","
		Else
			sql = sql & fldlst.Get(i) & " FROM " & tablename & " WHERE rowid = ?"
		End If
	Next
	Private id() As String = Array As String(rowid)
	Private rs1  As ResultSet = db.select_query_prepared(sql,id)
	If rs1.NextRow Then
		ftf1.Text = rs1.GetString(fldlst.Get(1))
		ftf2.Text = rs1.GetString(fldlst.Get(2))
	End If
	'ftf1.Text = rowid
	ftf1.HintText = fldlst.Get(1)
	ftf1.Update
	ftf2.HintText = fldlst.Get(2)
	ftf2.update
	Wait For (rsub1) Complete (Result As Int)
	If Result = xui.dialogResponse_Positive Then
		If ftf1.Text <> "" Then
			B4XPages.MainPage.change_record(tablename, Array As String(ftf1.Text,ftf2.Text),rowid)
			reset_list(tablename)
		End If
	else if Result = xui.dialogResponse_Negative Then
		B4XPages.MainPage.remove_record(tablename,rowid)
		reset_list(tablename)
	End If
End Sub

private Sub setup_dialog(strlayout As String,lbltext As String,lblcolor As Int) As Panel
	Dim pnl As B4XView = xui.CreatePanel("")
	pnl.SetLayoutAnimated(0, 0, 0, 340dip, 200dip)
	pnl.LoadLayout(strlayout)
	Dim lbl As Label
	lbl.Initialize("")
	lbl.Text = lbltext
	lbl.TextSize = 18
	lbl.TextColor = Colors.Black
	lbl.Color = lblcolor
	pnl.AddView(lbl,0,0dip,340dip,30dip)
	Return pnl
End Sub

Private Sub reset_list(tablename As String)
	fill_clv3
End Sub
To call the dialogs change the code from the clv3_ItemClick subroutine and from the sbtn3_Click subroutine.
Sub clv3_ItemClick (Index As Int, Value As Object)
	show_change_dialog("category",Value, "Category",Colors.ARGB(100,255,255,135))
	dragger.Initialize(clv3)
	dragger.AddDragButtons
End Sub

Sub sbtn3_Click
	show_add_dialog("category", "Category",Colors.ARGB(100,255,255,135))
	dragger.Initialize(clv3)
	dragger.AddDragButtons
End Sub
After you have declared the database variable and the cat_dialog variable and initialized them then you can test the CategoryPage code.
	Private db As database
	Private catdialog As B4XDialog
	db.Initialize("mybudget","budget_db",True,False)
	catdialog.Initialize(Root)
	catdialog.PutAtTop = True
	catdialog.BackgroundColor = Colors.LightGray
	catdialog.BodyTextColor = Colors.Blue
Run the app.
And now the dialogs in the expenses tab also work and show the category records!


2. save settings
To save the settings from the SettingsPage you can write code to fill the btnsave_Click subroutine:
Sub btnsave_Click
	If ftfstart.text = "" Or ftfend.text = "" Or ftfstartbalance.text = "" Or ftfcurrency.text = "" Then
		xui.MsgboxAsync("All the fields must be filled!", "Mybudget - Settings")
	End If
	If db.get_num_rows("settings") > 0 Then
		Private sql As String = "SELECT rowid, startdate, enddate, startbalance, currency FROM settings"
		Private rs1 As ResultSet = db.select_query(sql)
		rs1.NextRow
		Private rowid As Int = rs1.GetString("rowid")
		B4XPages.MainPage.change_record("settings", Array As String(ftfstart.Text,ftfend.Text,ftfstartbalance.Text,ftfcurrency.text),rowid)
	Else
		B4XPages.MainPage.add_record("settings", Array As String(ftfstart.Text,ftfend.Text,ftfstartbalance.Text,ftfcurrency.text))
	End If
	B4XPages.MainPage.lblbalance.Text = ftfstartbalance.Text
	B4XPages.MainPage.strcurrency = ftfcurrency.Text
End Sub
Declare the database variable:
	Private db As database
Initialize the database:
	db.Initialize("mybudget","budget_db",True,False)
Add a call to the btnsave_Click subroutine at the end of the reset code!
btnsave_Click
The first time the settings fields are not filled yet even though you previously saved them. So we need to write some code in the B4XPage_appear subroutine from the SettingsPage:
Private Sub B4XPage_appear
	If db.get_num_rows("settings") > 0 Then
		Private sql As String = "SELECT rowid, startdate, enddate, startbalance, currency FROM settings"
		Private rs1 As ResultSet = db.select_query(sql)
		rs1.NextRow
		ftfstart.Text = rs1.GetString("startdate")
		ftfend.Text = rs1.GetString("enddate")
		ftfstartbalance.Text = rs1.GetString("startbalance")
		ftfcurrency.Text = rs1.GetString("currency")
	Else
		btnreset_Click
	End If
End Sub


3. B4XMainpage code
Let's concentrate on the B4XMainPage. There is still some work to be done.
The listviews need to be filled.
Click on the B4XMainPage tab in the IDE. Go to the designer, open the clv1_item layout file and generate the members (if you haven't done that yet).
The label variables lbl1,lbl2,lbl3,lbl4 and lblcurr are added to the Class_Globals subroutine.
Now get the information from the database table expenses. Replace the fill_clv1 subroutine with this one:
Private Sub fill_clv1
	clv1.Clear
	Private sql As String = "SELECT expenses.rowid, date, category_id, description, amount, name, reference"
	sql = sql & " FROM expenses,category WHERE expenses.category_id = category.rowid ORDER BY date DESC;"
	Private rs1 As ResultSet = db.select_query(sql)
	Do While rs1.NextRow
		Dim pnl As Panel = clv1_item(rs1)
		clv1.Add(pnl,rs1.GetString("rowid"))
	Loop
End Sub
Each list item is a panel that contains the labels to fill. The clv1_item subroutine takes care of that.
Private Sub clv1_item(res As ResultSet) As Panel
	Dim p As B4XView = xui.CreatePanel("")
	p.SetLayoutAnimated(0, 0dip, 0dip, clv1.AsView.Width,84dip)
	p.LoadLayout("clv1_item")
	lblcurr.Text = "(" & strcurrency & ")"
	lbl1.Text = res.GetString("date")
	lbl2.Text = "-" & NumberFormat2(res.GetString("amount"),0,2,2,False)
	lblbalance.Text = NumberFormat2(lblbalance.Text - res.GetString("amount"),0,2,2,False)
	lbltotalexpense.Text = NumberFormat2(lbltotalexpense.Text - res.GetString("amount"),0,2,2,False)
	lbl3.Text = res.GetString("name") & " " & res.GetString("reference")
	lbl4.Text = res.GetString("description")
	Return p
End Sub
To test the code you can reset the database (remove and recreate) by running the app with the reset boolean from the db.initialize method set to True. Find the line and set the last argument to True:
db.Initialize("mybudget","budget_db",True,True)
Set it back to false for the next run!
Remember the Add button will not work until there are categories!
At the end of the dbdialog response test you can add a call to the B4XPage_Appear event subroutine. This will refresh the list and the cbx1 combobox from the dbdialog.
		B4XPage_Appear
In the show_change_dialog we need to get the information from the database before we can change something.
Add this code to the show_change_dialog:
Private Sub show_change_dialog(rowid As Int, title As String, title_color As Int)
	Dim fldlst As List = db.get_fieldnames(strtablename)
	Dim pnl1 As Panel = setup_dialog("db_dialog"," Edit/Delete " & title, title_color)
	Private sql As String = "SELECT rowid, "
	For i = 1 To fldlst.Size-1				' fldlst.get(0) = rowid
		If i < fldlst.Size-1 Then
			sql = sql & fldlst.Get(i) & ","
		Else
			sql = sql & fldlst.Get(i) & " FROM " & strtablename & " WHERE rowid = ?"
		End If
	Next
	Private id() As String = Array As String(rowid)
	Private rs1  As ResultSet = db.select_query_prepared(sql,id)
	If rs1.NextRow Then
		upd_rowid = rs1.GetString(fldlst.Get(0))
		lbldate.Text = rs1.GetString(fldlst.Get(1))
		ftf1.Text = rs1.GetString(fldlst.Get(4))
		old_amount = rs1.GetString(fldlst.Get(4))
		ftf2.Text = rs1.GetString(fldlst.Get(3))
	End If
	ftf1.HintText = "Amount (" & strcurrency & ")"
...
Note that the old_amount is now set with a value from the database record.
Declare the public variable upd_rowid:
	Public upd_rowid As String
Set the category_id as an argument to the get_cbx1_items subroutine.
	Private cbx1lst As List = get_cbx1_items(rs1.GetString(fldlst.Get(2)))
The call to the show_change_dialog needs to be adjusted. Now we use the value from the listview!
Sub clv1_ItemClick (Index As Int, Value As Object)
	strtablename = "expenses"
	show_change_dialog(Value, "Expense",Colors.ARGB(100,249,177,241))
End Sub
O.K. now let's take care of the earnings tab.
The sbtn2_Click subroutine:
Sub sbtn2_Click
	strtablename = "earnings"
	show_add_dialog("Earning",Colors.ARGB(100,158,255,150))
End Sub
the clv2_ItemClick subroutine:
Sub clv2_ItemClick (Index As Int, Value As Object)
	strtablename = "earnings"
	show_change_dialog(Value, "Earning",Colors.ARGB(100,158,255,150))
End Sub
The fill_clv2 and the clv2_item subroutines:
Private Sub fill_clv2
	clv2.clear
	Private sql As String = "SELECT earnings.rowid, date, category_id, description, amount, name, reference"
	sql = sql & " FROM earnings,category WHERE earnings.category_id = category.rowid ORDER BY date DESC;"
	Private rs1 As ResultSet = db.select_query(sql)
	Do While rs1.NextRow
		Dim pnl As Panel = clv2_item(rs1)
		clv2.Add(pnl,rs1.GetString("rowid"))
	Loop
End Sub

private Sub clv2_item(res As ResultSet) As Panel
	Dim p As B4XView = xui.CreatePanel("")
	p.SetLayoutAnimated(0, 0dip, 0dip, clv2.AsView.Width,84dip)
	p.LoadLayout("clv2_item")
	lblcurr.Text = "(" & strcurrency & ")"
	lbl1.Text = res.GetString("date")
	lbl2.Text = "+" & NumberFormat2(res.GetString("amount"),0,2,2,False)
	lblbalance.Text = NumberFormat2(lblbalance.Text + res.GetString("amount"),0,2,2,False)
	lbltotalearning.Text = "+" & NumberFormat2(lbltotalearning.Text + res.GetString("amount"),0,2,2,False)
	lbl3.Text = res.GetString("name") & " " & res.GetString("reference")
	lbl4.Text = res.GetString("description")
	Return p
End Sub
Get the settings in the B4XPage_Appear subroutine (before the fill_clv1 call):
	lblbalance.Text = 0
	strcurrency = "EUR"
	If db.get_num_rows("settings") > 0 Then
		Private sql As String = "SELECT rowid, startdate, enddate, startbalance,currency FROM settings"
		Private rs1 As ResultSet = db.select_query(sql)
		rs1.NextRow
		lblbalance.Text = rs1.GetString("startbalance")
		strcurrency = rs1.GetString("currency")
	End If
	lblcurrency.Text = "Balance (" & strcurrency & ")" & CRLF & "Start: " & lblbalance.Text
	lbltotalexpense.Text = 0
	lbltotalearning.Text = 0


4. Compile and run
Time to run the app.
The dialogs work fine, you can add, change and delete expenses and earnings records.
The cbx1 combobox shows the category records.
But there is still some work to be done.
When the user changes an expense or an earning the cbx1 combobox doesn't show the change.
The colors, fonts, labels from the layout need some fine tuning.
On to the next section.