
- •Реферат
- •Введение
- •1 Постановка задачи и анализ предметной области
- •1.1 Постановка задачи на разработку информационной системы
- •1.2 Функциональное моделирование бизнес-процессов предметной области
- •1.3 Моделирование потоков данных в предметной области
- •1.4 Построение исходной концептуальной модели данных предметной области
- •2 Проектирование информационной системы
- •2.1 Категории пользователей ис и их информационные потребности
- •2.2 Архитектура информационной системы
- •2.3 Логическая модель базы данных информационной системы
- •2.4 Пользовательский интерфейс приложения информационной системы
- •2.5 Требования к аппаратно-программному окружению информационной системы
- •2.6 Выбор технологий и средств разработки информационной системы
- •3. Разработка информационной системы
- •3.1 Физическое модель и реализация базы данных информационной системы
- •3.2 Серверная часть приложения информационной системы
- •3.3. Запросы клиентского приложения к базе данных
- •3.4 Кодирование клиентского приложения
- •3.5 Средства поддержки пользователя клиентского приложения
- •3.6 Тестирование клиентского приложения
- •Заключение
- •Список использованных источников
- •Приложение а (обязательное)
- •Приложение б
Заключение
В данном курсовом проекте была разработана информационная система для проведения тестирования среди студентов или более широкого круга пользователей.
Были проведены анализ требований, проектирование базы данных и запросов к ней. Разработано приложение, выполняющее все требуемые функции.
Для разработки приложения использовались: C++, Qt, PostgreSQL.
При проведении тестирования клиентского приложения ошибок не обнаружено.
Цель разработки достигнута.
Список использованных источников
PostgreSQL. Серия из шести статей Евгения Балдина, опубликованных в журнале Linux Format (2006—2007).
PostgreSQL. Наиболее продвинутая открытая СУБД в мире. Русскоязычный сайт о PostgreSQL (http://postgresql.ru.net/).
Дж. Уорсли, Дж. Дрейк - PostgreSQL для профессионалов [2003].
Русскоязычный форум по Qt (http://www.prog.org.ru/).
Жасмин Бланшет, Марк Саммерфилд - Qt 4: программирование GUI на С++ [2007].
М. Шлее - Qt Профессиональное программирование на С++[2006].
Официальная документация Qt (http://doc.qt.nokia.com/).
Приложение а (обязательное)
Текст программы
«DBAccess.h»:
#pragma once
#include <QSqlDatabase>
#include "../TS_Lecturer/Question.h"
class DBAccess
{
public:
DBAccess();
bool Connect(const QString& hostName, const QString& databaseName, const QString& userName, const QString& password);
~DBAccess(void);
QStringList GetStudentsList (QString group);
bool AddAnswer (int id, QString GroupName);
QString FindId(QString idCode);
void GetQuestions ();
void ShowQuestions(QTextBrowser *outQuestion, QGridLayout *outAnswer);
void ShowNextQuestion (QTextBrowser *outQuestion, QGridLayout *outAnswer);
void ShowPrevQuestion (QTextBrowser *outQuestion, QGridLayout *outAnswer);
int QuestionNumber;
private:
QSqlDatabase db;
int idTest;
CQuestions questions;
};
«DBAccess.cpp»:
#include "DBAccess.h"
#include <QMessageBox>
#include <QtSql>
#include <QDateTime>
#include <QTextBrowser>
DBAccess::DBAccess(void)
{
db = QSqlDatabase::addDatabase("QPSQL");
QuestionNumber = 0;
}
DBAccess::~DBAccess(void)
{
}
bool DBAccess::Connect(const QString& hostName, const QString& databaseName, const QString& userName, const QString& password)
{
db.setHostName(hostName);
db.setDatabaseName(databaseName);
db.setUserName(userName);
db.setPassword(password);
if (!db.open())
{
QMessageBox::critical(0, "Database Error", db.lastError().text());
return false;
}
return true;
}
QStringList DBAccess::GetStudentsList (QString group)
{
QStringList students;
QSqlQuery query;
QSqlQueryModel model;
model.setQuery(QString("SELECT \"Name\" FROM \"TExaminee\" WHERE \"idGroup\" = (SELECT \"id\" FROM \"TGroup\" WHERE \"Name\" = '%1')").arg(group), db);
if(!model.rowCount())
{
QMessageBox::information(NULL, "Error",
QString("Can't find any students in group %1").arg(group));
}
for (int i = 0; i < model.rowCount(); i++)
{
students.append(model.record(i).value("Name").toString());
}
return students;
}
QString DBAccess::FindId(QString Code)
{
QSqlQuery query;
QSqlQueryModel model;
model.setQuery(QString("SELECT \"id\" FROM \"TExaminee\" WHERE \"Code\" = '%1'").arg(Code), db);
if(!model.rowCount())
{
QMessageBox::critical(0, "Database Error", db.lastError().text());
}
return model.record(0).value(0).toString();
}
bool DBAccess::AddAnswer (int id, QString GroupName)
{
QSqlQueryModel model;
model.setQuery(QString("SELECT \"idSubject\", \"idTest\", \"idExaminator\" FROM \"TCurrentTest\" WHERE \"idGroup\" = (SELECT \"id\" FROM \"TGroup\" WHERE \"Name\" = '%1')").arg(GroupName), db);
if(!model.rowCount())
{
QMessageBox::critical(0, "Database Error", db.lastError().text());
}
int idSubject = model.record(0).value(0).toInt();
idTest = model.record(0).value(1).toInt();
int idExaminator = model.record(0).value(2).toInt();
QSqlQuery query;
query.prepare(QString("INSERT INTO \"TPassedTest\" (\"idExaminee\", \"idSubject\", \"idTest\", \"idExaminator\", \"Date\") VALUES (%1, %2 ,%3, %4, %5::abstime)").arg(id).arg(idSubject).arg(idTest).arg(idExaminator).arg( QDateTime::currentDateTime().toTime_t()));
if(!query.exec())
{
QMessageBox::critical(0, "Database Error", db.lastError().text());
return false;
}
return true;
}
void DBAccess::GetQuestions ()
{
QSqlQueryModel model;
model.setQuery(QString("SELECT \"Content\" FROM \"TQuestion\" WHERE \"idTest\" = '%1'").arg(idTest), db);
if(!model.rowCount())
{
QMessageBox::critical(0, "Database Error", db.lastError().text());
}
for (int i = 0; i < model.rowCount(); i++)
{
questions.AddFromXML(model.record(i).value("Content").toString().toUtf8());
}
}
void DBAccess::ShowQuestions(QTextBrowser *outQuestion, QGridLayout *outAnswer)
{
if (!questions.Questions.isEmpty())
questions.Questions[QuestionNumber].Display(outQuestion, outAnswer);
}
void DBAccess::ShowPrevQuestion (QTextBrowser *outQuestion, QGridLayout *outAnswer)
{
QuestionNumber = qMax(0, QuestionNumber - 1);
ShowQuestions(outQuestion, outAnswer);
}
void DBAccess::ShowNextQuestion (QTextBrowser *outQuestion, QGridLayout *outAnswer)
{
QuestionNumber = qMin(questions.Questions.size() - 1, QuestionNumber + 1);
ShowQuestions(outQuestion, outAnswer);
}
«Question.h»:
#pragma once
#include <QString>
#include <QPair>
#include <QPixmap>
#include <QTextBrowser>
#include <QLayout>
struct HTMLWithPictures
{
QString Content;
class CPicture
{
public:
QString Name;
QPixmap Pixmap;
QString tmpPath;
QString tmpName;
~CPicture();
void UnpackPictures();
};
QVector<CPicture> Pictures;
};
struct CQuestion : public HTMLWithPictures
{
int MaxScore;
QString AnswerType;
struct
{
QVector<HTMLWithPictures> Cases;
QString Manual;
// Enum??
} Answer;
void Display( QTextBrowser *outQuestion, QGridLayout *outAnswer );
};
class CQuestions
{
public:
void LoadFromXML( CQuestion &out, QByteArray xml );
void SaveToXML();
QByteArray OpenFromFile(QString path);
void AddFromXML (QByteArray xml)
{
Questions.resize(Questions.size() + 1);
LoadFromXML(Questions.last(), xml);
};
QVector<CQuestion> Questions;
};
«Question.cpp»:
#include "Question.h"
#include <QDomDocument>
#include <QFile>
#include <QMessageBox>
#include <QLabel>
#include <QRadioButton>
void CQuestions::SaveToXML()
{
/*
QDomDocument doc("QuestionXML");
QDomElement question = doc.createElement("Question");
question.setAttribute("Number", Number);
question.setAttribute("MaxScore", MaxScore);
doc.appendChild(question);
QDomElement tag = doc.createElement("Content");
question.appendChild(tag);
QDomText cont = doc.createTextNode(Content);
tag.appendChild(cont);
QString xml = doc.toString();
QFile out("out.xml");
out.open(QIODevice::WriteOnly);
out.write(xml.toAscii());
*/
}
QByteArray CQuestions::OpenFromFile(QString path)
{
QFile file(path);
if (file.open(QIODevice::ReadOnly))
return file.read(file.size());
return QByteArray();
}
void CQuestions::LoadFromXML( CQuestion &out, QByteArray xml )
{
QDomDocument doc("Question");
doc.setContent(xml);
// "element" is xml's root
QDomElement element = doc.documentElement();
// Loop for every child in "element"
for(QDomNode node1 = element.firstChild(); !node1.isNull(); node1 = node1.nextSibling())
{
QString nodeName = node1.nodeName();
if (nodeName == "Content")
{
// Question's content in HTML:
out.Content = node1.firstChild().toCDATASection().data();
}
else if (nodeName == "Data")
{
// Getting all data entries. So far only pictures are supported
for(QDomNode node2 = node1.firstChild(); !node2.isNull(); node2 = node2.nextSibling())
{
// Picture's filename
QString picName = node2.attributes().namedItem("name").firstChild().toText().data();
// Picture's base64 data -> byte array -> pixmap
QString picData = node2.firstChild().toText().data().trimmed();
QByteArray pixmapData = QByteArray::fromBase64(picData.toAscii());
QPixmap pixmap;
pixmap.loadFromData((uchar *)pixmapData.constData(), pixmapData.size());
if (!picName.isEmpty() && !pixmap.isNull())
{
out.Pictures.resize(out.Pictures.size() + 1);
out.Pictures.last().Name = picName;
out.Pictures.last().Pixmap = pixmap;
}
}
}
else if (nodeName == "Answers")
{
// Answer's type
out.AnswerType = node1.attributes().namedItem("type").firstChild().toText().data();
if (out.AnswerType == "Case")
{
int answerNum = 1;
for(QDomNode node2 = node1.firstChild(); !node2.isNull(); node2 = node2.nextSibling(), answerNum++)
{
//answerNum;
out.MaxScore = node2.attributes().namedItem("score").toText().data().toInt();
for(QDomNode node3 = node2.firstChild(); !node3.isNull(); node3 = node3.nextSibling())
{
if (node3.nodeName() == "Content")
{
out.Answer.Cases.resize(out.Answer.Cases.size() + 1);
// Answer's content in HTML:
out.Answer.Cases.last().Content = node3.firstChild().toCDATASection().data();
}
else if (node3.nodeName() == "Data")
{
for(QDomNode node4 = node3.firstChild(); !node4.isNull(); node4 = node4.nextSibling())
{
// Picture's filename
QString picName = node2.attributes().namedItem("name").firstChild().toText().data();
// Picture's base64 data -> byte array -> pixmap
QString picData = node4.firstChild().toText().data().trimmed();
QByteArray pixmapData = QByteArray::fromBase64(picData.toAscii());
QPixmap pixmap;
pixmap.loadFromData((uchar *)pixmapData.constData(), pixmapData.size());
out.Answer.Cases.last().Pictures.resize(out.Answer.Cases.last().Pictures.size() + 1);
out.Answer.Cases.last().Pictures.last().Name = picName;
out.Answer.Cases.last().Pictures.last().Pixmap = pixmap;
}
}
}
}
} // </Case>
else if (out.AnswerType == "Manual")
{
}
}
}
}
#include <QDir>
#include <QTemporaryFile>
void CQuestion::Display( QTextBrowser *outQuestion, QGridLayout *outAnswer )
{
// Setting question
QStringList searchPath;
for (int i = 0; i < Pictures.size(); i++)
{
Pictures[i].UnpackPictures();
searchPath << Pictures[i].tmpPath;
}
outQuestion->setSearchPaths(searchPath);
outQuestion->setText(Content);
// Clearing answer
QLayoutItem *li;
while (li = outAnswer->takeAt(0))
{
if (QWidget *w = li->widget())
delete w;
else if (QLayout *l = li->layout())
delete l;
delete li;
}
// Setting answer
if (AnswerType == "Case")
{
for (int i = 0, c = 0, r = 0; i < Answer.Cases.size(); i++)
{
QHBoxLayout *layout = new QHBoxLayout(outQuestion);
layout->setSpacing(0);
QRadioButton *rBtn = new QRadioButton(outQuestion);
layout->addWidget(rBtn);
QTextBrowser *tb = new QTextBrowser(outQuestion);
tb->setText(Answer.Cases[i].Content);
tb->setMinimumHeight(30);
layout->addWidget(tb);
outAnswer->addLayout(layout, r, c);
//outAnswer->addWidget(tb, r, c);
if (i & 1)
{
r = 0;
c++;
}
else
r++;
}
}
else if (AnswerType == "Manual")
{
QTextBrowser *tb = new QTextBrowser(outQuestion);
tb->setText(Answer.Manual);
outAnswer->addWidget(tb, 0, 0);
}
}
HTMLWithPictures::CPicture::~CPicture()
{
if (!tmpName.isEmpty())
QFile::remove(tmpName);
if (!tmpPath.isEmpty())
QDir::temp().rmdir(tmpPath);
}
void HTMLWithPictures::CPicture::UnpackPictures()
{
{
QTemporaryFile file;
file.open();
tmpPath = file.fileName();
}
QDir::temp().mkdir(tmpPath);
tmpName = QString("%1/%2").arg(tmpPath).arg(Name);
Pixmap.save(tmpName);
}
«ts_examinee.h»:
#ifndef TS_EXAMINEE_H
#define TS_EXAMINEE_H
#include <QtGui/QMainWindow>
#include "ui_ts_examinee.h"
#include "../TS_Lecturer/Question.h"
#include "DBAccess.h"
class TS_Examinee : public QMainWindow
{
Q_OBJECT
public:
TS_Examinee(QWidget *parent = 0, Qt::WFlags flags = 0);
~TS_Examinee();
private:
Ui::TS_ExamineeClass ui;
/*CQuestions questions;*/
DBAccess db;
private slots:
void on_forwardPushButton_clicked();
void on_backPushButton_clicked();
};
#endif // TS_EXAMINEE_H
«ts_examinee.срр»:
#include "ts_examinee.h"
#include "DBAccess.h"
#include "LoginDialog.h"
#include <QGridLayout>
TS_Examinee::TS_Examinee(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
db.Connect("localhost", "db_TestingSystem", "postgres", "1q2w3e");
LoginDialog loginDialog;
loginDialog.exec(&db);
db.GetQuestions();
db.ShowQuestions(ui.questionTextBrowser, ui.AnswerGridLayout);
}
TS_Examinee::~TS_Examinee()
{
}
void TS_Examinee::on_backPushButton_clicked()
{
db.ShowPrevQuestion(ui.questionTextBrowser, ui.AnswerGridLayout);
}
void TS_Examinee::on_forwardPushButton_clicked()
{
db.ShowNextQuestion(ui.questionTextBrowser, ui.AnswerGridLayout);
}
«main.cpp»:
#include <QtGui/QApplication>
#include "ts_examinee.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TS_Examinee w;
w.show();
return a.exec();
}