2017-06-07 33 views
2

QTでモーゲージ計算機を使用しています。 ユーザがプッシュボタンをクリックすると、 "on_pushButton_clicked()"関数が入力を取得します。Qt:on_pushButton_clicked()関数の入力値をpaintGL()に渡す方法

質問は、描画目的で "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) 
{ 
} 

感謝:)

+0

...かかわらず、全く意味をなさない型TのtoDoubleを呼び出しているのでAdditionaly、あなたのテンプレート機能を修正したいです。そして 'MainWindow'は' GLwidget'の存在をどのように認識していますか?最後に、より現代的なAPIであり、他のウィジェットとの相互運用性が向上しているので、 'QOpenGLWidget'を使うべきです。 –

答えて

-1

これは、セッターの機能を持つ、すなわちメンバ変数をいくつかの一般的なオブジェクト指向の考え方を用いることで解決することができます。あなたのサブクラスのQGLWidget(glwidget.h)にいくつかのメンバ変数を追加します。

private: 
    int m_my_int_value; 
    double m_my_double_value; 

また、これらの値(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関数でこれらのセッター関数を呼び出します。これらの値はpaintGLの実装でアクセス可能になります。

+1

ウィジェットの再描画をスケジュールするには、setterは 'update()'を呼び出す必要があります。また、値が変更されないときは何もしないでください。 –

+0

@Chris:私を助けてくれてありがとう。セッター機能をどこに置くべきかを明確にしてください。 – Alan

+0

setterとメンバ変数はすべてglwidget.hになければなりません。設定者がもっと複​​雑なことをする必要がある場合、glwidget.cppにそれらの定義を入れることができます – Chris

0

慣用的なアプローチは、ウィジェットを値の表示にし、その値をウィジェットのプロパティにすることです。これは、すべてのQtコントロールがどのように機能するかを示しています。 QLabelはテキストを表示でき、setTextを使用して設定したtextプロパティがあります。 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()イベントループからの再描画をスケジューリングします。更新要求は合体しているため、行内の複数のプロパティを設定すると、ウィジェットが1回のみペイントされます。したがって

、あなたは、UIフォームの要素としてdataViewを保持することを想定:

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ゲッターは、コピーではなく内部データへの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(); 
} 
+0

「おそらく、新しいトップレベルウィンドウとしてdataViewを動的に表示したいと思います」という段落が重複しています。尋ねられます。私はpersonnalyが短く、シンプルで一貫性のある答えを好む... – Tezirg

+0

@Tezirg重複する段落はありません。質問の自由な性質を考えると、質問者が望むものに応じていくつかの可能な実装を示す以外に選択肢はありませんでした。コードを見ると、段落全体で同じではないことがわかります。上記のどれにも不十分なことは、ユーザーコードの構造に関する不当な前提を作り出し、さらに別の実行可能なシナリオを見逃していないかどうかはわかりません。 –

+0

@KubaOber:あなたの助けてくれてありがとう!私は本当にいつか処理する必要があります。私は最近Qtを使い始めました。 Btw、QOpenGLWidgetのチュートリアルはありますか? – Alan

-1

qtの信号/スロット機構を使用することができます。

入力から必要なフィールドを使用して、独自の構造体を作成します。シグナルを介してポインタとして渡すことができます。

は、CPPに

signals: 
    void MySignal(MyStruct*); 

をmainwindow.hに追加: 公共スロット:

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); 
} 

はこのような機能を持っている 無効SaveDataを(体mystructの*のparam)は、 // bodyはデータを保存する必要があります。

そしておそらくmain.cppには、2つのメインウィジェットを作成する場所があります。

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

エッジの周りはやや粗いですが、基本的な考えを得ることを願っています。そうでない場合は、信号/スロット機構に関するQtの文書を参照してください。

+0

データ構造を生ポインタとして渡すことは安全に行うことができず、バグです。信号/スロット機構は、コードをデカップリングするために使用されます。信号のエミッタは、スロットや接続タイプについて何も想定できません。スロットが呼び出されるまでには、ポインタがぶら下がっているか、データが変更されている可能性があり、未定義の動作につながる可能性があります。代わりに、const参照によって 'MyStruct'を渡してください。 Qtは必要に応じてそれをコピーすることができます: 'Q_SIGNAL void newStruct(const MyStruct&);' 'struct MyStruct {...}; Q_DECLARE_METATYPE(MyStruct) 'です。 –

+0

@Hajdu:ヒントをありがとう!私はQtの初心者ですので、これらの機能に詳しくはありませんが、確かに試してみます! – Alan

0

GLwidgetクラスの変数を移動します。ここでは宣言されていると仮定しましたが、セッターやゲッターを使用することもできます。次に、更新を呼び出してウィジェットを更新します。

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();  
} 

それはあなたが `main`のコードを逃している

+0

一般に、ウィジェットのユーザは、ウィジェットの実装の詳細が漏出しているので、 'update()'を呼び出すことはAPIのバグです。例えば。 '' QLabel'に 'setText'を書いた後、そのような細部について心配する必要はありません。ウィジェットのユーザは決して 'update'を呼び出す必要はありません。基本的に、そのメソッドは保護されているはずです.QtのAPIデザインでは省略されています。代わりに、値が変更されたときに自動的に更新をスケジュールするsetterメソッドを使用します。 –

+0

@ Tezirg:確かに、私はまだ入力の種類に応じてそれを行う方法を理解しようとしています。私は最近Qtを使い始めました。それに対して何か解決策があるかどうかはわかりません。 – Alan

関連する問題