Ну вот я снова с Вами и с новой статьёй о QT =). Сегодня поговорим об интересной штуке… о том как можно получить доступ к БД и вывести данные в таблицу на форме.
Для доступа к БД мы будем использовать QtSql — набор классов для работы с базами данных используя язык структурированных запросов SQL. Основные классы данного модуля:
*QSqlDatabase — класс для предоставления соединения с базой, для работы с какой-нибудь конкретной базой данных требует объект, унаследованный от класса.
*QSqlQuery — реализует интерфейс между Qt и базами данных SQL.
*QSqlDriver — абстрактный класс, который реализуется для конкретной базы данных и может требовать для компиляции SDK базы данных. Например, для сборки драйвера под базу данных FireBird/InterBase требует .h файлы и библиотеки статической линковки, входящие в комплект поставки данной БД.
Ну думаю что всем понятно что для начала нужно создать новый проект:
QT += gui QT += sql TARGET = demo03 CONFIG += console CONFIG -= app_bundle TEMPLATE = app SOURCES += main.cpp mainwindow.cpp HEADERS += mainwindow.h
#include #include #include «mainwindow.h» int main(int argc, char *argv[]) < QApplication app(argc, argv); MainWindow *mw = new MainWindow(); mw->setGeometry(200,200,600,400); mw->show(); return app.exec(); >
#include #include class MainWindow : public QMainWindow < Q_OBJECT public: MainWindow(); ~MainWindow(); private: QAction *actionExit; QAction *actionAbout; QMenu *menuFile; QMenu *menuHelp; QLabel *labelMenu; QPushButton *butAdd; QPushButton *butDelete; QLineEdit *lineEdit; QSpinBox *spinBox; QVBoxLayout *vlayout; QHBoxLayout *hlayout; QWidget *mainWidget; QTableWidget *tableWidget; QSqlDatabase db; void RefreshTable(); private slots: void slotAdd(); void slotDelete(); void slotAbout(); >; #endif // MAINWINDOW_H
Разбор полёта
Qt Crash Course for Beginners — Create C++ GUI Apps
QTableWidget
Создаем таблицу QTableWidget с 4-мя колонками:
tableWidget = new QTableWidget(); tableWidget->setColumnCount(4);
Устанавливаем размер 3-х колонок(4-ю колонку мы спрячем и будем использовать для дополнительной информации):
tableWidget->setColumnWidth(0,200); tableWidget->setColumnWidth(1,200); tableWidget->setColumnWidth(2,50);
Называем наши колонки:
tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem(tr(«ID»))); tableWidget->setHorizontalHeaderItem(1, new QTableWidgetItem(tr(«DateTime»))); tableWidget->setHorizontalHeaderItem(2, new QTableWidgetItem(tr(«String»))); tableWidget->setHorizontalHeaderItem(3, new QtableWidgetItem(tr(«Integer»)));
Показываем сетку(ИХМО более приятней для глаз), выключаем MultiSelect и разрешаем выделять только строки:
tableWidget->setShowGrid(true); tableWidget->setSelectionMode(QAbstractItemView::SingleSelection); tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
Скрвыаем колонку с индексом 0:
Qt Tutorial : C++ Notepad App
tableWidget->setColumnHidden(0, true);
Добавляен новую строку и вносим данные:
tableWidget->insertRow(0); tableWidget->setItem(0, 0, new QTableWidgetItem(query.value(0).toString())); tableWidget->setItem(0, 1, new QTableWidgetItem(query.value(1).toDateTime().toString())); tableWidget->setItem(0, 2, new QTableWidgetItem(query.value(2).toString())); tableWidget->setItem(0, 3, new QTableWidgetItem(query.value(3).toString()));
Устанавливаем высоту строки:
tableWidget->setRowHeight(0, 20);
Модуль QtSql использует плагины драйверов для взаимодействия с API различных баз данных. Так как API SQL модуля не зависит от баз данных, код, специфичный для определенной БД, содержится в этих драйверах. Некоторые драйвера поставляются с Qt, а другие могут быть добавлены.
Соединение с базой данных
Прежде, чем получить доступ к базе данных с помощью классов QSqlQuery или QSqlQueryModel, вы должны установить с базой данных хотя бы одно соединение.
Соединения с базой данных идентифицируются с помощью произвольных строк. QSqlDatabase также поддерживает концепцию соединения по умолчанию, которое используется классом Qt SQL, если никакое другое соединение не указано. Этот механизм очень удобен для приложений, использующих только одно соединение с базой данных.
Пример кода устанавливающего соединение с базой данных SQLite:
QSqlDatabase db = QSqlDatabase::addDatabase(«QSQLITE»); db.setDatabaseName(Path); db.open()
Пример кода устанавливающего соединение с базой данных MySQL(используются дополнительные параметры):
QSqlDatabase db = QSqlDatabase::addDatabase(«QMYSQL»); db.setHostName(«localhost»); db.setDatabaseName(«myBase»); db.setUserName(«root»); db.setPassword(«pass»); db.open();
QSqlDatabase::addDatabase() — это имя драйвера. Для получения списка драйверов, смотрите документацию addDatabase(). Для инициализации данных соединения мы вызываем setHostName(), setDatabaseName(), setUserName() и setPassword().
Для удаления соединения с базой данных, сначала закройте базу данных с помощью QSqlDatabase::close(), а затем, удалите ее с помощью статического метода QSqlDatabase::removeDatabase().
Выполнение запроса
Для выполнения SQL запросов, просто создают объект QSqlQuery и вызывают QSqlQuery::exec(). QSqlQuery предоставляет единовременный доступ к результирующей выборке одного запроса. После вызова exec(), внутренний указатель QSqlQuery указывает на позицию перед первой записью. Мы должны вызвать метод QSqlQuery::next() один раз, чтобы переместить указатель к первой записи, затем снова повторять вызов next(), чтобы получать доступ к другим записям, до тех пор пока он не вернет false.
Функция QSqlQuery::value() возвращает значение поля текущей записи. Поля задаются индексами, начиная с нуля. Функция QSqlQuery::value() возвращает значение типа QVariant, который может хранить значения различных типов C++ и ядра Qt, такие как int, QString и QByteArray. Различные типы значений базы данных автоматически приводятся к ближайшему эквиваленту в Qt.
Вы можете перемещаться взад и вперед по выборке, используя функции QSqlQuery::next(), QSqlQuery::previous(), QSqlQuery::first(), QSqlQuery::last() и QSqlQuery::seek(). Текущий номер строки можно получить с помощью QSqlQuery::at(), а общее количество строк в выборке, если это поддерживается базой данных, возвращается функцией QSqlQuery::size().
Пример(В нижеприведенном примере мы не указываем соединение, поэтому используется соединение по умолчанию.):
QSqlQuery query; query.exec(«SELECT * FROM tabMain;»); while (query.next()) < tableWidget->insertRow(0); tableWidget->setItem(0, 0, new QTableWidgetItem(query.value(0).toString())); tableWidget->setItem(0, 1, new QTableWidgetItem(query.value(1).toDateTime().toString())); tableWidget->setItem(0, 2, new QTableWidgetItem(query.value(2).toString())); tableWidget->setItem(0, 3, new QTableWidgetItem(query.value(3).toString())); tableWidget->setRowHeight(0, 20); >
Если возникает ошибка, exec() возвращает false. Доступ к ошибке можно получить с помощью QSqlQuery::lastError().
Вставка, изменение и удаление записей
Вставляя запись в таблицу, используя INSERT, можно одновременно вставить множество записей. Но зачастую эффективней отделить запрос от реально вставляемых значений. Это можно сделать с помощью вставки значений через параметры.
В следующем примере показана вставка с помощью поименованного параметра:
QSqlQuery query; query.prepare(«INSERT INTO tabMain VALUES (null , :datetime, :string, :int);»); query.bindValue(«:datetime», QDateTime::currentDateTime()); query.bindValue(«:string», lineEdit->text()); query.bindValue(«:int», spinBox->value()); query.exec();
Помимо удобства выполнения, вставка через параметры имеет еще и то преимущество, что вы избавлены от необходимости заботиться о преобразовании специальных символов.
Изменение записей очень похоже на вставку в таблицу:
QSqlQuery query; query.prepare(«UPDATE tabMain SET String = ‘:string’, Int = :int WHERE lineEdit->text()); query.bindValue(«:int», spinBox->value()); query.bindValue(«:id», iID); query.exec();
И наконец приведем пример выражения DELETE:
QSqlQuery query; query.prepare(«DELETE FROM tabMain WHERE tableWidget->item(tableWidget->currentIndex().row(), 0)->text()); query.exec();
Ну вот и плод этих стараний =)
Источник: open-life.org
Qt C++ — пример программы — несколько форм — как передать указатель на родительскую форму -обмен данными между формами- пример
/*ниже дочерний и родительский класс взаимно используют друг друга в собственных
описаниях. Чтобы интерпретатор понял что к чему — мы сначала их объявляем
— а потом только описываем — причём методы
родительского класса описываем вообще снаружи — а первое объявлеение дочерего класса
— чисто формальное, оно позволяет интерпретатору понять,
что мы вообще имеем дело с классом (хотя бы это) а не со случайно
нажатой комбинацией клавишь =))
*/
/* опишем класс
главного окна который наследует
функционал и свойства QMainWindow*/
class myMainWindow:public QMainWindow
< Q_OBJECT // макрос необходимый для вссякого класса
// который использует синтаксис Qt отличный от стандарта Си++
// -в нашем случае — это описание слотов Qt
/* опишем класс
дополнительного окна
программы*/
class NewWindow :public QWidget
< Q_OBJECT
public:
// храним ссылки на составные
// компоненты — дочерние элементы окна
QPushButton* button2;
QPushButton* openNewWindow;
QLineEdit* pathEdit;
QPushButton* startButton;
QTextEdit *resultText;
// храним ссылку на массив URL-ов
// с информацией об их вхождениях в файлы
ResultArray* resultInfo;//результат работы программы =))
// также сохраним ссылку на родительское окно чтобы
// обмениваться данными и посылать команды на создание дополнительных окон из главного окна
myMainWindow* parentWindow; // ссылка на родителя
// далее описание конструктора дополнительного окна
NewWindow(myMainWindow* parent,QString path=»D:/Bu-Bu/HTML»): QWidget() //
/* ОЧЕНЬ ВАЖНО = чтобы виджеты отображались на дополнительном окне
на хранить указатели на них в виде полей данного окна (его класса)
как это сделано в данном примере,скажем, для кнопки button2*/
// this->parentWindow= parent; //запоминаем ссылку на родительское окно
// обеспечим возможность передачи пути во внось открываемое окно
resultInfo = new ResultArray();
this->resize(400, 500);
// чтобы окна не были в куче используем qrand()
this->move(100+(qrand() % 300), 100+(qrand() % 300));
this->setWindowTitle(«Окно операции (поиска)»);
//вернёт строчку, в которой окажется содержимое файла
static QString readFile(QString filename)
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return NULL;
QByteArray total;
QByteArray line;
while (!file.atEnd()) line = file.read(1024);
total.append(line);
>
int CheckColAndLine(int elnumd,int col,int line,QString filename)
int result = 0;//такого вхождения нет
UrlInfo* urlinfo = this->resultInfo->urls[elnumd];
for (int i = 0; i files.size(); ++i)
if ((urlinfo->line[i]==line)(urlinfo->col[i]==col)(!(QString::compare(urlinfo->files[i],filename))))
result=1;
>
>
return result;
>
/*проверяет — просматривая массив
— известен ли нам уже данный URL*/
int CheckUrlInArray(QString str,int strnumb,int colpoz, QString filename)
int result=0;
UrlInfo* urlinfo;
for (int i = 0; i resultInfo->urls.size(); ++i)
urlinfo =this->resultInfo->urls[i];
if (!(QString::compare(urlinfo->url,str)))// если такой URL уже известен
result=1;
/*решаем — записывать и очередное вхождение*/
if (!(CheckColAndLine(i,colpoz,strnumb,filename))) // если это другая строка или другое вхождение на этой же строке
urlinfo->files.push_back(filename);
urlinfo->col.push_back(colpoz);
urlinfo->line.push_back(strnumb);
>
break;
>
>
return result;
>
/*проверяет известность URL-а — и если он не известен, то
создаёт новую запист в массиве*/
int IsInResultArray(QString str,int strnumb,int colpoz, QString filename)
int result=0;
// если подобный url ещё не встречался
if(!CheckUrlInArray(str,strnumb,colpoz,filename))
// создаём новую запись о новом Url-е
UrlInfo* info= new UrlInfo();
info->url=str;
info->files.push_back(filename);
info->col.push_back(colpoz);
info->line.push_back(strnumb);
// добавляем эту запись в массива результата:
this->resultInfo->urls.push_back(info);
result = 1;// фиксируем тот факт, что нашли новый
>
return result; //нашли ли новый URL
>
int ParseString(QString str,int strnumb,QString filename)
//int pos = rxp->indexIn(str);
//int pos = rxp.indexIn(«Length: 36 inches»);
if (rxp.indexIn(str)!=-1) // если URL встречается в строке
QStringList list = rxp.capturedTexts(); // получаем массив вхождений
QString rezline;
for (int i = 0; i
rezline = list[i];
QRegExp rxp(«(«+rezline+»)»);
int colnumb = rxp.indexIn(str);
if (colnumb!=-1)
result+=(IsInResultArray(rezline,strnumb,colnumb,filename));
>
// эта функция разбивает файл на строки и для каждой вызывает
void ParseFile(QString str,QString filename)
QString line =»»; // сюда заносим массив строк для каждого элемента
QByteArray ar = str.toAscii();
char* p=ar.data();
int n1=0;
int n=0;//счётчик строк
int nu=0; // число найденных в файле уникальных URL
while(*p)
if (*p==’n’)//если встретили символ переноса строки
< n++; // увеличиваем счётчик
nu+=ParseString(line,n,filename); // отдаём строку на «разбор»
line=»»; // обнуляем временную строку
> else
line+=*p; // прибавляем очередной символ
>
p++;
if (line==»»)// если была только одна строка
nu+=ParseString(line,n,filename); // отдаём строку на «разбор»
n++;
>
>
logIt(«Найдено [«+QString::number(n) +»] строк» + «n Среди них обнаружено [«+QString::number(nu) +»] уникальных URL»);
void ShowResult()
UrlInfo* urlinfo;
QString result=»»; // сюда записываем весь резульатат прежде чем вывести на экран
// foreach (this->resultInfo->urls,urlinfo)
for (int i = 0; i resultInfo->urls.size(); ++i)
urlinfo=this->resultInfo->urls[i];
result += «[«+QString::number(i)+»] «+»URL =»+urlinfo->url+»n встречается в файлах [строка] | [столбец] =n»;
for (int j = 0; j files.size(); ++j)
result += «(«+QString::number(j)+») Файл [«+QString::number(urlinfo->line[j])+»] | [«;
result +=QString::number(urlinfo->col[j])+»] =n»;
>
result +=»n=============================n==========================n»;
>
this->resultText->setText(this->resultText->toPlainText()+result);// выводим результаты поиска на экран
/*описываем слоты нашего окна операций(дочернее по отношению к главному)*/
public slots:
void chooseDirectory() // описываем реализацию внутри тела программы
this->pathEdit->setText(QFileDialog::getExistingDirectory(this, tr(«Open Directory»),»/home»,QFileDialog::ShowDirsOnly));
>
void openAdditionalWindow() // описываем реализацию внутри тела программы
this->parentWindow->opnNewWindow(this->pathEdit->text());// используем обычный метод
>
void searchUrl() // запускает функциию поиска вхождений Url
// получаем текущий путь и «открываем» папку
QDir dir(this->pathEdit->text());// передаём в конструктор строку
QStringList nameFilter; // имя фильтра
// можно задать интересующие расширения nameFilter nameFilter QFileInfoList list = dir.entryInfoList( nameFilter, QDir::Files );// сказываем что нас интересуют только файлы
QFileInfo fileinfo; // сюда будем считывать эжлементы
foreach (fileinfo, list) // foreach — приятный подарок-макрос от Qt =)
logIt(«Открыт файл
«);
>
//выводим результаты поиска в текстовое поле
ShowResult();
>
//===========далее описание методов и слотов для myMainWindow
void myMainWindow::openNewWindow() // описываем реализацию внутри тела программы
NewWindow * someNewWindow = new NewWindow(this); // Be sure to destroy you window somewhere
winds.push_back(someNewWindow); // добавляем очедное окно —
// наше приложение таким образом будет многооконным
>
void myMainWindow::opnNewWindow(QString path=»123″) // описываем реализацию снаружи (метод)
NewWindow * someNewWindow = new NewWindow(this,path); // Be sure to destroy you window somewhere
winds.push_back(someNewWindow); // добавляем очедное окно —
// наше приложение таким образом будет многооконным
>
// описываем конструктор снаружи класса
myMainWindow::myMainWindow(QWidget *parent)
: QMainWindow(parent)
/*создаём действие используя конструктор типа
QAction ( const QString , this);
QMenu *file;
file = menuBar()->addMenu(«);
// указываем одно из действий для элемента меню File
QAction *newsearch = new QAction(«, this);
file->addAction(newsearch);
file->addAction(quit2);
//file = menuBar()->addMenu(«);
/*прикрепляем сигналы к слотам — в обоих случаях мы оюидаем от пользователя
активизации элемента меню (triggered()) — но для действия ВЫХОД
мы вызываем стандартный слот выхода =quit()
а для действия открытия нового окна слот openNewWindow()
котроый мы описали в классе myMainWindow выше*/
connect(quit2, SIGNAL(triggered()), qApp, SLOT(quit())); // для выхода
connect(newsearch, SIGNAL(triggered()), this, SLOT(openNewWindow())); // для доп. окна
this->setWindowTitle(«Главное окно программы (4 задача Си++)»);
logEdit = new QTextEdit(this);
logEdit->move(120,100);
logEdit->resize(600,300);
QLabel *review = new QLabel(«Журнал событий:», this);
review->move(10,100);
this->resize(800, 400);
this->show();
int main(int argc, char *argv[])
// блок настройки кодировки
// выбирайте кодировку в соответсвии с реальной кодировкой исходника
QTextCodec *cyrillicCodec = QTextCodec::codecForName(«UTF-8»);
QTextCodec::setCodecForTr(cyrillicCodec);
QTextCodec::setCodecForLocale(cyrillicCodec);
QTextCodec::setCodecForCStrings(cyrillicCodec);
//конец блока настройки кодировки
QApplication app ( argc, argv );
myMainWindow *window = new myMainWindow();
_____________
матфак вгу и остальная классика =)
Источник: fkn.ktu10.com
C qt пример программы
В этой статье я кратко опишу готовое решение по вопросу о том, как в C++ / Qt написать функцию обратного вызова (callback-функцию).
Задача: есть некий класс Airplane (самолетик). Нужно сделать этому классу интерфейсный метод, через который можно указать, какую внешнюю функцию использовать для управления поведением самолетика. Затем надо создать объект класса Airplane , и задать ему функцию поведения.
Пусть метод, через который устанавливается функция поведения называется setCallbackFunc . Этот метод должен иметь всего один параметр — указатель на функцию, который он должен запомнить. Тогда интерфейс класса самолетика (h-файл) может выглядеть так:
class Airplane : public QObject
void setCallbackFunc (void (*func)(QObject *airplane,
// Указатель в котором запоминается
// указатель на функцию поведения самолетика
void (*callbackFunc)(QObject *airplane, int y));
>;
Вопрос: сколько параметров мы видим в прототипе метода setCallbackFunc ? Для тех, кто слабо понимает жуткий синтаксис C++, скажу, что правильный ответ — один. Почему так, будет объяснено чуть ниже. Теперь непосредственно реализация метода, который устанавливает функцию обратного вызова:
void Airplane:: setCallbackFunc ( void (*func)(QObject *airplane,
// Эапоминается переданный указатель
Для управления самолетиком будем использовать обычную функцию (хотя, вместо обычной функции можно использовать метод какого-нибудь класса).
Как видно из вышеприведенного кода, функция, которая должна управлять поведением самолетика, принимает указатель на объект, который ее вызвал (переменная *airplane ). Можно обойтись и без этого указателя, но в дальнейшем он может пригодиться для вызова каких-то методов объекта самолетика. Так же эта функция принимает текущие координаты x и y самолетика по ссыке , чтобы функция могла эти координаты изменять.
Важный момент для понимания. Найдите в вышеприведенном коде конструкцию:
void (*func)(QObject *airplane,
Эта монструозная конструкция ни что иное, как указатель на функцию. Причем не на абы какую функцию, а только на ту, которая возвращает тип void и принимает три аргумента с типами QObject* , int . Имя этого указателя — func .
Функция управления самолетиком может выглядеть так:
Прототип в h-файле:
static void fly(QObject *airplane, int y);
Обратите внимание, что прототип функции fly() описывается как static . Это важно, так как только статические функции (или методы классов) могут работать как callback-функции. Если забыть указать ключевое слово static , то в момент компиляции будет ошибка вида:
error: no matching function for call to ‘Airplane::setCallbackFunc()’
candidates are: void Airplane::setCallbackFunc(void (*)(QObject*, int))
Реализация функции управления самолетиком:
void fly(QObject *airplane, int y)
С такой реализацией самолетик полетит по мягкой параболе. Обратите внимание, что в реализации ключевое слово static не указывается. Это особенность синтаксиса C++: ключевое слово static нужно указывать только в прототипе.
Далее возникает вопрос: а как вызывать эту функцию обратного вызова? А очень просто! Предположим, что у класса Airplane есть метод update() , и в нем нужно сделать вызов нашей callback-функции. Код этого метода может выглядеть так:
// Вызов функции управления поведением самолетика
// qobject_cast(this) — это указатель
// на текущий объект самолетика
// x и y — текущие координаты самолетика
callbackFunc(qobject_cast(this), x, y);
Теперь последний штрих. Создаем объект самолетика, и задаем ему функцию поведения:
mig29. setCallbackFunc( fly);
Все! Если теперь постоянно вызывать метод mig29.update() , то координаты самолетика будут меняться согласно алгоритму, заданному в функции fly() .
Источник: webhamster.ru