Разработка классов приложения
Классы приложения разрабатываем с учетом результатов объектной декомпозиции, обязательно предусматривая методы, обрабатывающие все получаемые объектом сообщения.
Класс Главная форма
На рисунке 5 показан вид Главной формы на экране и приведена диаграмма класса Главная форма. Согласно своему визуальному представлению класс должен включать виджеты кнопок и обеспечивать реакцию на нажатие последних.
Рисунок 5 – Диаграмма классов класса Главной формы
Согласно своему визуальному представлению класс должен включать виджеты кнопок и обеспечивать реакцию на нажатие последних, соответственно необходимы конструктор Window() и слоты:
ShowAdd () – метод Показать форму добавления записей;
ShowPrint () – метод Показать форму вывода всех записей;
ShowFind() – метод Показать форму поиска записей.
Объявление класса Главной формы поместим в заголовочный файл mainForm.h:
#ifndef mainForm_h
#define mainForm_h
#include <QtGui>
#define RUS(str) codec->toUnicode(str)
#include "addForm.h"
#include "findForm.h"
#include "printForm.h"
class Window : public QWidget
{
Q_OBJECT
QPushButton * btnAdd,* btnPrint,
* btnFind, * btnExit;
addForm winAdd; // форма Добавления
printForm winPrint; // форма Отображение всех
findForm winFind; // форма Поиска
public:
Window(); // конструктор
public slots:
void showAdd(); // показать форму Добавления
void showPrint(); // показать форму Отображения всех
void showFind(); // показать форму Поиска
};
#endif
Тогда файл mainForm.cpp должен содержать описание методов класса Windows:
|
|
#include "mainForm.h"
Window::Window()
{
QTextCodec *codec =
QTextCodec::codecForName("Windows-1251");
this->setWindowTitle(RUS("Записная книжка"));
// создаем кнопки
btnAdd = new QPushButton(RUS("Добавить"),this);
btnFind = new QPushButton(RUS("Найти"),this);
btnPrint = new QPushButton(RUS("Показать"),this);
btnExit = new QPushButton(RUS("Выход"),this);
// создаем компоновщик и передаем ему кнопки
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(btnAdd);
layout->addWidget(btnFind);
layout->addWidget(btnPrint);
layout->addWidget(btnExit);
// устанавливаем размеры окна
resize(180,150);
// связываем сигналы от нажатия кнопок со слотами
connect(btnExit, SIGNAL(clicked(bool)),
this,SLOT(close()));
connect(btnAdd,SIGNAL(clicked(bool)),
this,SLOT(showAdd()));
connect(btnFind,SIGNAL(clicked(bool)),
this,SLOT(showFind()));
connect(btnPrint, SIGNAL(clicked(bool)),
this,SLOT(showPrint()));
}
void Window::showAdd()
{ winAdd.show(); }
void Window::showFind()
{ winFind.show(); }
void Window::showPrint()
{ winPrint.showAll(); }
Класс доступа к данным
Как указано выше, класс данных должен инкапсулировать связь с файлом и все операции над хранимыми в файле данными. С учетом того набора операций с файлом, который был выявлен при объектной декомпозиции приложения, получаем диаграмму классов для этого класса, изображенную на рисунке 6.
Рисунок 6 – Диаграмма классов класса bookFile
|
|
Кроме операций над данными на диаграмме показано, что класс данных должен включать адрес объекта специального класса QFile, который предназначен в Qt для работы с текстовыми или двоичными файлами. Так класс QFile содержит методы проверки существования файла, его открытия и закрытия файла, а также методы чтения и записи блоков данных заданной длины.
Согласно заданию в файле должны храниться имена и фамилии абонентов на русском языке в кодировке Unicode, т. е. именно в том виде, в котором они были введены посредством виджетов ввода. Соответственно для представления данных в программе целесообразно использовать объекты-строки класса QString, которые также предназначены для работы с кодировкой Unicode. Для удобства обработки три объекта-строки: для хранения имени, фамилии и телефона – целесообразно собрать в структуру recType (структура на диаграмме классов показана как класс) и предусмотреть в объекте соответствующий буфер r для хранения данных в процессе поиска.
Кроме этого класс данных должен включать поля для размещения булевских ключей поиска данных, которые позволят реализовать поиск по фамилии и/или имени:
· k1 – в запросе присутствует фамилия;
· k2 – в запросе присутствует имя;
|
|
· k3 – найдена фамилия;
· k4 – найдено имя;
· ff – найдена запись.
Полностью формируем объявление класса в файле bookFile.h:
#ifndef bookFile_h
#define bookFile_h
#include <QFile>
struct recType // структура записи данных одного абонента
{ QString fam,name,nom; };
class bookFile
{
QFile * f; // указатель на объект класса QFile
bool k1,k2,k3,k4,ff; // ключи поиска
public:
recType r; // буфер ввода-вывода
bookFile(); // конструктор
~bookFile(); // деструктор
bool addRec(recType r); // добавление записи в файл
bool readRec(); // чтение записи из файда
bool findFirst(const recType r1); // поиск первой
// записи, удовлетворяющей условию
bool findNext(const recType r1);
// поиск следующей записи
};
#endif
Класс QFile библиотеки Qt обеспечивает чтение из файла и запись в файл указанного количества байтов, но при работе со сложными типами хранимых данных использование методов класса QFile требует программирования дополнительных действий по преобразованию данных в требуемый формат.
Гораздо эффективнее при выполнении операций ввода-вывода применять потоки – объекты класса QDataStream – для двоичных файлов и QTextStream – для текстовых файлов.
Поток типа QTextStream предназначен для работы с данными, хранимыми в файле в текстовом виде. При этом данные текстовых типов, таких как Char, QChar, QString, QByteArray, записываются в файл и читаются из него без изменений, а данные базовых типов языка С++, таких как short, int, long, float, double, при вводе из файла и выводе в файл преобразуются из текстового представления во внутреннее и обратно.
|
|
Поток типа QDataStream также обеспечивает выполнение операций ввода вывода с данными базовых типов С++, однако кроме этого он позволяет также вводить и выводить объекты многих классов библиотеки Qt, таких как QBrush, QColor, QDateTime, QFont, QPixmap, QString, QVariant. Формат внутреннего представления данных в файле отличен от формата двоичного файла С++. В процессе разработки классов библиотеки этот формат многократно менялся, но при этом он не требует преобразования числовых данных в текстовое представление и основан на внутреннем двоичном формате данных.
В рассматриваемом примере мы сохраняем в файле текстовые данные, соответственно применимы оба типа потоков, однако класс QDataStream обеспечивает более простой и быстрый вариант обработки, не требующий преобразований и записи маркеров конца строк, поэтому будем использовать именно его.
Ниже представлено описание методов класса, которое размещаем в файле bookFile.cpp:
#include "bookFile.h"
#include "mainForm.h"
bookFile::bookFile() // конструктор
{
QTextCodec *codec =
QTextCodec::codecForName("Windows-1251");
f=new QFile("book.txt");// создаем объект-файл
if(!f->exists()) // если файл не существует, то
{ // формирмируем сообщение
QMessageBox msg(QMessageBox::Critical,
RUS("Файл не найден"),
RUS("Файл book.txt создан"),
QMessageBox::Ok,0);
msg.exec();// выводим сообщение на экран
}
f->open(QFile::ReadWrite); // открываем файл
// для ввода-вывода
}
bookFile::~bookFile() // деструктор
{
f->close(); // закрываем файл
delete f; // освобождаем память
}
bool bookFile::addRec(recType r)
{
f->seek(f->size()); // переходим на конец файла
QDataStream out(f); // связываем с файлом поток вывода
out<<r.fam<<r.name<<r.nom;// выводим данные в файл
return true;
}
bool bookFile::readRec()
{
QDataStream in(f); // связываем с файлом поток ввода
if (in.atEnd())return false;
else
{
in>>r.fam>>r.name>>r.nom;
return true;
}
}
bool bookFile::findFirst(const recType r1)
{
k1=(r1.fam==""); // устанавливаем два ключа поиска
k2=(r1.name=="");
ff=false; // устанавливаем ключ поиска «запись не найдена»
f->reset();
bool fff = readRec();
while(fff &&(!ff))
{
k3=(r1.fam==r.fam); //строим еще два ключа поиска
k4=(r1.name==r.name);
if ((!k1 && !k2 && k3 && k4)||
(!k1 && k2 && k3)||
(k1 && !k2 && k4))
ff=true; // ключ поиска «запись найдена»
else fff=readRec();
}
return ff; // возвращаем ключ поиска
}
bool bookFile::findNext(const recType r1)
{
ff=false; // ключ поиска «запись не найдена»
bool fff = readRec();
while((!ff) && fff)
{
k3=(r1.fam==r.fam);//строим еще два ключа поиска
k4=(r1.name==r.name);
if ((!k1 && !k2 && k3 && k4)||
(!k1 && k2 && k3)||
(k1 && !k2 && k4))
ff=true; // ключ поиска «запись найдена»
else fff=readRec();
}
return ff; // возвращаем ключ поиска
}
Примечание – Сложные условия поиска составлены на основе специальной таблицы [1].
Дата добавления: 2018-04-04; просмотров: 556; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!