Qt:如何将on_pushButton_clicked()函数的输入值传递给paintGL()

时间:2017-06-07 15:09:03

标签: c++ qt

我正在使用QT的抵押贷款计算器。 当用户点击按钮时,“on_pushButton_clicked()”函数将获得输入。

问题是我很困惑如何将输入从“on_pushButton_clicked()”传递到“paintGL()”函数以用于绘图目的。

我的最后一种方法是使用全局变量来解决这个问题,但我真的想避免这样的事情...所以如果有人可以用更好的方法启发,那将非常受欢迎。

我的代码如下:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "ui_mainwindow.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:

    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    template <class T>
    T inputcheck(QLineEdit *input, T output);
    //friend class GLwidget;
    double loan;
    int maturity;
    double rate1;
    double rate2;
    double rate3;
    int period2;
    int period3;    

private slots:
    void on_pushButton_Calculate_clicked();

    void on_pushButton_Quit_clicked();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QCoreApplication>
#include <QDesktopWidget>
#include "glwidget.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

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

template <class T>
T MainWindow::inputcheck(QLineEdit *input, T output) 
{
    bool ok;
    output = input->text().toDouble(&ok);
    if(TRUE && output > 0)
    {
        return output;
    }
    else
    {
        input->setText("ERR");
        return 0;
    }
}

void MainWindow::on_pushButton_Calculate_clicked()
{

    // getting inputs()
    loan = inputcheck(ui->lineEdit_loan, loan);
    maturity = inputcheck(ui->lineEdit_maturity, maturity);
    rate1 = inputcheck(ui->lineEdit_rate1, rate1);
    rate2 = inputcheck(ui->lineEdit_rate2, rate2);
    rate3 = inputcheck(ui->lineEdit_rate3, rate3);
    period2 = inputcheck(ui->lineEdit_period2, period2);
    period3 = inputcheck(ui->lineEdit_period3, period3);
    printf("loan:%f, maturity:%d,rate1:%f,rate2:%f,rate3:%f, period2:%d, period3:%d\n", loan, maturity, rate1, rate2, rate3, period2, period3);      

}

void MainWindow::on_pushButton_Quit_clicked()
{
    QCoreApplication::quit();

}

glwidget.h

#ifndef GLWIDGET_H
#define GLWIDGET_H

#include <QObject>
#include <QGLWidget>


class calculation;
class GLwidget : public QGLWidget
{
    Q_OBJECT
public:
    explicit GLwidget(QWidget *parent = 0);
    void initializeGL();
    void paintGL();
    void resizeGL(int width, int height);

private:

};

#endif // GLWIDGET_H

glwidget.cpp

#include "glwidget.h"
#include <gl/GL.h>


GLwidget::GLwidget(QWidget *parent):QGLWidget(parent)
{
}

void GLwidget::initializeGL()
{
}

void GLwidget::paintGL()
{
**// I need the inputs to be here!!**
}

void GLwidget::resizeGL(int width, int height)
{
}

感谢您的帮助:)

4 个答案:

答案 0 :(得分:0)

惯用方法是使窗口小部件成为值的显示,其中值是窗口小部件的属性。这就是所有Qt控件的工作方式,例如: QLabel可以显示一些文字,并且具有您使用text设置的setText属性。一旦用新文本调用setText,标签就会知道自己更新。因此:

class DataView : public QOpenGLWidget
{
  Q_OBJECT
  Q_PROPERTY(double principal READ principal WRITE setPrincipal)
  Q_PROPERTY(int amortizationPeriod READ amortizationPeriod WRITE setAmortizationPeriod)
  ...
  double m_principal = {};
  int m_amortizationPeriod = {};
public:
  explicit GLwidget(QWidget *parent = {}) : QOpenGLWidget(parent) {}
  void initializeGL() override;
  void paintGL() override;
  void resizeGL(int w, int h) override;
  double principal() const { return m_principal; }
  void setPrincipal(double principal) {
    if (m_principal == principal) return;
    m_principal = principal;
    update();
  }
  int amortizationPeriod() const { return m_amortizationPeriod; }
  void setAmortizationPeriod(int period) {
    if (m_amortizationPeriod == period) return;
    m_amortizationPeriod = period;
    update();
  }
  ...
};

update()安排从事件循环重绘。更新请求是合并的,因此在一行中设置多个属性只会将窗口小部件绘制一次。

因此,假设您将dataView作为Ui表单的元素:

void MainWindow::on_pushButton_Calculate_clicked()
{
    auto principal = inputcheck(ui->lineEdit_loan, loan);
    auto amortizationPeriod = inputcheck(ui->lineEdit_maturity, maturity);
    ...
    ui->dataView->setPrincipal(principal);
    ui->dataView->setAmortizationPeriod(amortizationPeriod);
    ...
}

也许您希望动态地将dataView显示为新的顶级窗口:

void MainWindow::on_pushButton_Calculate_clicked()
{
    auto principal = inputcheck(ui->lineEdit_loan, loan);
    auto amortizationPeriod = inputcheck(ui->lineEdit_maturity, maturity);
    ...
    auto dataView = new DataView(this);
    dataView->setWindowFlags(dataWidget->windowFlags() | Qt::Window);
    dataView->setPrincipal(principal);
    dataView->setAmortizationPeriod(amortizationPeriod);
    ...
    dataView->show();
}

如果您希望更容易传递数据,可以将所有属性捆绑在代表贷款的数据类型中:

struct Loan {
  double principal = {};
  int amortizationPeriod = {};
  ...
  bool operator==(const Loan & o) const {
    return 
      qFuzzyCompare(principal, o.principal)
      && amortizationPeriod == o.amortizationPeriod
      && ...;
    // use qFuzzyCompare when comparing floating point values
  }
};
Q_DECLARE_METATYPE(Loan)

class DataView : public QOpenGLWidget
{
  Q_OBJECT
  Q_PROPERTY(Loan loan READ loan WRITE setLoan)
  Loan m_loan;
public:
  explicit GLwidget(QWidget *parent = {}) : QOpenGLWidget(parent) {}
  void initializeGL() override;
  void paintGL() override;
  void resizeGL(int w, int h) override;
  const Loan & loan() const { return m_loan; }
  Loan getLoan() const { return m_loan; }
  void setLoan(const Loan & loan) {
     if (m_loan == loan) return;
     m_loan = loan;
     update();
  }
};

方便时,可以使用getLoan获取可修改的贷款副本。通常的loan getter成本很低,因为它返回对内部数据的const引用,而不是副本。

然后:

void MainWindow::on_pushButton_Calculate_clicked()
{
    Loan loan;
    loan.principal = inputcheck(ui->lineEdit_loan, loan);
    loan.amortizationPeriod = inputcheck(ui->lineEdit_maturity, maturity);
    ...
    ui->dataView->setLoan(loan);
    ...
}

如果您希望动态地将dataView显示为新的顶级窗口:

void MainWindow::on_pushButton_Calculate_clicked()
{
    Loan loan;
    loan.principal = inputcheck(ui->lineEdit_loan, loan);
    loan.amortizationPeriod = inputcheck(ui->lineEdit_maturity, maturity);
    ...
    auto dataView = new DataView(this);
    dataView->setWindowFlags(dataView->windowFlags() | Qt::Window);
    dataView->setLoan(loan);
    dataView->show();
}

您还可以将数据视图与MainWindow完全分离,并通过信号传递数据:

class MainWindow : public QMainWindow {
  ...
public:
  Q_SLOT newLoan(const Loan &);
  ...
};

void MainWindow::on_pushButton_Calculate_clicked()
{
    Loan loan;
    loan.principal = inputcheck(ui->lineEdit_loan, loan);
    loan.amortizationPeriod = inputcheck(ui->lineEdit_maturity, maturity);
    ...
    emit newLoan(loan);
}

int main(int argc, char ** argv) {
  QApplication app(argc, argv);
  MainWindow mainWindow;
  DataView dataView;
  QObject::connect(&mainWindow, &MainWindow::newLoan, [&](const Loan & loan){
    dataView.setLoan(loan);
    dataView.show();
  });
  mainWindow.show();
  return app.exec();
}

如果数据视图始终可见,您可以:

int main(int argc, char ** argv) {
  QApplication app(argc, argv);
  MainWindow mainWindow;
  DataView dataView;
  QObject::connect(&mainWindow, &MainWindow::newLoan, &dataView, &DataView::setLoan);
  mainWindow.show();
  dataView.show();
  return app.exec();
}

答案 1 :(得分:0)

移动GLwidget类中的变量。在这里我假设他们被宣布为公开,但你可能想要使用setter和getter。然后,调用update来刷新小部件。

void MainWindow::on_pushButton_Calculate_clicked()
{
    ui->myglwidgetname->loan = inputcheck<double>(ui->lineEdit_loan);
    ui->myglwidgetname->maturity = inputcheck<int>(ui->lineEdit_maturity);
    ui->myglwidgetname->rate1 = inputcheck<double>(ui->lineEdit_rate1);
    ui->myglwidgetname->rate2 = inputcheck<double>(ui->lineEdit_rate2);
    ui->myglwidgetname->rate3 = inputcheck<double>(ui->lineEdit_rate3);
    ui->myglwidgetname->period2 = inputcheck<int>(ui->lineEdit_period2);
    ui->myglwidgetname->period3 = inputcheck<int>(ui->lineEdit_period3);
    ui->myglwidgetname->update();    
}

另外,你想纠正你的模板化函数,因为它调用toDouble而不管T类型根本没有意义......

答案 2 :(得分:-1)

这可以通过使用一些常见的面向对象的想法来解决,即具有setter函数的成员变量。在QGLWidget的子类(glwidget.h)中添加一些成员变量。

private:
  int m_my_int_value;
  double m_my_double_value;

然后,您还需要为这些值设置一些setter函数(也在glwidget.h中)。

public:
  void Set_my_int_value(int val);
  void Set_my_double_value(double val);

您可以将这些函数的声明放在glwidget.cpp。

void GLwidget::Set_my_int_value(int val)
{
  if(val != m_my_int_value)
  {
    m_my_int_value = val;
    update();
  }
}

void GLwidget::Set_my_double_value(double val)
{
  if(val != m_my_double_value)
  {
    m_my_double_value = val;
    update();
  }
}

在on_click函数中调用这些setter函数。然后可以在paintGL的实现中访问这些值。

答案 3 :(得分:-1)

你可以使用qt的Signal / Slot mechanizm。

使用输入中的所需字段创建自己的结构。您可以将其作为指针传递信号。

添加到mainwindow.h

signals:
    void MySignal(MyStruct*);

在cpp:

void MainWindow::on_pushButton_Calculate_clicked(){

// getting inputs()
    loan = inputcheck(ui->lineEdit_loan, loan);
    maturity = inputcheck(ui->lineEdit_maturity, maturity);
    rate1 = inputcheck(ui->lineEdit_rate1, rate1);
    rate2 = inputcheck(ui->lineEdit_rate2, rate2);
    rate3 = inputcheck(ui->lineEdit_rate3, rate3);
    period2 = inputcheck(ui->lineEdit_period2, period2);
    period3 = inputcheck(ui->lineEdit_period3, period3);
    printf("loan:%f, maturity:%d,rate1:%f,rate2:%f,rate3:%f, period2:%d, period3:%d\n", loan, maturity, rate1, rate2, rate3, period2, period3); 
    MyStruct* struct = new MyStruct();
    ... //add data to mystruct
    emit MySignal(struct);
}

有这样的功能:     公共位置:         void saveData(MyStruct * param); //正文应保存您喜欢的数据

在main.cpp中,你可以创建两个主要的小部件,就像这样。

MainWindow mainW();
GLWidget glW();
connect(&mainW, SIGNAL( MySignal(MyStruct*)), &glW, SLOT(saveData(MyStruct*)));

边缘有点粗糙,但我希望你能得到基本的想法。如果没有,请查看Signal / Slot mechanizm上的Qt文档。