来自 Qt 中 main.cpp 代码的 MainWindow [英] MainWindow from code from the main.cpp in Qt

查看:91
本文介绍了来自 Qt 中 main.cpp 代码的 MainWindow的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

想了解MainWindowmain.cpp 在代码上的区别.具体来说,如何将专门写在 main.cpp 中的代码块修改为 mainwindow.cppmainwindow.h 的一部分>.

Want to understand the difference in code between the MainWindow and the main.cpp. Specifically, how a chunk of code written exclusively in the main.cpp needs to be modified to be part of the mainwindow.cpp and mainwindow.h.

举个例子,我试图修改这个很好的 answer 中的代码以在 MainWindow.

As an example, I am trying to modify the code from this fine answer to work in MainWindow.

main.cpp

#include <QtWidgets>
#include <QtNetwork>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    //setup GUI (you could be doing this in the designer)
    QWidget widget;
    QFormLayout layout(&widget);
    QLineEdit lineEditName;
    QLineEdit lineEditGender;
    QLineEdit lineEditRegion;
    auto edits = {&lineEditName, &lineEditGender, &lineEditRegion};
    for(auto edit : edits) edit->setReadOnly(true);
    layout.addRow("Name:", &lineEditName);
    layout.addRow("Gender:", &lineEditGender);
    layout.addRow("Region:", &lineEditRegion);
    QPushButton button("Get Name");
    layout.addRow(&button);

    //send request to uinames API
    QNetworkAccessManager networkManager;
    QObject::connect(&networkManager, &QNetworkAccessManager::finished,
                 [&](QNetworkReply* reply){
        //this lambda is called when the reply is received
        //it can be a slot in your GUI window class
        //check for errors
        if(reply->error() != QNetworkReply::NoError){
            for(auto edit : edits) edit->setText("Error");
            networkManager.clearAccessCache();
        } else {
            //parse the reply JSON and display result in the UI
            QJsonObject jsonObject=     QJsonDocument::fromJson(reply->readAll()).object();
            QString fullName= jsonObject["name"].toString();
            fullName.append(" ");
            fullName.append(jsonObject["surname"].toString());
            lineEditName.setText(fullName);
            lineEditGender.setText(jsonObject["gender"].toString());
            lineEditRegion.setText(jsonObject["region"].toString());
        }
        button.setEnabled(true);
        reply->deleteLater();
        });
     //url parameters
    QUrlQuery query;
    query.addQueryItem("amount", "1");
    query.addQueryItem("region", "United States");
    QUrl url("http://uinames.com/api/");
    url.setQuery(query);
    QNetworkRequest networkRequest(url);
    //send GET request when the button is clicked
    QObject::connect(&button, &QPushButton::clicked, [&](){
        networkManager.get(networkRequest);
        button.setEnabled(false);
        for(auto edit : edits) edit->setText("Loading. . .");
    });

    widget.show();
    return a.exec();
}

编辑

添加了相同答案的计时器部分;请演示这个带有定时器的版本也可以这样做

added the timer part of the same answer; please demonstrate how this version with the timer can done as well

QTimer timer;
QObject::connect(&timer, &QTimer::timeout, [&](){
    networkManager.get(networkRequest);
    button.setEnabled(false);
    for(auto edit : edits) edit->setText("Loading. . .");
});
timer.start(60000); //60000 msecs = 60 secs

我努力将 networkManager 修改为类成员,如何构建代码以及如何替换 lambda 函数.

I struggle with modifying the networkManager as class members, how to structure the code and how to replace the lambda functions.

如果有人可以为我提供所有必需的修改以更好地理解,那就太好了.

If someone can provide all the required modifications for me to gain a better understanding that would be great.

推荐答案

您可能希望将用户界面和控制器(业务逻辑)分离到单独的类中.

You would want to separate out the user interface and the controller (business logic) into separate classes.

main() 的主体实例化 ui 和控制器并将它们连接起来.每 5 秒获取一次新结果的计时器.计时器也可以放入 Controller 中 - 我将它分离出来作为向现有类添加功能而不修改它的示例.

The body of main() instantiates the ui and the controller and connects them. A timer that fetches new results every 5 seconds. The timer could be rolled into the Controller, too - I show it separated out as an example of adding functionality to an existing class without modifying it.

// https://github.com/KubaO/stackoverflown/tree/master/questions/into-mainwin-39643510
#include "mainwindow.h"
#include "controller.h"

int main(int argc, char *argv[])
{
   QApplication app{argc, argv};
   MainWindow ui;
   Controller ctl;
   QTimer timer;
   timer.start(5*1000);
   QObject::connect(&timer, &QTimer::timeout, &ctl, &Controller::get);

   QObject::connect(&ctl, &Controller::busy, &ui, [&]{ ui.setState(MainWindow::Loading); });
   QObject::connect(&ui, &MainWindow::request, &ctl, &Controller::get);
   QObject::connect(&ctl, &Controller::error, &ui, [&]{ ui.setState(MainWindow::Error); });
   QObject::connect(&ctl, &Controller::values, &ui, &MainWindow::setFields);
   ui.show();
   return app.exec();
}

控制器对用户界面一无所知,只负责处理请求.每次开始处理请求时,它都会发出 busy 信号.

The controller knows nothing of the user interface, and deals with processing the requests only. It emits a busy signal every time a request starts being processed.

如果你想为多个活动的请求提供更好的反馈,busy 信号只需要在没有待处理的请求并添加一个新的请求时才需要发出,并且 idle 当最后一个请求完成并且没有更多未决请求时将发出信号.

If you wanted to provide better feedback for multiple active requests, the busy signal would need to be emitted only when there were no requests pending and a new one is added, and an idle signal would be emitted when the last request has finished and there are no more pending ones.

#ifndef CONTROLLER_H
#define CONTROLLER_H

#include <QtNetwork>

class Controller : public QObject {
   Q_OBJECT
   QNetworkAccessManager manager{this};
   QNetworkRequest request;
   Q_SLOT void onReply(QNetworkReply *);
public:
   explicit Controller(QObject * parent = nullptr);
   Q_SLOT void get();
   Q_SIGNAL void busy();
   Q_SIGNAL void error(const QString &);
   Q_SIGNAL void values(const QString & name, const QString & gender, const QString & region);
};

#endif // CONTROLLER_H

controller.cpp

#include "controller.h"

Controller::Controller(QObject *parent) : QObject(parent)
{
   QUrlQuery query;
   query.addQueryItem("amount", "1");
   query.addQueryItem("region", "United States");
   QUrl url("http://uinames.com/api/");
   url.setQuery(query);
   request = QNetworkRequest(url);
   connect(&manager, &QNetworkAccessManager::finished, this, &Controller::onReply);
}

void Controller::onReply(QNetworkReply * reply) {
   if (reply->error() != QNetworkReply::NoError) {
      emit error(reply->errorString());
      manager.clearAccessCache();
   } else {
      //parse the reply JSON and display result in the UI
      auto jsonObject = QJsonDocument::fromJson(reply->readAll()).object();
      auto fullName = jsonObject["name"].toString();
      fullName.append(" ");
      fullName.append(jsonObject["surname"].toString());
      emit values(fullName, jsonObject["gender"].toString(), jsonObject["region"].toString());
   }
   reply->deleteLater();
}

void Controller::get() {
   emit busy();
   manager.get(request);
}

用户界面对任何业务逻辑一无所知,它提供了一个足以让业务逻辑使用它的 API.它可以处于以下三种状态之一:Normal 状态,其中结果可见,Loading 状态,其中显示忙反馈,以及 Error 状态,其中显示错误信息.setFields 槽将状态返回到 Normal.

The user interface knows nothing of any business logic, it provides an API that's sufficient for the business logic to use it. It can be in one of three states: Normal state where results are visible, Loading state where a busy feedback is shown, and Error state where error information is shown. The setFields slot returns the state to Normal.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QtWidgets>

class MainWindow : public QWidget {
  Q_OBJECT
  QFormLayout layout{this};
  QLineEdit lineEditName;
  QLineEdit lineEditGender;
  QLineEdit lineEditRegion;
  QPushButton button{"Get Name"};
  QLineEdit * edits[3] = {&lineEditName, &lineEditGender, &lineEditRegion};
public:
  enum State { Normal, Loading, Error };
  explicit MainWindow(QWidget * parent = nullptr);
  Q_SLOT void setFields(const QString & name, const QString & gender, const QString & region);
  Q_SLOT void setState(State);
  Q_SIGNAL void request();
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
{
   for(auto edit : edits) edit->setReadOnly(true);
   layout.addRow("Name:", &lineEditName);
   layout.addRow("Gender:", &lineEditGender);
   layout.addRow("Region:", &lineEditRegion);
   layout.addRow(&button);
   connect(&button, &QPushButton::clicked, this, &MainWindow::request);
}

void MainWindow::setFields(const QString & name, const QString & gender, const QString & region) {
   setState(Normal);
   lineEditName.setText(name);
   lineEditGender.setText(gender);
   lineEditRegion.setText(region);
}

void MainWindow::setState(MainWindow::State state) {
   if (state == Normal) {
      for (auto edit : edits) edit->setEnabled(true);
      button.setEnabled(true);
   }
   else if (state == Loading) {
      for (auto edit : edits) edit->setEnabled(false);
      button.setEnabled(false);
   }
   else if (state == Error) {
      for (auto edit : edits) edit->setText("Error...");
      button.setEnabled(true);
   }
}

这篇关于来自 Qt 中 main.cpp 代码的 MainWindow的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆