Brain Trainer Qt (Учимся считать в уме или проект выходного дня)

в 12:40, , рубрики: c++, linux, qt, Разработка под Linux

Наткнулся на посты, где очень бурно обсуждалась тема эффективного счета в уме
Один, Два
Тема заинтересовала и я начал искать программы и сервисы для тренировки

В скором времени пришло осознание, что быстрее написать свое приложение, под свои хотелки и с кнопками где мне удобно, + перспектива переноса на любимый Windows Phone

Для тех кому интересно посмотреть/покритиковать — добро пожаловать под кат
Brain Trainer Qt (Учимся считать в уме или проект выходного дня) - 1

Список классов:

  1. controller.cpp — реализует логику переключения состояния, полный MVVP наверно не совсем уместен на сигналах слотах, да на таком простом проекте, по этому просто абстрагирует от основного View
    controller.cpp

    void Controller::addButtonControl(QPushButton *pbutton, eCurrentState state) {
        buttons.push_back(qMakePair(pbutton, state));
    }
    void Controller::addResultInput(QLineEdit *pline) {
        resultlabelInput = pline;
    }
    void Controller::changeState(QPushButton *pbutton) {
        resetCheckedAllExectThis(pbutton);
        if(is_activeButton(pbutton)) {
            pbutton->setChecked(true);
            setCurrentState(getStateItem(pbutton));
        }
    }
    

  2. DarkStyle.cpp — набор css из проекта DarkStyle
  3. exercise.cpp — генерирует примеры, использует random до заданных разрядов, проверяет деление на NULL
    exercise.cpp

    Exercise::sExercise Exercise::getLastExercise() {
        return exercise;
    }
    
    Exercise::sExercise Exercise::getNewExercise(
            Controller::eCurrentState operation,
            int count_max,
            bool use_minus)
    {
        switch(operation) {
        case Controller::eCurrentState::state_statisctic:
            break;
        case Controller::eCurrentState::state_settings:
            break;
        case Controller::eCurrentState::state_substraction:
            exercise.first = random->getRandom(count_max);
            exercise.last = random->getRandom(count_max);
            if(!use_minus) {
                while(exercise.first < 0) {
                    exercise.first = random->getRandom(count_max);
                }
                while(exercise.last < 0) {
                    exercise.last = random->getRandom(count_max);
                }
            }
            exercise.result = (exercise.first - exercise.last);
            break;
        case Controller::eCurrentState::state_addtion:
            exercise.first = random->getRandom(count_max);
            exercise.last = random->getRandom(count_max);
            if(!use_minus) {
                while(exercise.first < 0) {
                    exercise.first = random->getRandom(count_max);
                }
                while(exercise.last < 0) {
                    exercise.last = random->getRandom(count_max);
                }
            }
            exercise.result = (exercise.first + exercise.last);
            break;
        case Controller::eCurrentState::state_division:
            exercise.first = random->getRandom(count_max);
            exercise.last = random->getRandom(count_max);
            while(exercise.last <= 0) {
                exercise.last = random->getRandom(count_max);
            }
            if(!use_minus) {
                while(exercise.first < 0) {
                    exercise.first = random->getRandom(count_max);
                }
            }
            exercise.result = (exercise.first / exercise.last);
            break;
        case Controller::eCurrentState::state_multiplication:
            exercise.first = random->getRandom(count_max);
            exercise.last = random->getRandom(count_max);
            if(!use_minus) {
                while(exercise.first < 0) {
                    exercise.first = random->getRandom(count_max);
                }
                while(exercise.last < 0) {
                    exercise.last = random->getRandom(count_max);
                }
            }
            exercise.result = (exercise.first * exercise.last);
            break;
        }
        return exercise;
    }
    

  4. graphclass.cpp симпатичный класс для диаграмм QCustomplot, лицензия GPL
    Код ничем не примечателен, почти целиком из примеров qcustomplot.

    graphclass.cpp

    void GraphClass::init() {
        QLinearGradient gradient(0, 0, 0, 400);
        gradient.setColorAt(0, QColor(90, 90, 90));
        graph->setBackground(QBrush(gradient));
    
        graph->addGraph(); // blue line
        graph->graph(0)->setPen(QPen(QBrush(QColor(40, 110, 255)), Qt::Dense5Pattern));
    
        QSharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime);
        timeTicker->setTimeFormat("%h:%m:%s");
        graph->xAxis->setTicker(timeTicker);
    
        graph->graph(0)->rescaleValueAxis(true, true);
        graph->xAxis->setVisible(true);
        graph->yAxis->setVisible(true);
        graph->xAxis->setTicker(timeTicker);
        graph->axisRect()->setupFullAxesBox();
        graph->yAxis->setRange(-1.2, 1.2);
        graph->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectLegend);
    
        // make left and bottom axes transfer their ranges to right and top axes:
        connect(graph->xAxis, SIGNAL(rangeChanged(QCPRange)), graph->xAxis2, SLOT(setRange(QCPRange)));
        connect(graph->yAxis, SIGNAL(rangeChanged(QCPRange)), graph->yAxis2, SLOT(setRange(QCPRange)));
    }
    void GraphClass::addNewValue(double value) {
        lastValue = value;
    }
    void GraphClass::update() {
        static QTime time(QTime::currentTime());
        // calculate two new data points:
        double key = time.elapsed()/10000.0; // time elapsed since start of demo, in seconds
        static double lastPointKey = 0;
        if (key-lastPointKey > 0.002) // at most add point every 2 ms
        {
            // add data to lines:
            graph->graph(0)->addData(key, lastValue);
            lastPointKey = key;
        }
        // make key axis range scroll with the data (at a constant range size of 8):
        graph->xAxis->setRange(key, 8, Qt::AlignRight);
        graph->replot();
    }
    

  5. settings.cpp — настройки, JSON (QJsonObject, QJsonDocument)
    settings.cpp

    bool Settings::loadJson() {
        QString val;
        QFile file;
        file.setFileName("./settings.json");
        file.open(QIODevice::ReadWrite | QIODevice::Text);
        val = file.readAll();
        file.close();
    
        if(!val.isEmpty()) {
            QJsonDocument d = QJsonDocument::fromJson(val.toUtf8());
            QJsonObject sett2 = d.object();
            QJsonValue value = sett2.value(QString("settings"));
            qDebug() << value;
            QJsonObject item = value.toObject();
    
            //-- settings
            QJsonValue subobj = item["count_digits"];
            count_digit_max = subobj.toInt();
            qDebug() << subobj.toString();
    
            subobj = item["use_minus"];
            use_minus = static_cast<bool>(subobj.toInt());
            qDebug() << subobj.toString();
    
            subobj = item["first_name"];
            first_name = subobj.toString();
            qDebug() << subobj.toString();
    
            subobj = item["last_name"];
            last_name = subobj.toString();
            qDebug() << subobj.toString();
    
            subobj = item["exercise_all_time"];
            exercise_all_time = new QTime();
            *exercise_all_time = exercise_all_time->fromString(subobj.toString(), "HH:mm:ss");
            qDebug() << exercise_all_time->toString("HH:mm:ss");
    
            subobj = item["exercise_correct"];
            exercise_correct = subobj.toInt();
            qDebug() << subobj.toString();
    
            subobj = item["exercise_wrong"];
            exercise_wrong = subobj.toInt();
            qDebug() << subobj.toString();
    
            subobj = item["use_advice"];
            use_advice = static_cast<bool>(subobj.toInt());
            qDebug() << subobj.toString();
    
            subobj = item["exercise_passed"];
            exercise_passed = subobj.toInt();
            qDebug() << subobj.toString();
    
            //-- advice
            value = sett2.value(QString("advice"));
            qDebug() << value;
            item = value.toObject();
    
            for(auto it=item.begin(); it!=item.end(); it++) {
                advice.push_back((*it).toString());
                qDebug() << (*it).toString();
            }
        }
        return !val.isEmpty();
    }
    
    void Settings::saveJson() {
        QFile file;
        file.setFileName("./settings.json");
        if(file.open(QIODevice::ReadWrite | QIODevice::Text)){
    
            QJsonObject jsonObSettings;
            QJsonObject jsonObParamSettings;
            QJsonObject jsonObParamAdvice;
    
            jsonObParamSettings["count_digits"] = count_digit_max;
            jsonObParamSettings["use_minus"] = use_minus;
            jsonObParamSettings["first_name"] = first_name;
            jsonObParamSettings["last_name"] = last_name;
            jsonObParamSettings["exercise_all_time"] = exercise_all_time->toString("HH:mm:ss");
            jsonObParamSettings["exercise_correct"] = exercise_correct;
            jsonObParamSettings["exercise_wrong"] = exercise_wrong;
            jsonObParamSettings["exercise_passed"] = exercise_passed;
            jsonObParamSettings["use_advice"] = use_advice;
            int i=0;
    
            for(auto it=advice.begin(); it!=advice.end(); it++) {
                jsonObParamAdvice[QString("advice_%1").arg(i)] = (*it);
                i++;
            }
    
            jsonObSettings["settings"] = jsonObParamSettings;
            jsonObSettings["advice"] = jsonObParamAdvice;
    
            QJsonDocument doc(jsonObSettings);
            file.write(doc.toJson());
            file.close();
        }
    }

  6. statistic.cpp — просто хранит сколько примеров решено, ошибки и т.п
  7. timer.cpp слушит для упорядочивания таймеров (1сек. для счетчика, 25сек. для советов, 15сек. для сохранения результатов в JSON (пока так, вообще нужен SqLite
    timer.cpp
     QTimer *timer_update_result = new QTimer();
        time = new QTime(0, 0, 0, 0);
        timer_one_sec = new QTimer();
        timer_get_advice = new QTimer();
    
        connect(timer_one_sec, SIGNAL(timeout()), this, SLOT(nextTimeOneSecond()));
        connect(timer_get_advice, SIGNAL(timeout()), this, SLOT(nextTimeAdviceTime()));
        connect(timer_update_result, SIGNAL(timeout()), this, SLOT(nextTimeUpdateResult()));
    
        QTimer::singleShot(100, [=] {
            nextTimeAdviceTime();
        });
    
        timer_update_result->start(15000);
        timer_one_sec->start(1000);
        timer_get_advice->start(25000);
    
    void TimerClass::nextTimeOneSecond() {
        QString time_string;
        if(is_enabled) {
            *time = (time->addSecs(1));
            time_string = time->toString("hh:mm:ss");
            emit update(time_string);
        }
    }
    void TimerClass::nextTimeUpdateResult() {
        emit updateLastResult();
    }
    void TimerClass::nextTimeAdviceTime() {
        emit updateAdvice();
    }
    

  8. view.cpp — основной класс, самый объемный
    view.cpp - конструктор

    //-- create statistic class
        statistict = new Statistic(ui->graph,
                                   ui->stat_all_time,
                                   ui->stat_exe_correct,
                                   ui->stat_exe_passed,
                                   ui->stat_exe_wrong);
    
        //--- create setttings
        settings = new Settings();
        if(settings->init()) {
            statistict->setLastStatistic(
                        settings->getLastAllTime(),
                        settings->getLastExerciseCorect(),
                        settings->getLastExerciseWrong(),
                        settings->getLastExercisePassed());
        } else {
            QMessageBox::critical(this, "Error JSON", "Error opening JSON file!", QMessageBox::Ok);
        }
    
        //-- create controller
        controller = new Controller();
    
        //--- create exercise
        exercise = new Exercise();
    
        //-- create reverse timerClass and connect slot
        timer = new TimerClass();
    
        connect(timer, SIGNAL(update(QString)), this, SLOT(updateTime(QString)));
        connect(timer, SIGNAL(updateAdvice()), this, SLOT(updateAdvice()));
        connect(timer, SIGNAL(updateLastResult()), this, SLOT(updateLastResult()));
    
        //-- Set StyleSheet
        QFile styleF;
        styleF.setFileName("./darkstyle/darkstyle.qss");
        styleF.open(QFile::ReadOnly);
        QString qssStr = styleF.readAll();
        qApp->setStyleSheet(qssStr);
    
        //--- insert control buttons
        controller->addButtonControl(ui->addition_button, Controller::state_addtion);
        controller->addButtonControl(ui->division_button, Controller::state_division);
        controller->addButtonControl(ui->multiplication_button, Controller::state_multiplication);
        controller->addButtonControl(ui->settings_button, Controller::state_settings);
        controller->addButtonControl(ui->statistic_button, Controller::state_statisctic);
        controller->addButtonControl(ui->substraction_button, Controller::state_substraction);
        controller->addResultInput(ui->result_input);
    
        ui->settings_count_digits->setCurrentIndex(settings->getCountDigiMax()-1);
        ui->settings_use_minus->setCurrentIndex(settings->getUseMinus());
        ui->settings_first_name->setText(settings->getFirstName());
        ui->settings_last_name->setText(settings->getLastName());
        ui->settings_use_advice->setCurrentIndex(settings->getUseAdvice());
    
        //-- Connect signal-slots
        connect(ui->result_input, SIGNAL(returnPressed()), this, SLOT(resultInputEditFinished()));
        connect(controller, SIGNAL(changeStateAddition()), this, SLOT(updateStateAddition()));
        connect(controller, SIGNAL(changeStateMultiplication()), this, SLOT(updateStateMultiplication()));
        connect(controller, SIGNAL(changeStateSettings()), this, SLOT(updateStateSettings()));
        connect(controller, SIGNAL(changeStateStatistic()), this, SLOT(updateStateStatistic()));
        connect(controller, SIGNAL(changeStateSubstraction()), this, SLOT(updateStateSubstraction()));
        connect(controller, SIGNAL(changeStateDivision()), this, SLOT(updateStateDivision()));
        connect(ui->settings_count_digits, SIGNAL(currentIndexChanged(int)), this, SLOT(updateCountDigits(int)));
        connect(ui->settings_use_minus, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUseMinus(int)));
        connect(ui->settings_use_advice, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUseAdvice(int)));
        connectSlots();
    

Brain Trainer Qt (Учимся считать в уме или проект выходного дня) - 2

Ссылка на gitHub

Автор: Владимир

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js