Организуем доступ к базам данных 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 <wx/wx.h>

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 <wx/wx.h>
#include <Databaselayer.h>
#include <SqliteDatabaseLayer.h>

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 <wx/image.h>
#include <DatabaseLayerException.h>
#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
Отлично, теперь можно приступать к работе с базой данных.

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

Creating Nice Reports with wxWidgets ZIP API

wxWidgets contains a set of classes which handle several archive formats. Most commonly used archive format is ZIP. This tutorial shows how to use wxWidgets API for reading and writing ZIP-files.
As you probably know, Microsoft Office 2007 produces .DOCX files which are ZIP archives which contain several XML files, images and few directories inside. After visiting Microsoft Developer’s Days I decided to add new feature to my current project and create new type of report which is based on .DOCX file format. This tutorial contains some techniques which you can use for generating such reports by yourself.
Continue reading…