Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to pass the values from the GUI to the main.cpp to execute a calculation?



  • Hi everyone,
    I´m kind of confused on how to pass the arguments that i choose on spinboxes and radio buttons on the GUI to perform a calculation that is described on a function in main.cpp.
    I´ve seen many methods, signal/slot, qml, thread, commandparse, and I really don´t know what to use.
    Explaining:
    1-With the help of some people, i did the code for the ricker function, see: https://forum.qt.io/topic/91344/problem-adapting-a-c-code-to-qt

    2-Then I added a way to plot it using qwt, but it was done without a widget;
    3-also i did in another project a GUI where one can choose many parameters, being some of them the inputs for the ricker function. After a CommandLinkButton is clicked the values chosen are written to a txt file and saved.
    4-I copied the ricker function and plotting code to the main.cpp of the GUI interface, and I´m trying to pass the values chosen on the GUI as the arguments to the function, but the plotting can only open after the
    commandlinkbutton is clicked. But i´m struggling to do that.

    If I put the arguments on the code, everything works, so I know it is ok.
    Can anyone show me a way of doing it, I mean pass the arguments from the GUI t the ricker function, and plot only after the commandlinkbutton is clicked? The arguments I want to pass are: wavelet_freq=f, sampling_rate=dt and polarity.
    Thanks in advance.

    my header is:
    #ifndef INTERFACE2_H
    #define INTERFACE2_H
    #include <QtGui>
    #include <QWidget>

    namespace Ui {
    class interface2;
    }

    class interface2 : public QWidget
    {
    Q_OBJECT

    public:
    explicit interface2(QWidget *parent = 0);
    ~interface2();

    int number_traces;
    int trace_samples;
    double sampling_rate;
    int polarity;
    double wavelet_freq;
    bool noise;
    bool standard_reflec;
    
    double f;
    double dt1;
    double dt=dt1/1000;
    

    private:
    Ui::interface2 *ui;

    private slots:
    void on_RUN_clicked();

    };

    #endif // INTERFACE2_H

    MY interface.cpp is:

    #include "interface2.h"
    #include "ui_interface2.h"
    #include <QtCore/QString>
    #include <QtCore/QFile>
    #include <QtCore/QTextStream>
    #include <QMessageBox>

    interface2::interface2(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::interface2)

    {

    ui->setupUi(this);
    on_RUN_clicked();
    connect(ui->RUN, SIGNAL (clicked(bool)), QApplication::instance(), SLOT (quit(bool)));
    

    }

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

    void interface2::on_RUN_clicked()
    {

    number_traces = ui->traces->value();
    trace_samples = ui->samples->value();
    sampling_rate = ui->rate->value();
    dt1=ui->rate->value();
    wavelet_freq = ui->freq->value();
    f=ui->freq->value();
    
    {
        if(ui->reflectivity->isChecked())/*refletividade padrao*/
        {
         standard_reflec= 1;
        }
        else
        {
         standard_reflec= 0;
        }
    }
    
    {
        if(ui->Noise->isChecked())/*introduzir ruido*/
        {
          noise= 1;
        }
        else
        {
         noise= 0;
        }
    }
    
    {
        if(ui->negative->isChecked())/*polaridade negativa*/
        {
          polarity=-1;
        }
    
    }
    
    {
        if(ui->positive->isChecked())/*polaridade positiva*/
        {
          polarity=1;
        }
    }
    

    {

    QString outputFilename = "sismica1.ini";
    QFile outputFile(outputFilename);
    outputFile.open(QIODevice::WriteOnly|QIODevice::Text);
    
    /* Check it opened OK */
    if(!outputFile.isOpen())
    {
        QMessageBox::warning(this,tr("Sismica"),tr("- Error, unable to open sismica1.ini for output"));
    
    }
    
    /* Point a QTextStream object at the file */
    QTextStream outStream(&outputFile);
    
    /* Write the line to the file */
    outStream << "////////////////////////////////////////////////////////////////////////////////////"<<endl
              << "Impedancia.txt"<<"\n"
              << number_traces<<"\n"
              << trace_samples<<"\n"
              << sampling_rate/1000<<"\n"
              << wavelet_freq<<"\n"
              << polarity<<"\n"
              << noise<<"\n"
              << standard_reflec<<"\n";
    
    /* Close the file */
    outputFile.close();
    }
    emit polarity;
    

    }

    my main.cpp is:

    #include "interface2.h"
    #include <QApplication>
    #include <qapplication.h>
    #include <qwt_plot.h>
    #include <qwt_plot_curve.h>
    #include <qwt_plot_grid.h>
    #include <qwt_symbol.h>
    #include <qwt_legend.h>
    #include <cmath>

    const double pi = 3.14159265358979323846;
    double dt=0.008;
    int polarity=-1;

    QVector<QPointF> ricker(double f, double dt=0.008, double length = 60.0)
    {
    size_t N = (length - dt/2.0)/dt;
    QVector<QPointF> w(N);
    for (size_t i = 0; i < N; ++i)
    {
    double t = -length/2 + idt;
    w[i].setX(t);
    w[i].setY(polarity
    ((1.0 - 2pipifftt) * exp(-pipifft*t)));
    }
    return w;
    }

    int main(int argc, char *argv[])
    {

    QApplication a(argc, argv);
    interface2 w;
    w.show();
    
    QwtPlot plot;
    plot.setTitle( "Ricker Wavelet" );
    plot.setCanvasBackground( Qt::white );
    plot.setAxisScale( QwtPlot::xBottom, -0.25, 0.25 );
    plot.setAxisScale( QwtPlot::yLeft, -1.0, 1.0 );
    plot.insertLegend( new QwtLegend() );
    
    QwtPlotGrid *grid = new QwtPlotGrid();
    grid->attach( &plot );
    
    QwtPlotCurve *curve = new QwtPlotCurve();
    curve->setTitle( "Wavelet" );
    curve->setPen( Qt::blue, 4 ),
    curve->setRenderHint( QwtPlotItem::RenderAntialiased, true );
    
    curve->setSamples(ricker(10));
    curve->attach( &plot );
    plot.resize(800, 600);
    plot.show();
    
    return a.exec();
    

    }


  • Lifetime Qt Champion

    Hi,

    Why not integrate the Qwt stuff in your main widget ? That would likely simplify your code.



  • @SGaist Good idea, I believe it will solve two issues, how to pass the argument f to the ricker I think and plotting when clicking on the button. Still need to figure out how to pass the arguments to the Qvector that will be on the main.cpp, I´ll try it when I get home.
    Thanks.



  • @SGaist I tried waht u said, although it solves the problem of passing the arguments, it doesn´t work. it says:
    : error: no matching function for call to 'QVector<QPointF>::QVector(double&, double&, double&)'
    QVector<QPointF> ricker(f=10, dt=0.008, length = 60.0)

    Doesn´t matter where i put the vector inside the code. ^


  • Qt Champions 2019

    @Flavio-Mesquita said in How to pass the values from the GUI to the main.cpp to execute a calculation?:

    QVector<QPointF> ricker(f=10, dt=0.008, length = 60.0)

    This code is invalid.
    Should be

    QVector<QPointF> ricker;
    ricker.append(QPointF(x, y));
    

    See http://doc.qt.io/qt-5/qpointf.html and http://doc.qt.io/qt-5/qvector.html
    There is no QPointF constructor taking 3 arguments also it does not know anything about f, dt or length, so I'm not sure what you're trying to achieve.



  • @jsulm Thanks for pointing, I was trying to set the arguments in order to make the function run. The f argument has to be passed at : curve->setSamples(ricker(f));. At the example below i chose f=10. Anyway, I dont get why when I make a Qt console application it works fine. If u have qwt in ur computer, u can simply copy and paste it this file and run, it will work.
    I know that in order to put it in a project with a GUI, where the arguments f, dt and polarity have to be passed from the GUI to the function I need to do something else, maybe SIGNAL/SLOT I just dont know how and where to put it.

    I put the code like that:

    #include <qapplication.h>
    #include <qwt_plot.h>
    #include <qwt_plot_curve.h>
    #include <qwt_plot_grid.h>
    #include <qwt_symbol.h>
    #include <qwt_legend.h>
    #include <cmath>

    const double pi = 3.14159265358979323846;
    int polarity=-1;

    QVector<QPointF> ricker(double f, double dt = 0.001,double length = 60.0 )
    {
    size_t N = (length - dt/2.0)/dt;
    QVector<QPointF> w(N);
    for (size_t i = 0; i < N; ++i)
    {
    double t = -length/2 + idt;
    w[i].setX(t);
    w[i].setY(polarity
    ((1.0 - 2pipifftt) * exp(-pipifft*t)));
    }
    return w;
    }

    int main( int argc, char **argv )
    {
    QApplication a( argc, argv );

    QwtPlot plot;
    plot.setTitle( "Ricker Wavelet" );
    plot.setCanvasBackground( Qt::white );
    plot.setAxisScale( QwtPlot::xBottom, -0.25, 0.25 );
    plot.setAxisScale( QwtPlot::yLeft, -1.0, 1.0 );
    plot.insertLegend( new QwtLegend() );
    
    QwtPlotGrid *grid = new QwtPlotGrid();
    grid->attach( &plot );
    
    QwtPlotCurve *curve = new QwtPlotCurve();
    curve->setTitle( "Wavelet" );
    curve->setPen( Qt::blue, 4 ),
    curve->setRenderHint( QwtPlotItem::RenderAntialiased, true );
    
    curve->setSamples(ricker(10));
    curve->attach( &plot );
    plot.resize(800, 600);
    plot.show();
    return a.exec();
    

    }



  • Hi,

    You need a qobject child with slots to attach your signals to.

    I see you are generating everything programatically which is fine but in main you have nothing to connect your signal to.

    Take your code and put it in a constructor for some class inheriting QObject. (you will need to make your ptrs into class data otherwise you will lose your pointers after the constructor.).

    After you have that in a QObject you can create the slots that you need to connect the signals from your different ui components.

    Also I suggest taking a step back... It looks like you started with console application, and are now using some UI stuff. I would start with with widget application and build your UI in the designer. (this will allow you to access the components that will eventually feed the data into your ricker function). I would then integrate your code into the mainwindow class just as @SGaist eluded to.

    Either way to get your signals and slots your going to need a class that inherits from QObject somehow and calls the proper code that you need to implement.

    Good Luck,
    Shawn


  • Qt Champions 2019

    @Flavio-Mesquita I'm not sure what the problem is now. In your example at the beginning you already read all this information from the UI, so what is not working?



  • @jsulm The way I found to pass the argument f from the interface to the main was using QProcess, like this:

    Inserting a void in the interface:

    void interface2::wavelet()
    {

    std::cin >>f;
    std::cout << f <<endl;
    }

    And adding these lines before the Qwt stuff on the main code:

    QProcess p1;
    p1.start("interface2.exe");
    p1.write("f\n");
    QObject::connect(&p1, &QProcess::readyRead, &p1{
    //output to qDebug, you may want to update some GUI component instead
    qDebug() << p1.readAll();
    });

    Although it doesn´t give any erros while compiling it crashes, I believe it is some type error in the variable f, since it is declared as double on the ricker vector, and write sends it like a qint64. Is there anyway to define the type inside write ()?


  • Qt Champions 2019

    @Flavio-Mesquita Now I'm completely lost - why is your interface a stand alone application now?
    And how it can crash while compiling? Do you maybe mean it does not compile and shows you a compiler error?


  • Qt Champions 2019

    @Flavio-Mesquita Also if you really want you app to be a stand alone application then you're using QProcess wrongly: you are passing string "f\n" to it and not the value of variable f.



  • @jsulm I was suspecting I was doing something wrong there, I´m reading how to use QProcess right now, I got thi idea from an example I found in a forum. How would I do the pass the variable f trough it?


  • Qt Champions 2019

    @Flavio-Mesquita It depends. Do you want to pass this variable as parameter when starting the process? If so then:

    QStringList arguments;
    arguments << f;
    myProcess->start(program, arguments);
    

    See http://doc.qt.io/qt-5/qprocess.html
    Else

    myProcess->write(QByteArray::number(f));
    

    But you're aware that you will need to read it from stdin in your GUI app?



  • @jsulm I finally got it "working", did the way sgaist said, I was forgetting to declare the Qvector on the header., that was all.
    like this:
    QVector<QPointF> ricker(double f, double dt, double length );

    The only issue now, is the plot that closes too fast, I just see the window for miliseconds and disapear, how do I fix it?


Log in to reply