[solved]Call class function in another cpp file
-
Hi,
Sorry for this very simple question but I am failing horribly at it.
So I have a function in my MainWindow.cpp; void test().
void MainWindow::test() { progressBar->setEnabled(true); progressBar->setVisible(true); progressBar->setValue(50); ui->dockWidget->setWindowTitle("TEST"); }
The function is declared in mainwindow.h
In jsfunctions.cpp I have mainwindow.h included and I try to call test(); . However, I have to make an object because otherwise I cant call it. The result of this is that the changes in UI that are made in the test() function are not visible, they are in a new object. I do not want this, I want to change the current UI that is visible (and I would like to avoid creating a new UI). I tried static (which gave errors) and tried to make signal/slot connections.
I am sure its something very simple, but I just don't see it. Help would be greatly appreciated.
-
Well, as you discovered, you need an object to call a method. Then the most obvious solution would be to give a pointer on your
MainWindow
object to the function which tries to callMainWindow::test()
.One solution would be to emit a signal in your jsfunction,cpp (about which you don't give information) which would trigger the call to
MainWindow::test()
(which would need to be a slot). But without knowing what the content of jsfunction.cpp it's hard to tell.Give us more information on how you want to call
MainWindow::test()
and we'll be able to help. -
You should not call MainWindow methods somewhere else. Your jsfunction should emit a signal instead of calling test(), you connect that signal to a slot in MainWindow. This way jsfunction do not need to know anything about MainWindow.
-
Currently I am working in 2 windows. 1 window is the MainWindow, the application launches with only this. The second window opens when requested and gives the functionality to parse a script (using QJSEngine). This window is called CustomCode.
In the script I want to call functions which I have in my project. Currently I am only trying to call test() to understand the principle and continue from that.
According to this stackoverflow, I had to use QObjects. That is where jsfunctions came in, this is a QObject class which I integrate into the QJSEngine.
So my QS Script looks like this:
jsfunction.call_test();
CustomCode.h:
#ifndef CUSTOMCODE_H #define CUSTOMCODE_H #include <QMainWindow> namespace Ui { class CustomCode; } class CustomCode : public QMainWindow { Q_OBJECT public: explicit CustomCode(QWidget *parent = 0); ~CustomCode(); private: Ui::CustomCode *ui; private slots: void on_button_clicked(); }; #endif // CUSTOMCODE_H
CustomCode.cpp:
#include "customcode.h" #include "ui_customcode.h" #include "jsfunctions.h" #include <QtWidgets> #include <QJSEngine> #include <QFile> CustomCode::CustomCode(QWidget *parent) : QMainWindow(parent), ui(new Ui::CustomCode) { ui->setupUi(this); QPushButton *button = new QPushButton("Test"); ui->verticalLayout->addWidget(button); connect(button,SIGNAL(pressed()),SLOT(on_button_clicked())); } CustomCode::~CustomCode() { delete ui; } void CustomCode::on_button_clicked() { QLabel *tb = new QLabel; ui->verticalLayout->addWidget(tb); QJSEngine myEngine; QJSValue scripttb = myEngine.newQObject(tb); jsfunctions jsfunction; QJSValue jsfunctionObj = myEngine.newQObject(&jsfunction); myEngine.globalObject().setProperty("jsfunction",jsfunctionObj); myEngine.globalObject().setProperty("tb",scripttb); QString fileName = "customlogic.qs"; QFile scriptFile(fileName); if (!scriptFile.open(QIODevice::ReadOnly)) { }// handle error QTextStream stream(&scriptFile); QString contents = stream.readAll(); scriptFile.close(); QJSValue result = myEngine.evaluate(contents, fileName); //QJSValue result = myEngine.evaluate("jsfunction.call_test();"); if (result.isError()) { qDebug() << "result: " << result.property("lineNumber").toInt() << ":" << result.toString(); } }
jsfunctions.h:
#ifndef JSFUNCTIONS_H #define JSFUNCTIONS_H #include <QObject> #include <QWidget> #include <mainwindow.h> class jsfunctions : public QObject { Q_OBJECT public: explicit jsfunctions(QObject *parent = 0); void call_test() { emit send_test(); } signals: void send_test(); public slots: }; #endif // JSFUNCTIONS_H
jsfunctions.cpp:
#include "jsfunctions.h" #include "mainwindow.h" jsfunctions::jsfunctions(QObject *parent) : QObject(parent) { }
MainWindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QtCore> #include <QtGui> #include <QProgressBar> #include <QGridLayout> #include <QScrollArea> #include "vprParam.h" #include "customcode.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); CustomCode *codewindow; ~MainWindow(); public slots: void test(); private: QStandardItemModel *model; QWidget *box; QGridLayout *grid; void build_UI(vprParam_Inst_t* pInst, std::string profile); private slots: void on_actionOpen_CSV_triggered(); void on_actionIP_List_toggled(bool arg1); void on_treeView_doubleClicked(const QModelIndex &index); void on_actionSave_triggered(); void on_profile_clicked(int index); void on_actionAdd_custom_logic_triggered(); private: Ui::MainWindow *ui; QProgressBar *progressBar; QWidget *central; QGridLayout *layout; }; void loadcsv(QString IP, QString SUBIP); void SetValueInDb(QString name, int value); #endif // MAINWINDOW_H
mainwindow.cpp (only the relevant code)
#include "mainwindow.h" #include "ui_mainwindow.h" #include "vprParam.h" #include <string> #include <vector> #include <QFileDialog> #include <QtWidgets> #include <QComboBox> #include <QLabel> #include "paramblock.h" struct readips { }; struct create_db { }; struct memory { } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); progressBar = new QProgressBar; ui->statusBar->addPermanentWidget(progressBar); progressBar->setVisible(false); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_actionOpen_CSV_triggered() { } void loadcsv(QString IP,QString SUBIP) { } void MainWindow::on_actionIP_List_toggled(bool arg1) { } void MainWindow::on_treeView_doubleClicked(const QModelIndex &index) { } void MainWindow::on_profile_clicked(int index) { } void MainWindow::build_UI(vprParam_Inst_t* pInst, std::string profile) { } void MainWindow::on_actionAdd_custom_logic_triggered() { codewindow = new CustomCode; codewindow->show(); } void MainWindow::test() { progressBar->setEnabled(true); progressBar->setVisible(true); progressBar->setValue(50); ui->dockWidget->setWindowTitle("TEST"); }
I already tried to make it with signal/slots but I failed at this, I always ended up with having to create a new object for mainwindow, I would like to see how to do it properly.
Also, sorry for any messy/confusing code, I am new to c++ and Qt and a rookie programmer overall.Thanks!
-
OK, according to what I understood from your design,
MainWindow
spawns aCustomCode
instance when requested. Therefore when constructing theCustomCode
instance you know whichMainWindow
instance you have to connect to. If I were you I'd use the callingMainWindow
instance as parent of theCustomCode
instance. This would allow to connect thesend_test()
signal to thetest()
slot of yourMainWindow
instance. -
How could I do that?
If I do this in mainwindow.cpp:
codewindow = new CustomCode; codewindow->setParent(this); connect(codewindow,SIGNAL(send_test()),SLOT(test())); codewindow->show();
This makes it compile but instead of a seperate window the current mainwindow gets overwritten with the codewindow and the send_test() is in jsfunctions.h, not in CustomCode.h. Would I have to make a function that calls another function that calls the signal? Or am I missing it here? Sorry
Edit:
Succes!
I used : (in mainwindow.cpp)
void MainWindow::on_actionAdd_custom_logic_triggered() { codewindow = new CustomCode; QObject::connect(&jsfunction,SIGNAL(send_test()),this,SLOT(test())); codewindow->show(); }
added
extern jsfunctions jsfunction;
to mainwindow.h and customcode.h
addedjsfunctions jsfunction;
in jsfunctions.cppand changed jsfunctions.h to
signals: void send_test(); public slots: void call_test() { emit send_test(); }
Now it works! test() gets properly called and my UI actually changes. Many thanks! :)
PS: How do I change the topic to solved?
-
I don't think it is necessary to have a static instance of
jsfunctions
to do this. Why did you add it? As far as I understand, thejsfunctions
instance was meant to be used in theCustomCode
instance? Assuming my hypothesis is correct, I would do theconnect
in theCustomCode
, where both theMainWindow
andjsfunctions
instance are used:void MainWindow::on_actionAdd_custom_logic_triggered() { codewindow = new CustomCode( this ); codewindow->show(); }
CustomCode::CustomCode( QObject* parent ) : QMainWindow(parent) , ui(new Ui::CustomCode) , jsfunction( new jsfunctions() ) { connect( jsfunction, SIGNAL( send_test() ), parent, SLOT( test() ) ); } @TheHawk said: > PS: How do I change the topic to solved? You can simply edit the topic title (IIRC by editing your first post),
-
I have no particular reason why I chose it to be static, I did it because after googling some errors it was suggested to use static.
Anyhow, your code indeed works as well and your assumption was correct! :)
I do have a little issue now. Callingcodewindow = new CustomCode( this );
makes the new window always on top. I previously calledcodewindow = new CustomCode;
, this made the 2 windows independant (if you clicked the one in the back it came to front). I don't really see an option how to fix this behavior besides using signals and slots at a click to bring a window up and lower the other one. Am I missing the obvious here?thanks!
-
I think you can tune this behaviour with the correct window flag, which is the second argument of the
QMainWindow
constructor.Edit:
As another way to do it, you can pass a null pointer to theQMainWindow
constructor in theCustomCode
constructor, but still use the parent pointer in theconnect
statement. -
I tried all the window flag settings without succes, it always stays on top.
How would I pass a null pointer to the
QMainWindow
constructor in theCustomCode
constructor? Can't really get my head around it. Changing the call to:
codewindow = new CustomCode(0);
orcodewindow = new CustomCode;
creates the desired effect but makes me unable to call the function (since no parent exists I think?).Am I even calling the windowflag correctly?
void MainWindow::on_actionAdd_custom_logic_triggered() { CustomCode *codewindow; codewindow = new CustomCode(0); //QObject::connect(&jsfunction,SIGNAL(send_test()),this,SLOT(test())); codewindow->setWindowFlags(Qt::Window); codewindow->show(); }
-
I got a question though (kinda off-topic). Would it be possible to create a signal from the
MainWindow
to a slot (or function) inside the javascript script that I evaluate insideCustomCode
? So for example:I want to plot a graph using the javascript script. I want that graph to use actual, changing values from
mainwindow
. So I would like to create a signal that triggers upon a value change and then call a function inside the javascript script to update the graph with the new values. -
@TheHawk said:
I got a question though (kinda off-topic). Would it be possible to create a signal from the
MainWindow
to a slot (or function) inside the javascript script that I evaluate insideCustomCode
? So for example:Better ask a new question in a new thread, for the future, it helps when looking for a problem on the forum.
You are free to define any signal / slot you want, so the short answer is yes.
You can emit a signal inMainWindow
when the data needs to be reprocessed by the js script managed byCustomCode
.