Ruslan Polupan
Ruslan Polupan07 серпня 2019 р. 10:41

Проект iMpos. Частина 010. Отримання найменувань палива

Список АЗС, з якими будемо робити подальші дії, ми отримали.
Створюємо слот викликаний при натисканні на CheckBox на GroupBox Дії.

void FuelNameDialog::on_groupBoxActions_clicked(bool checked)
{
    if(checked){
        //Очищаем список терминалов передаваемых для дальнейшей обработки
        listTerminals.clear();
        //Добавляем отмеченные терминалы в список
        int rowCount = ui->tableWidgetTerm->rowCount();
        for(int i=0; i<rowCount; ++i){
            QWidget *item = ui->tableWidgetTerm->cellWidget(i,0);
            QCheckBox *checkBox = qobject_cast<QCheckBox*>(item->layout()->itemAt(0)->widget());
            if(checkBox->isChecked()){
               listTerminals.append(ui->tableWidgetTerm->item(i,1)->data(Qt::DisplayRole).toInt());
            }
        }
        //Проверяем что список не пустой
        if(listTerminals.size()==0){
            QMessageBox::warning(this, "Ошибка ввода","Нет выбранных терминалов");
            ui->groupBoxActions->setChecked(false);
            return;
        }
    }
    ui->groupBoxFuel->setEnabled(!checked);
}

За промовчанням на вкладці Перегляд вибрано опцію Показати звіт.
Призначаємо слоти для обробки сигналів від buttonBoxView:

void FuelNameDialog::on_buttonBoxView_rejected()
{
    ui->groupBoxFuel->setEnabled(true);
    ui->groupBoxActions->setChecked(false);
}

void FuelNameDialog::on_buttonBoxView_accepted()
{
    //Диалог для отображения результатов и прогресса получения данных с АЗС
    ViewFuelNameDialog *viewFnDlg = new ViewFuelNameDialog(&listTerminals,this);
    viewFnDlg->exec();
}

Загальний алгоритм отримання даних про найменування видів палива:
- Отримуємо параметри підключення до бази даних АЗС;
- використовуючи потоки отримуємо інформацію про підключення з відображення поточного прогресу з кожної АЗС;
- надаємо користувачеві результат у вигляді таблиці.

Для зберігання інформації про найменування створимо тип даних FuelName, який дозволить зберігати та отримувати інформацію та містить такі поля:
- Номер резервуару;
- Код виду палива;
- коротке найменування палива;
- повне найменування палива, що відображається у фіскальному чеку.

Створюємо клас FuelName. У заголовний файл додаємо властивості:

    int m_tankID;             //    номер резервуара;
    int m_fuelID;             //    код вида топлива;
    QString m_shortName;      //    краткое наименование топлива;
    QString m_name;           //    полное наименование топлива которое отображается в фискальном чеке.

Qt Creator дозволяє швидко створити метод установки отримання значення властивості. Для цього викликаємо контекстне меню на ім'я властивості, вибираємо Рефакторинг Створити методи отримання та встановлення значення. Повторюємо дії всім властивостей нашого класу.

В результаті отримуємо наступне:

назва палива.h

#ifndef FUELNAME_H
#define FUELNAME_H
#include <QString>

class FuelName
{
public:
    FuelName();
    int tankID() const;
    void setTankID(int tankID);

    int fuelID() const;
    void setFuelID(int fuelID);

    QString shortName() const;
    void setShortName(const QString &shortName);

    QString name() const;
    void setName(const QString &name);

private:
    int m_tankID;             //    номер резервуара;
    int m_fuelID;             //    код вида топлива;
    QString m_shortName;      //    краткое наименование топлива;
    QString m_name;           //    полное наименование топлива которое отображается в фискальном чеке.   
};

#endif // FUELNAME_H

fuelname.cpp

#include "fuelname.h"

FuelName::FuelName()
{

}

int FuelName::tankID() const
{
    return m_tankID;
}

void FuelName::setTankID(int tankID)
{
    m_tankID = tankID;
}

int FuelName::fuelID() const
{
    return m_fuelID;
}

void FuelName::setFuelID(int fuelID)
{
    m_fuelID = fuelID;
}

QString FuelName::shortName() const
{
    return m_shortName;
}

void FuelName::setShortName(const QString &shortName)
{
    m_shortName = shortName;
}

QString FuelName::name() const
{
    return m_name;
}

void FuelName::setName(const QString &name)
{
    m_name = name;
}

Для зберігання інформації про всі види палива на АЗС створимо ще один клас AzsFuelName:
azsfuelname.h

#ifndef AZSFUELNAME_H
#define AZSFUELNAME_H
#include "fuelname.h"
#include <QList>
#include <QString>

class AzsFuelName
{
public:
    AzsFuelName();
    QList<FuelName> listFuels() const;
    void insertFuelName(int tankID, int fuelID,  QString shortName, QString name); //Добавления наименования топлива
    int terminalID() const;
    void setTerminalID(int terminalID);
private:
    int m_terminalID;           //Номер терминала 
    QList<FuelName> m_listFuels;//Список наименований топлива
};

#endif // AZSFUELNAME_H

azsfuelname.cpp

#include "azsfuelname.h"

AzsFuelName::AzsFuelName()
{

}

QList<FuelName> AzsFuelName::listFuels() const
{
    return m_listFuels;
}

void AzsFuelName::insertFuelName(int tankID, int fuelID, QString shortName, QString name)
{
    FuelName fn;
    fn.setTankID(tankID);
    fn.setFuelID(fuelID);
    fn.setShortName(shortName);
    fn.setName(name);
    m_listFuels.append(fn);
}

int AzsFuelName::terminalID() const
{
    return m_terminalID;
}

void AzsFuelName::setTerminalID(int terminalID)
{
    m_terminalID = terminalID;
}

Створимо заголовний файл, в якому визначимо структуру для зберігання поточного статусу виконання запиту в потоці та перерахування поточних статусів виконання запитів.
statusthread.h

#ifndef STATUSTHREAD_H
#define STATUSTHREAD_H
#include <QObject>

struct statusThread             //Структура для хранения текущего статуса 
{
    int terminalId;             //Номер терминала
    int currentStatus;          //Текущий статус операции получения наименования
};

enum statusList {               //Список статусов
    CONNECT_TO_DATABASE,        //Соединение с базой данных
    SELECT_FUEL_NAME,           //Выполнение запроса
    ERROR_OPEN_DATABASE,        //Ошибка отрытия базы данных
    ERROR_GET_FUEL_NAME,        //Ошибка выполнения запроса
    FINISHED                    //Удачное завершение запроса
};

//Разрешаем использовать данный тип данных во взаимодействии сигнал-слот
Q_DECLARE_METATYPE(statusThread);

#endif // STATUSTHREAD_H

Для реалізації отримання інформації в потоці створимо клас, в якому буде здійснюватися отримання списку найменувань палива GetFuelNameClass.

getfuelnameclass.h

#ifndef GETFUELNAMECLASS_H
#define GETFUELNAMECLASS_H
#include "statusthread.h"
#include "azsfuelname.h"
#include <QObject>
#include <QSqlQuery>
#include <QSqlError>


class GetFuelNameClass : public QObject
{
    Q_OBJECT
public:
    explicit GetFuelNameClass(QStringList connList, QObject *parent = nullptr);

signals:
    void finisList();                           //Получение наименований завершено
    void signalSendStatus(statusThread);        //Текущий статус получеия наименований
    void signalSendAzsFuelName(AzsFuelName);    //Отправка наименований видов топлива в основной поток
public slots:
    void getFuelList();                         //Получение наименований топлива
private:
    QStringList m_connList;                     //Параменты подключения к базе данный АЗС
    statusThread currentStatus;                 //Текущий статус выполнения
};

#endif // GETFUELNAMECLASS_H

getfuelnameclass.cpp

#include "getfuelnameclass.h"
#include "LoggingCategories/loggingcategories.h"

GetFuelNameClass::GetFuelNameClass(QStringList connList, QObject *parent) : 
    QObject(parent),
    m_connList(connList)
{
    typedef statusThread st;
    qRegisterMetaType<st>("st");
}

void GetFuelNameClass::getFuelList()
{
    //Устанавливаем текущий статус выполнения
    currentStatus.terminalId=m_connList[0].toInt();
    currentStatus.currentStatus=CONNECT_TO_DATABASE;
    emit signalSendStatus(currentStatus);

    //Cоздаем подключение к базе данных АЗС
    QSqlDatabase db = QSqlDatabase::addDatabase("QIBASE", m_connList[0]);

    db.setHostName(m_connList[1]);
    db.setDatabaseName(m_connList[2]);
    db.setUserName("SYSDBA");
    db.setPassword(m_connList[3]);

    //Подключаемся к базе данных АЗС
    if(!db.open()){
        //Не удалось подключится
        qCritical(logCritical()) << Q_FUNC_INFO << "Невозможно подключится к базе данных АСЗ" << m_connList[0] << db.lastError().text();
        //Меняем статус выполнения
        currentStatus.currentStatus=ERROR_OPEN_DATABASE;
        //Отправляем статус главному потоку
        emit signalSendStatus(currentStatus);
        //Завершаем выполнение по данной АЗС
        emit finisGetList();
        return;
    }
    //Меняем статус выполнения и отправляем его в главный поток
    currentStatus.currentStatus=SELECT_FUEL_NAME;
    emit signalSendStatus(currentStatus);

    //Создаем и подготавливаем запрос
    QSqlQuery q = QSqlQuery(db);
    q.prepare("select t.TANK_ID, f.FUEL_ID, f.SHORTNAME, f.NAME from FUELS f "
              "LEFT JOIN tanks t ON t.FUEL_ID = f.FUEL_ID "
              "where f.ISACTIVE='T' "
              "order by t.TANK_ID");
    //выполняем запрос
    if(!q.exec()) {
        //Запрос выполнить не удалось
        qCritical(logCritical()) << Q_FUNC_INFO << "Не возможно получить список видов топлива с АЗС." << m_connList[0] << q.lastError().text();
        //Меняем статус выполнения и отправляем его в главный поток
        currentStatus.currentStatus=ERROR_GET_FUEL_NAME;
        emit signalSendStatus(currentStatus);
        emit finisGetList();
        return;
    }
    AzsFuelName _fuelName;
    _fuelName.setTerminalID(m_connList[0].toInt());
    while(q.next()){
        _fuelName.insertFuelName(q.value(0).toInt(),q.value(1).toInt(),q.value(2).toString(),q.value(3).toString());
    }
    currentStatus.currentStatus=FINISHED;
    emit signalSendAzsFuelName(_fuelName);
    emit signalSendStatus(currentStatus);
    emit finisGetList();
}

Реалізація діалогу відображення процесу одержання найменувань видів палива
viewfuelnamedialog.h

#ifndef VIEWFUELNAMEDIALOG_H
#define VIEWFUELNAMEDIALOG_H
#include "statusthread.h"
#include "azsfuelname.h"
#include <QDialog>
#include <QSqlQuery>
#include <QSqlError>

namespace Ui {
class ViewFuelNameDialog;
}

class ViewFuelNameDialog : public QDialog
{
    Q_OBJECT

public:
    explicit ViewFuelNameDialog(QList<int> *listTerm, QWidget *parent = nullptr);
    ~ViewFuelNameDialog();

private slots:

public slots:
    void slotGetStatusThread(statusThread status);      //Обработка статуса выполнения запроса
    void slotGetAzsFuelName(AzsFuelName azsFuelname);   //Получение списка наименований по терминалу
private:
    void createUI();
    void getConnectionsList();                 //Получения дагнных о подключении к базам данных АЗС
    void fuelNameList();                       //Наименования видов топлива

private:
    Ui::ViewFuelNameDialog *ui;
    QList<int> *m_terminalSList;              //Список терминалов с которыми будем работать
    QList<QStringList> m_connectionsList;     //Cписок данных для подключения к базе данных АЗС
    QList<AzsFuelName> m_listFuelName;        //Список наименований топлива
    QStringList statusText;                   //Список описанияй статуса подключений
};

#endif // VIEWFUELNAMEDIALOG_H

viewfuelnamedialog.cpp

#include "viewfuelnamedialog.h"
#include "ui_viewfuelnamedialog.h"
#include "passconv.h"
#include "getfuelnameclass.h"
#include "LoggingCategories/loggingcategories.h"
#include <QThread>

ViewFuelNameDialog::ViewFuelNameDialog(QList<int> *listTerm, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::ViewFuelNameDialog),
    m_terminalSList(listTerm)
{
    ui->setupUi(this);

    //Описания статосов выполнения запроса
    statusText.insert(CONNECT_TO_DATABASE,"Подключение к базе данных АЗС...");
    statusText.insert(SELECT_FUEL_NAME,"Получение списка видов топлива....");
    statusText.insert(ERROR_OPEN_DATABASE,"Ошибка открытия базы данных АЗС!");
    statusText.insert(ERROR_GET_FUEL_NAME, "Ошибка получения списка наименований топлива!");
    statusText.insert(FINISHED,"Готово!");

    createUI();
    getConnectionsList();
    fuelNameList();
}

ViewFuelNameDialog::~ViewFuelNameDialog()
{
    delete ui;
}

void ViewFuelNameDialog::createUI()
{
    ui->tableWidget->setColumnCount(2);
    ui->tableWidget->verticalHeader()->hide();
    ui->tableWidget->setHorizontalHeaderLabels(QStringList() << "АЗС" << "Статус");
    ui->tableWidget->horizontalHeader()->setStretchLastSection(true);
    ui->tableWidget->verticalHeader()->setDefaultSectionSize(36);
}
//Получение параметров подключения к базам данных азс
void ViewFuelNameDialog::getConnectionsList()
{
    QSqlQuery q;
    QString strIN="";
    for(int i=0;i<m_terminalSList->size();++i){
        strIN += QString::number(m_terminalSList->at(i))+",";
    }
    strIN.resize(strIN.size()-1);
    QString strSQL = QString("select c.TERMINAL_ID, c.SERVER_NAME, c.DB_NAME, c.CON_PASSWORD from CONNECTIONS c "
                             "where c.TERMINAL_ID IN(%1) and c.CONNECT_ID=2").arg(strIN);
    QStringList list;
    if(!q.exec(strSQL)) qCritical(logCritical()) << "Не удалось получить список терминалов" << q.lastError().text();
    while(q.next()){
        list.clear();
        list << q.value(0).toString() << q.value(1).toString() << q.value(2).toString()  << passConv(q.value(3).toString());
        m_connectionsList.append(list);
    }
}

void ViewFuelNameDialog::fuelNameList()
{
    //Количетсво обрабатываемх АЗС
    int _azsCount = m_connectionsList.size();
    ui->progressBarGetFuel->setRange(0, _azsCount);
    ui->progressBarGetFuel->setValue(0);
    ui->progressBarGetFuel->setFormat("Обработано %v из %m");


    for(int i=0; i<_azsCount; i++){
        //Создаем объект класса получения наиметований и потока
        GetFuelNameClass *getFuel = new GetFuelNameClass(m_connectionsList.at(i));
        QThread *thread = new QThread();
        //помещаем класс в поток.
        getFuel->moveToThread(thread);
        //Связываем сигналы и слоты
        connect(thread,&QThread::started, getFuel, &GetFuelNameClass::getFuelList);
        connect(getFuel,&GetFuelNameClass::signalSendStatus,this,&ViewFuelNameDialog::slotGetStatusThread,Qt::UniqueConnection);
        connect(getFuel,&GetFuelNameClass::signalSendAzsFuelName,this,&ViewFuelNameDialog::slotGetAzsFuelName,Qt::DirectConnection);
        connect(getFuel, &GetFuelNameClass::finisGetList, getFuel, &GetFuelNameClass::deleteLater);
        connect(getFuel, &GetFuelNameClass::finisGetList, thread, &QThread::quit);
        connect(thread, &QThread::finished, thread, &QThread::deleteLater);
        thread->start();
    }
}

void ViewFuelNameDialog::slotGetStatusThread(statusThread status)
{
    if(status.currentStatus == CONNECT_TO_DATABASE){
        //Статус соединения с базой
        //Добавляем строки в TableWidget
        int row = ui->tableWidget->rowCount();
        ui->tableWidget->insertRow(row);
        ui->tableWidget->setItem(row,0, new QTableWidgetItem(QString::number(status.terminalId)));
        ui->tableWidget->setItem(row,1, new QTableWidgetItem(statusText[status.currentStatus]));
        ui->tableWidget->item(row,0)->setIcon(QIcon(":/Image/azs.png"));
        ui->tableWidget->item(row,1)->setIcon(QIcon(":/Image/database.png"));
        ui->tableWidget->item(row,1)->setBackground(QBrush("#F4FA58"));
        ui->tableWidget->sortByColumn(0,Qt::AscendingOrder);
        return;
    }

    int rowCount = ui->tableWidget->rowCount();
    for (int i=0;i<rowCount;++i) {
        //Находим строку в TableWidget и изменяем ее в соответсвии со статусом
        if(ui->tableWidget->item(i,0)->text().toInt() == status.terminalId){
            ui->tableWidget->item(i,1)->setText(statusText[status.currentStatus]);
            switch (status.currentStatus) {
            case SELECT_FUEL_NAME:
                 ui->tableWidget->item(i,1)->setBackground(QBrush("#D7DF01"));
                 ui->tableWidget->item(i,1)->setIcon(QIcon(":/Image/selectfuel.png"));
                break;
            case ERROR_OPEN_DATABASE:
                ui->tableWidget->item(i,1)->setBackground(QBrush("#FE2E2E"));
                ui->tableWidget->item(i,1)->setIcon(QIcon(":/Image/error.png"));
                ui->progressBarGetFuel->setValue(ui->progressBarGetFuel->value()+1);
               break;
            case ERROR_GET_FUEL_NAME:
                ui->tableWidget->item(i,1)->setBackground(QBrush("#DF01A5"));
                ui->tableWidget->item(i,1)->setIcon(QIcon(":/Image/error.png"));
                ui->progressBarGetFuel->setValue(ui->progressBarGetFuel->value()+1);
               break;
            case FINISHED:
                ui->tableWidget->item(i,1)->setBackground(QBrush("#BFFF00"));
                ui->tableWidget->item(i,1)->setIcon(QIcon(":/Image/Accept.png"));
                ui->progressBarGetFuel->setValue(ui->progressBarGetFuel->value()+1);
               break;
            default:
                break;
            }
            break;
        }
    }
}

void ViewFuelNameDialog::slotGetAzsFuelName(AzsFuelName azsFuelname)
{
    //Добавляем полученный список наименований
    m_listFuelName.append(azsFuelname);
}

В результаті отримуємо наступне

Після завершення опитування всіх АЗС відображається статус опитування.

Такий спосіб реалізації взаємодії потоків та основним потоком мені здався наочним. Якщо у когось є зауваження та пропозиції щодо реалізації з великою подякою вислухаю їх.

Архів проекту:

iMposCh010.zip iMposCh010.zip

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:50бали,
  • Рейтинг балів-4
m
  • molni99
  • 26 жовтня 2024 р. 01:37

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80бали,
  • Рейтинг балів4
m
  • molni99
  • 26 жовтня 2024 р. 01:29

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:20бали,
  • Рейтинг балів-10
Останні коментарі
i
innorwall14 листопада 2024 р. 19:03
Qt/C++ - Урок 060. Налаштування зовнішнього вигляду програми під час виконання I didnt have an issue work colors priligy dapoxetine 60mg revia cost uk August 3, 2022 Reply
i
innorwall14 листопада 2024 р. 11:42
Як скопіювати файли в Linux If only females relatives with DZ offspring were considered these percentages were 23 order priligy online uk
i
innorwall14 листопада 2024 р. 09:09
Qt/C++ - Підручник 068. Hello World за допомогою системи збирання CMAKE в CLion ditropan pristiq dosing With the Yankees leading, 4 3, Rivera jogged in from the bullpen to a standing ovation as he prepared for his final appearance in Chicago buy priligy pakistan
i
innorwall14 листопада 2024 р. 04:05
EVILEG-CORE. Використання Google reCAPTCHA 2001; 98 29 34 priligy buy
Тепер обговоріть на форумі
i
innorwall14 листопада 2024 р. 03:39
добавить qlineseries в функции priligy amazon canada 93 GREB1 protein GREB1 AB011147 6
i
innorwall11 листопада 2024 р. 10:55
Всё ещё разбираюсь с кешем. priligy walgreens levitra dulcolax carbs The third ring was found to be made up of ultra relativistic electrons, which are also present in both the outer and inner rings
9
9Anonim25 жовтня 2024 р. 09:10
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…
ИМ
Игорь Максимов03 жовтня 2024 р. 04:05
Реализация навигации по разделам Спасибо Евгений!

Слідкуйте за нами в соціальних мережах