Note: this tutorial was made for older versions of DMD, DFL and Entice Designer. While it can still help you along, you will probably get errors if you attempt to compile.

Building a basic AddressBook application using Entice Designer

Introduction

We will build a simple AddressBook application, which uses SQLite as the data storage engine.
This tutorial's purpose is to help D users get in touch with DFL, Entice and SQLite4D.

Requirements:

Download

Download Entice Designer Address Book tutorial. The download comes with SQLite4D.

Planning:

Our plan is quite simple, all we need is an application to store and retrieve data, and a user interface to operate it.
We will split the work into 3 parts:

  1. designing the interface
  2. building the data handling component
  3. connecting these two components

Designing the user interface

We can accomplish the whole addressbook functionality within one single form. A ListView control will be used to hold and display each record as a human understandable identifier (contacts name); some TextBox elements grouped in a GroupBox to insert, edit and display the data; and we also need Buttons to control our application.

To begin...
Start Entice and create a new form (clicking on "New" or "New Form" button) -
Choose a path (i.e. D:\works\myaddressbook) and a name for the form.
Select "Main Form" - this will create the main() function which starts the form (otherwise, the form must be called from another control).

Now you can see the form layout in the designer area. Drag its margins until you match the desired dimensions (400,460). Alternatively, you can change its width and height by editing their values in the Property Panel (docked on the right).
Double click on the text property in the Property Panel and enter "Simple DFL AddressBook", this will set the form caption.

Add the ListView: click on the ListView icon on the ToolBox (docked on the left) and click inside the form in the designer area.
With the ListView selected, change the "dock" property on the property panel from "NONE" to "TOP". This means the ListView will fill the top of the form. If you change the form's size, all its docked children will change their size accordingly. You can still edit its height by dragging its bottom border.
Double click the Name property and change it to "lview"; we will need to access it later, and this trick saves on typing. You should also set gridLines to true and view to DETAILS

Add a Panel to the form, dock it to BOTTOM, and change its name to "buttons". Set its height to 40.

Now add a GroupBox and change its dock property to FILL so it fills the parent's unused space.
Note: we added the bottom Panel before the GroupBox because the order is important in DFL. If you add the Panel after GroupBox, it won't be displayed because the GroupBox is already filling all the space.
Change its name to "group" and set the text property to "De&tails". ("&" is for mnemonics)

Labels: click on the Label icon in the ToolBox, hold the control key on your keyboard while clicking multiple times inside the GroupBox in the designer, add 5 Labels this way (to exit this mode, click on the pointer in the ToolBox) arrange them by dragging or by editing their top and left properties in the Property Panel. Set their text as follows: "name", "address", "telephone", "email" and "website"

Add 5 TextBoxes in the same manner and change their names according to this pattern txtName, txtAddress...

Don't forget to add 4 buttons in the bottom Panel area. Set their height to 26, their names to btn1, btn2, btn3 and btn4 and text to "&New", "&Save", "&Delete", "&Close"

Quick test: save your work, compile it with dfl -ofsab <filename> -gui
now play "spot the difference":

 

Coding the back-end

Switch to text editing mode (<filename> tab at top of designer); add the following imports just above the class declaration

private import 	sqlite_import, sqlite_oo;
import std.string;
add the following declarations after the Entice variables declaration block
SqliteDatabase db;
SqliteResult res;
int rec;
add this code after the initializeMainForm() call in the constructor
initDatabase();
And the initDatabase function is defined as:
private void initDatabase()
{
	db = new SqliteDatabase("data.db");
}
This will open the database "data.db" or create a blank one if the file is not found;
the database structure, we need only one table:
CREATE table `contacts` (
	id integer primary key,
	name,
	address,
	telephone,
	email,
	website);
you can run this query using any tool you like (the download package contains a small sql commander "sqlc.exe"), or let the application take care of this.
res = db.query("SELECT * FROM sqlite_master WHERE type='table' AND name='contacts'"); 
	//read the sqlite documentation for SQL queries;
	
if (!res.numRows) //if no row is returned we need to setup our table;
{
	db.exec(/* the query above */);
}
Add a function to save contact's details and one to delete contacts
private void saveContact(char[][] data) //data contains the TextBox.Texts 
{
//data[0] holds the record number, if =0, it means add a new record, otherwise update this record
	if(data[0] == "0") 
	{
		db.exec("INSERT INTO contacts (name, address, telephone, email, website) 
						values(
						'"~data[1]~"', 
						'"~ data[2] ~"', 
						'"~ data[3] ~"', 
						'"~ data[4] ~"', 
						'"~ data[5] ~"'
				)");
	} else {
		db.exec("UPDATE contacts SET 
						name = '"~data[1]~"', 
						address = '"~data[2]~"', 
						telephone = '"~data[3]~"', 
						email = '"~data[4]~"', 
						website = '"~data[5]~"'
				WHERE 	id='"~data[0]~"'
				");
	}
}
private void deleteContact(char[] id)
{
	db.exec("DELETE FROM contacts WHERE id='"~id~"' ");
}
Add code to load contact. We will pass the ListView to the function which loads data directly into the ListView
private void getContacts(ListView lv)
{
	lv.clear(); // clear any elements and load data after that.
	// This is important because we will call this function after every contact editing or deleting operation.
	res = db.query("SELECT * FROM contacts");
	char[][] c;
	while((c = res.fetch()) != null)
	{
		lv.addRow(c); 
	}
}
Entice is still under development so there are few things we need to take care of, like adding columns to ListView. If you compile the code right now, you'll see that it runs OK, but the list box does not show any records, but it will after adding columns:
initDesign(); //add this line to the constructor
	
private void initDesign()
{
	ColumnHeader col;
	/* this is used to store the sqlite row id */
		col = new ColumnHeader;
		col.width =0; // there is no reason to make it visible
					  // the data is there regardless of it's size;
	lview.columns.add(col);
		col = new ColumnHeader;
		col.text = "Name";
		col.width=400;
	lview.columns.add(col);
		col = new ColumnHeader;
	lview.columns.add(col);
		col = new ColumnHeader;
	lview.columns.add(col);
		col = new ColumnHeader;
	lview.columns.add(col);
		col = new ColumnHeader;
	lview.columns.add(col);
}

Connecting design with data

We need to add actions to Form elements according to the functionality plan below:

adding a new record:
click "New", this enables the GroupBox and the TextBoxes it contains
view record details
double click on a record in the ListView, this changes the TextBoxes to reflect the currently focused ListViewItem.
edit a record
When a record is loaded into the GroupBox, the second button is changed from "save" to "edit"; clicking on "edit" will enable the GroupBox and changes the button from "edit" back to "save".
saving
click save, this will insert a new record or update the current record if in editing mode, and disables the GroupBox;.
deleting records
double click on a record in the ListView and click "delete".
add these lines within the initDesign function body
lview.doubleClick ~= &lview_doubleClick; //on double_click event handling
btn1.click ~= &btn1_click;	
btn2.click ~= &btn2_click;	
btn3.click ~= &btn3_click;	
btn4.click ~= &btn4_click;
and the actions:
protected void lview_doubleClick(Object sender, EventArgs ea)
{
	if(!lview.focusedItem) return false; // if no item is focused(you clicked below records) stop executing;
	
	txtName.text		= lview.focusedItem.subItems.opIndex(0).text;
	txtAddress.text		= lview.focusedItem.subItems.opIndex(1).text;
	txtTelephone.text	= lview.focusedItem.subItems.opIndex(2).text;
	txtEmail.text		= lview.focusedItem.subItems.opIndex(3).text;
	txtWebsite.text		= lview.focusedItem.subItems.opIndex(4).text;
	btn2.text		= "&Edit";
	btn2.enabled		= true;
	btn3.enabled		= true;
	rec = atoi(lview.focusedItem.text); // set the record number;
}

protected void btn1_click(Object sender, EventArgs ea)
{
	group.enabled = true;
	txtName.text		= "";
	txtAddress.text		= "";
	txtTelephone.text	= "";
	txtEmail.text		= "";
	txtWebsite.text		= "";
	btn2.text		= "&Save";
	btn2.enabled		= true;
	btn3.enabled		= false;
	btn4.text		= "&Cancel";
	rec = 0;
}

protected void btn2_click(Object sender, EventArgs ea)
{
	if (btn2.text == "&Save")
	{
		char[][] c;
		c ~= std.string.toString(rec);
		c ~= txtName.text;
		c ~= txtAddress.text;
		c ~= txtTelephone.text;
		c ~= txtEmail.text;
		c ~= txtWebsite.text;
		saveContact(c);
		getContacts(lview);
		group.enabled 		= false;
		txtName.text		= "";
		txtAddress.text		= "";
		txtTelephone.text	= "";
		txtEmail.text		= "";
		txtWebsite.text		= "";
		btn2.enabled 		= false;
		btn3.enabled 		= false;
		btn4.text 		= "&Close";
		rec=0;
	} else {
		group.enabled 		= true;
		btn2.text 		= "&Save";
		btn3.enabled 		= false;
		btn4.text 		= "&Cancel";
	}
}

protected void btn3_click(Object sender, EventArgs ea)
{
	deleteContact(std.string.toString(rec));
	getContacts(lview);
	group.enabled 		= false;
	txtName.text		= "";
	txtAddress.text		= "";
	txtTelephone.text	= "";
	txtEmail.text		= "";
	txtWebsite.text		= "";
	btn2.enabled 		= false;
	btn3.enabled 		= false;
	btn4.text		= "&Close";
}

protected void btn4_click(Object sender, EventArgs ea)
{
	if(btn4.text == "&Close") 
	{
		close();
	} else {
		group.enabled 	= false;
		btn4.text 	= "&Close";
		if(rec==0) 
		{
			txtName.text		= "";
			txtAddress.text		= "";
			txtTelephone.text	= "";
			txtEmail.text		= "";
			txtWebsite.text		= "";
			btn2.enabled 		= false;
			
		} else {
			btn2.enabled		= true;
			btn2.text 		= "&Edit";
			btn3.enabled 		= true;
		}
				
	}

and that would be it!
Compile with dfl -ofsab -gui -release <filename> sqlite_import sqlite_oo sqlite.lib

To add an application icon: create a filename named sab.rc containing this line:
101 ICON DISCARDABLE "sab.ico"
run from command line: rcc sab.rc this will create a file sab.res
add this line to the Form constructor:
icon = new Icon(LoadIconA(GetModuleHandleA(null), cast(char*) 101));
compile with dfl -ofsab -gui -release <filename> sqlite_import sqlite_oo sqlite.lib sab.res
(See this for more information on using icons)

Thank you for your patience.
Please send feed-back about this tutorial to un_guru at yahoo dot com
Edited by Christopher E. Miller
DFL and Entice Designer written by Christopher E. Miller
dprogramming.com