Разработка классов приложения



Классы приложения разрабатываем с учетом результатов объектной декомпозиции, обязательно предусматривая методы, обрабатывающие все получаемые объектом сообщения.

Класс Главная форма

На рисунке 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; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!