Using wxSQLite3 for Creating Mobile Software

New video which shows ho to:

  • Create minimal wxWidgets application for Windows Mobile
  • Compile SQLite for Windows Mobile 5
  • Compile wxSQLite3 for Windows Mobile 5
  • Setup wxWidgets application to use wxSQLite
  • Create SQLite database programmatically
  • Create tables in database programmatically
  • Fill tables with data
  • Retrieve data
  • Handle exceptions

Download video “Using wxSQLite3 for Creating Mobile Software”

Download sample “Using wxSQLite3 for Creating Mobile Software”

Организуем доступ к базам данных SQLite при разработке кросс-платформенных приложений на C++/wxWidgets – Часть III – Сборка проекта под Linux в Eclipse

Продолжение статьи о работе с базами данных на wxWidgets. Первая часть статьи доступна здесь. Вторая часть доступна здесь.
В третьей части рассказывается о том, как собрать приложение, использующее DatabaseLayer, SQLite и wxARG в Linux с помощью Eclipse.

Я использую дистрибутив Fedora Core 5, в котором не оказалось файла libsqlite3.a, необходимого для сборки проекта. Для того чтобы решить эту проблему, я удалил пакеты sqlite и sqlite-devel, затем скачал исходный код sqlite (sqlite-x.y.z.tar.gz), собрал его:

./configure –enable-static
make
make install

После сборки sqlite необходимо убедиться, что путь к файлам libsqlite3.so.* находится в списке путей поиска библиотек. Я же просто создал ссылки на эти файлы в каталоге /lib
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
Теперь, если это еще не сделано, нужно удалить все .h и .cpp файлы, не относящиеся к проекту databaselayer_sqlite из папок databaselayer/src и databaselayer/include, а также папку databaselayer/tests
После того, как предварительная подготовка выполнена, запускаем Eclipse и в папке databaselayer создаем новый проект. Назовем его SqliteDatabaseLayer.
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
Выбираем тип проекта Static Library (Gnu). Жмем Finish
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1

Далее идем в настройки проекта и в разделе C/C++ Build -> Miscellaneous в поле Other flags дописываем

`wx-config --cxxflags`

Заметьте, кавычки обратные (кнопка со знаком ~ на клавиатуре ;))
Отлично, настройки библиотеки SqliteDatabaseLayer мы завершили. Теперь нужно создать проект для тестового приложения.
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
Создаем новый проект в папке SQLiteTest
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
Указываем тип проекта Executable (Gnu)
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
В зависимостях проекта выбираем проект библиотеки SqliteDatabaseLayer. Жмем Finish
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
В свойствах проекта в разделе C/C++ Build -> Directories добавляем новые записи

  • {ProjDirPath}/art
  • {ProjDirPath}/wxActiveRecord
  • {ProjDirPath}/../databaselayer/include

Заметьте, скобки фигурные, в отличии от настроек проекта в Visual Studio
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1

В свойствах проекта в разделе C/C++ Build -> Miscellaneous в поле Other flags дописываем:

`wx-config --cxxflags`

Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
В свойствах проекта в разделе C/C++ Build -> Libraries добавляем новые записи

  • SqliteDatabaseLayer
  • sqlite3

Библиотеки должны быть добавлены именно в указанной последовательности т.к. библиотека libSqliteDatabaseLayer.a зависит от libsqlite3.a

И в списке Library search path добавляем запись

  • {ProjDirPath}/../databaselayer/Debug

Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1

В свойствах проекта в разделе C/C++ Build -> GCC C++ Linker -> Miscellaneous в поле Linker flags дописываем:

`wx-config --libs`

Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1

Собираем проект с помощью Project -> Build Project

После успешной сборки неплохо было бы запустить наше приложение и проверить его на работоспособность.
Выбираем пункт меню Run -> Run…
В диалоговом окне Run жмем правой кнопкой на элементе C/C++ Local Application, выбираем пункт меню New
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1

После этого у нас должна появиться новая конфигурация запуска с названием SQLiteTest
Жмем кнопку Search Project
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
В окне Program Selection выбираем наше приложение. Жмем OK
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
На вкладке Debugger в списке Debugger выбираем GDB Debugger. Жмем Run
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
Ну, вот и результат… довольно опрятно получилось.
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
Диалоговое окно ввода данных выглядит вот подобным образом.
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1

Как видим, ничего особо сложного в разработке кросс-платформенных приложений нет, но, как и любой труд, кросс-платформенная разработка программного обеспечения требует опыта и сноровки. Надеюсь, данный материал послужит толчком для новичков начать немного по-другому смотреть на свои проблемы и на способы их решения.

Скачать исходный код к статье

Организуем доступ к базам данных SQLite при разработке кросс-платформенных приложений на C++/wxWidgets – Часть 2 – wxActiveRecordGenerator (wxARG)

Продолжение статьи, рассказывающей о работе с базами данных в wxWidgets. Первую чать статьи можно почитать здесь.
В предыдущей части мы рассмотрели настройку проекта, сборку дополнительных библиотек и создание графического интерфейса приложения. В этой часит рассказывается как создать классы бизнес-логики с помощью утилиты wxARG и о том, как эти классы использовать в своем проекте.
Continue reading…

Организуем доступ к базам данных SQLite при разработке кросс-платформенных приложений на C++/wxWidgets – Часть I – Шаблон проекта и GUI

Очень часто вижу на форумах темы, связанные с организацией доступа к базам данных для приложений на C++. Тема, сама по себе, довольно актуальная и очень интересная, хотя у новичков зачастую вызывает трудности. И в этот раз я хочу рассказать о том, что написание кросс-платформенных приложений на C++, использующих для своей работы базы данных, не является чем-то непосильным, а также о том, что написание кросс-платформенных приложений может оказаться довольно увлекательным занятием.

Итак, эта статья о разработке приложений, использующих для своей работы базы данных SQLite.
Для работы нам понадобится:

Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
Для начала, создадим новый проект (Win32 Project) в Visual Studio 2005 и назовем его SQLiteTest
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
В мастере создания проекта выберем тип проекта Windows Application и в дополнительных свойствах укажем Empty project
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
Затем распакуем библиотеку DatabaseLayer в папку, в которой находится файл SQLiteTest.sln
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
В Solution Explorer жмём правой кнопкой на названии Solution’а, выбираем пункт Add -> Existing Project
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
И в окне выбора файла проекта, выбираем проект databaselayer/build/databaselayer_databaselayer_sqlite.dsp (или .vcproj).
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
Теперь нам необходимо указать зависимости проектов. Наше приложение должно быть собрано после сборки библиотеки Databaselayer, поэтому в Solution Explorer жмем правой кнопкой на названии проекта SQLiteTest и выбираем пункт меню Project Dependencies…
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
В списке проектов ставим маркер на названии проекта databaselayer_sqlite и жмем OK
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
Далее, выбираем пункт меню Build -> Configuration Manager и указываем конфигурации сборки каждого проекта для каждой конфигурации сборки Solution’а. Я использую статическую раздельную Unicode-сборку wxWidgets, поэтому для Debug-конфигурации сборки Solution’а я выбираю конфигурацию Static Unicode Debug Multilib проекта databaselayer_sqlite и конфигурацию Debug проекта SQLiteTest. Такие же действия необходимо проделать и для Release-конфигурации сборки Solution’а, все вхождения слова Debug в названиях конфигураций на Release
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
После этого, распаковываем архив sqlite-source-x_y_z.zip в папку databaselayer/sqlite/include и архив sqlitedll-x_y_z.zip в папку databaselayer/sqlite/lib
В каталоге databaselayer/sqlite/lib должны появиться файлы sqlite3.dll и sqlite3.def
Всё это очень хорошо, но для использования динамической библиотеки в нашем проекте, неплохо было бы иметь .lib файл, которого у нас сейчас нет. Для того, чтобы он у нас был, создаем два batch-скрипта:

setupvars.bat

"C:/Program Files/Microsoft Visual Studio 8/VC/bin/vcvars32.bat"

export.bat

lib.exe /def:sqlite3.def /machine:x86 /out:sqlite3.lib

Запускаем командную строку, переходим в папку databaselayer/sqlite/lib и по очереди запускаем эти два batch-файла

setupvars
export

После выполнения этих нехитрых действий, у нас должны появиться два файла: sqlite3.exp и sqlite3.lib
Копируем файл sqlite3.dll в папку SQLiteTest/bin

Отлично, теперь создаем в нашем проекте SQLiteTest четыре новых файла:

  • SQLiteTestApp.h
  • SQLiteTestApp.cpp
  • SQLiteTestMainFrame.h
  • SQLiteTestMainFrame.cpp

Теперь открываем свойства проекта, переходим в раздел C/C++ и в настройках Additional Include Directories добавляем две новые записи:

  • $(ProjectDir)../databaselayer/sqlite/include
  • $(ProjectDir)../databaselayer/ include

Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1

Переходим в раздел Linker и в настройках Additional Library Directories добавляем две новые записи:

  • $(ProjectDir)../databaselayer/sqlite/lib
  • $(ProjectDir)../databaselayer/ lib

Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
В разделе Linker -> Input в настройках Additional Dependencies добавляем записи:

  • advapi32.lib
  • comctl32.lib
  • uuid.lib
  • rpcrt4.lib
  • wxbase28ud.lib
  • wxmsw28ud_core.lib
  • wxmsw28ud_adv.lib
  • wxpngd.lib
  • wxcode_msw28ud_databaselayer_sqlite.lib
  • sqlite3.lib

Не забываем, что суффикс d в названиях библиотек wxWidgets указывает на то, что используется отладочная версия библиотеки. Release-версии библиотек не имеют в названии этого суффикса.
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
Далее, в разделе Linker -> General для всех конфигураций указываем параметр Output File равным ../bin/$(ProjectName).exe и в разделе Debugging параметр Working Directory равным ../bin. Это позволит генерировать исполняемый файл в отдельную папку.
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
Итак, предварительная настройка завершена, можно приступать к написанию кода.

SQLiteTestMainFrame.h

#ifndef _SQLITE_TEST_MAINFRAME_H
#define _SQLITE_TEST_MAINFRAME_H

#include 

class SQLiteTestMainFrame : public wxFrame
{	
	void CreateControls();
public:
	SQLiteTestMainFrame();
	bool Create(wxWindow * parent, wxWindowID id, const wxString & title);

	DECLARE_EVENT_TABLE()
	void OnExit(wxCommandEvent & event);
};

#endif

SQLiteTestMainFrame.cpp

#include "SQLiteTestMainFrame.h"
#include "SQLiteTestApp.h"

BEGIN_EVENT_TABLE(SQLiteTestMainFrame, wxFrame)
EVT_MENU(wxID_EXIT, SQLiteTestMainFrame::OnExit)
END_EVENT_TABLE()

SQLiteTestMainFrame::SQLiteTestMainFrame()
{
	Create(NULL, wxID_ANY, _("SQLite Addressbook"));
}

bool SQLiteTestMainFrame::Create(wxWindow * parent, wxWindowID id, const wxString & title)
{
	bool res = wxFrame::Create(parent, id, title, wxDefaultPosition, wxSize(700, 500));
	if(res)
	{
		CreateControls();
	}
	return res;
}

void SQLiteTestMainFrame::CreateControls()
{
	wxMenuBar * menuBar = new wxMenuBar;
	SetMenuBar(menuBar);

	wxMenu * fileMenu = new wxMenu;
	fileMenu->Append(wxID_EXIT, _("ExittAlt+F4"));

	menuBar->Append(fileMenu, _("File"));

	CreateStatusBar(2);
	Centre();
}

void SQLiteTestMainFrame::OnExit(wxCommandEvent & event)
{
	wxUnusedVar(event);
	Close();
}

SQLiteTestApp.h

#ifndef _SQLITE_TEST_APP_H
#define _SQLITE_TEST_APP_H

#include 
#include 
#include 

class SQLiteTestApp : public wxApp
{
	DatabaseLayer * m_Database;
public:
	virtual bool OnInit();
	virtual int OnExit();

	bool ConnectToDatabase();
	DatabaseLayer * GetDatabase();
};

DECLARE_APP(SQLiteTestApp)

#endif

SQLiteTestApp.cpp

#include 
#include 
#include "SQLiteTestApp.h"
#include "SQLiteTestMainFrame.h"

IMPLEMENT_APP(SQLiteTestApp)

bool SQLiteTestApp::OnInit()
{
	if(!ConnectToDatabase())
	{
		wxFAIL_MSG(_("Error connecting to database!"));
		return false;
	}
	wxImage::AddHandler(new wxPNGHandler);
	wxImage::AddHandler(new wxJPEGHandler);

	SQLiteTestMainFrame * frame = new SQLiteTestMainFrame;
	SetTopWindow(frame);
	frame->Show();

	return true;
}

int SQLiteTestApp::OnExit()
{
	if(m_Database)
	{
		if(m_Database->IsOpen())
		{
			m_Database->Close();
		}
		wxDELETE(m_Database);
	}
	return wxApp::OnExit();
}

bool SQLiteTestApp::ConnectToDatabase()
{
	m_Database = new SqliteDatabaseLayer();
	wxString db_filename(wxT("addressbook.db"));
	PreparedStatement * pStatement(NULL);
	bool bCreate = !wxFileExists(db_filename);
	if(bCreate)
	{
		wxMessageBox(_("Database does not exist... recreating."));
	}
	try
	{
		m_Database->Open(db_filename);
		// Try to recreate tables
		try
		{
			m_Database->RunQuery(wxT("CREATE TABLE groups(id integer primary key, 
				name varchar(128) not null,
				description varchar(512));"));
		}
		catch(DatabaseLayerException & e) {wxUnusedVar(e);}
		try
		{
			m_Database->RunQuery(wxT("CREATE TABLE persons(
				id integer primary key,
				groupid integer not null,
				first_name varchar(64) not null,
				last_name varchar(64) not null,
				gender boolean not null,
				address varchar(128) not null,
				city varchar(64) not null,
				country varchar(32) not null,
				phone varchar(32),
				email varchar(128),
				website varchar(260));"));
		}
		catch(DatabaseLayerException & e) {wxUnusedVar(e);}
		if(bCreate)
		{
			m_Database->RunQuery(
				wxT("INSERT INTO groups(name, description) VALUES ('Friends', 'My friends')"));
			pStatement = m_Database->PrepareStatement(
				wxT("INSERT INTO persons(groupid, first_name,last_name,gender,address,city,country,phone) VALUES
					(?,?,?,?,?,?,?,?)"));
			if (pStatement)
			{
				pStatement->SetParamInt(1, 1);
				pStatement->SetParamString(2, _("John"));
				pStatement->SetParamString(3, _("Doe"));
				pStatement->SetParamBool(4, 1);
				pStatement->SetParamString(5, _("SomeStreet st., 123/45"));
				pStatement->SetParamString(6, _("Some City"));
				pStatement->SetParamString(7, _("Some Country"));
				pStatement->SetParamString(8, _("+000-00-000-00-00"));
				pStatement->RunQuery();
				m_Database->CloseStatement(pStatement);
				pStatement = NULL;
			}
		}
	}
	catch(DatabaseLayerException & e)
	{
		if(pStatement) 
		{
			m_Database->CloseStatement(pStatement);
			pStatement = NULL;
		}
		wxFAIL_MSG(e.GetErrorMessage());
		return false;
	}
	return true;
}

DatabaseLayer * SQLiteTestApp::GetDatabase()
{
	return m_Database;
}

Итак, что же мы сделали: мы создали класс приложения SQLiteTestApp, содержащий указатель на объект класса DatabaseLayer, который и будет обеспечивать связь с нашей базой данных. При запуске приложения проверяется наличие файла addressbook.db и, в случае если файл не найден, он создается. Вместе с базой данных создаются две таблицы: groups и persons и заполняются тестовыми данными.
Главная форма приложения содержит строку меню и строку статуса и, пока, ничего не делает.
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
После успешной сборки приложения и его запуска, в папке bin должен появиться файл базы данных addressbook.db
Работа с базами данных в wxWidgets - SQLite + DatabaseLayer - 1
Отлично, теперь можно приступать к работе с базой данных.

Читать продолжение статьи…