QT calling functions in different sources - c++

In my project I've created multiple gui pages. In a secondary source (secondary.cpp) I want to call a function that declared in my mainwindow.cpp. I'm not really sure how to do this.
I've tried to declare the function at public section like:
QString format (QString number);
And definition in the mainwindow.cpp like:
QString MainWindow::format(QString number)
{
...
}
Then i include #include "mainwindow.h" in my secondary source (secondary.cpp) and calling the function with lower = format(upper); but I'm getting an error message:
format was not declared in this scope.
I've also tried calling it by
lower = MainWindow::format(upper);
which gives me the error message
Cannot call member function QString MainWindown::format(Qstring)
without object.
Finaly I also tried to make a class in my mainwindow.h
class test : public QString
{
public:
QString format (QString number);
};
With QString test::format(QString number) in my mainwindow.cpp calling the function by lower = test::format(upper);
this gives me the error:
Cannot call member function QString MainWindown::format(QString)
without object.
I'm not convinced that I need to create a new class, but I thought I'd try anyway.

You need to create object of MainWindow class, then call function:
MainWindow *w = new MainWindow;
QString lower = w->format(upper);
Or another solution is static function of class. This way you have no needed create object of class and can call method by name like this:
QString lower = MainWindow::format(upper);
Of course you need to include your #include "mainwindow.h" header.
But you should know that MainWindow class is not the best place storing function for formation string, you can use QString class function like QString::toUpper() or QString::toLower() or create your own class for formating:
class myFormatingStringClass {
QString toLower(QString str);
static QStrin toUpper(QString str);
}
As i said above this way you will need to create object of myFormatingStringClass for using myFormatingStringClass::toLower() function or using static method:
QString upper = QString("Hello World");
myFormatingStringClass formating;
QString lower = formatin.toLower(upper); // Using class method of existing object
QString upper = myFormatingStringClass::toUpper(lower); // Using static method

You can't do test::format(...) to call a non-static member function.
It must be bound to an object (an instance of your class). For example, you can do this :
test testObject;
QString formattedString = testObject.format(strToFormat);

Related

Use of temporal constructors inside vector

I cam from programming in Java and I thought doing as here [my code] could work the definition of temporal constructors, but I am having problems the proper way of writing the code to just work.
PROBLEM: I want to add a Constructor of the class Coomunication for every port I find in a machine and save it into a vector:
ControlCommunication.cpp:
...
QVector<Comunication *> ports;
...
void ControlCommunication::checkPorts(){
qint16 vendorid = cuquito.getVendorID();
qint16 productid = cuquito.getProductID();
const QString blankString = "N/A";
for (const QSerialPortInfo &serialPortInfo : QSerialPortInfo::availablePorts()) {
Comunication com(serialPortInfo.portName());
addPort(com); // <- I do not know how to get this working well
}
}
ControlCommunication.h:
class ControlCommunication : public QObject
{
Q_OBJECT
public:
explicit ControlCommunication(QObject *parent = nullptr);
QVector<Comunication*> getComunicationPorts(){return comunicationports;}
void addPort(Comunication com);
...
Comunication.h:
#ifndef COMUNICATION_H
#define COMUNICATION_H
#include <QObject>
#include <QSerialPort>
#include <QMainWindow>
class Comunication:public QObject{
Q_OBJECT
public:
Comunication( QString serialPortName);
Comunication();
public:
public slots:
void openSerialPort();
void closeSerialPort();
void writeData(const QByteArray &data);
void readData(QByteArray &data);
void handleError(QSerialPort::SerialPortError error);
QString getPortName(){return portname;};
signals:
private:
QSerialPort *m_serial = nullptr;
QString portname;
};
#endif // COMUNICATION_H
The error I get is: call to implicitly-deleted copy constructor of 'Comunication'
comunication.h:8:20: note: copy constructor of 'Comunication' is implicitly deleted because base class 'QObject' has a deleted copy constructor
qobject.h:449:20: note: 'QObject' has been explicitly marked deleted here
controlcommunication.cpp:27:49: note: passing argument to parameter 'com' here
As I understand from the error message, I cannot call a constructor which is gonna be deleted in that function from other statements. How can i get this working?
The error you're getting mean you can't copy Communication. When you're passing com to addPort, you're making a copy of the object which will be passed to the function. But because you're inheriting a QObject you can't make copies of your objects. Which means you can't those objects by value. You can add pointers or (ideally) a reference to use objects.
But in your case, I don't think that's going to work easily, you seem to want a QVector<Communication*> which I'm assuming will be filled by addPort. But you're creating Communication in your loop which will be delted when it exists the loop, and so pointers to it won't work.
I don't have enough information, and I'm not versed with Qt, so please someone correct if I'm wrong, but I would suggest that you build Communication inside addPort and change QVector<Communication*> to QVector<Communication>.
My intuition would be that Communication doesn't need to inherit from QObject, but I could be wrong. But the data from your program should probably be separated from the Qt stuff, to make things easier to manage.
You are passing the Comunication object by value into the addPort function. This will try to create a copy of the object. But QObjects (and anything derived from QObject) are non-copyable. So you should change your function to take a pointer or reference instead.
Also, you probably need to allocate your objects on the heap because they will go out of scope, freeing any stack memory.
void addPort(Communication *com);
...
for (const QSerialPortInfo &serialPortInfo : QSerialPortInfo::availablePorts()) {
// Allocate on the heap
Comunication *com = new Comunication(serialPortInfo.portName());
// Pass pointer to addPort
addPort(com);
}

QT Creator accessing pointers to objects

Very new to QT but basically I have a class called object and on my GUI is a one button and one text browser. Now in my class object I have one private QString variable called name and its constructor assigns a value (QString) to the variable called name . The object class has one function called QString getName() const; which returns the name:
class object{
private:
QString name;
public:
object(QString name);
QString getName()const;
};
Now in QT in my mainwindow.h file I put
public:
object *o;
and then in the constructor :
object o2("Name");
o = &o2;
Now I want to call the function void MainWindow::on_pushButton_clicked() and all this function will do is set the text in the text browser to the name variable in my object (which would be "Name" btw) so inside the function I put ui->Console->setText(o->getName()); console being the name of my text browser- when i run the code and click the button its saying that Ive referenced memory and giving an error. Keep in mind I moved ui->Console->setText(o->getName()); to the constructor and it worked perfectly (obviously didnt work when the button was clicked but the text was put in the text browser) so what am I doing wrong here ?
The pointer (o) outlives the object that it points to (o2). One way to fix it is by allocating new memory for the object:
o = new object("Name");
And then you'll need to remember to delete that memory later.

not working Passing instance of class by reference in qt c++ lambda Signal&Slots

This code in Profile3.cpp i just want to pass the instance kitchenData of Kitchen_Data class reference not by value but it prints that
error: undefined reference to
`Profile3::Kitchen_DoubleClicked(Kitchen_Data&)'
Profile3::Profile3(QWidget *parent) :
QWidget(parent),
ui(new Ui::Profile3)
{
ui->setupUi(this);
Kitchen_Data kitchenData;
connect(ui->treeWidget_Kitchen,
&QTreeWidget::itemDoubleClicked,
[&,this]{Kitchen_DoubleClicked (kitchenData);});
}
in profile3.h i've the class
class Kitchen_Data{
public:
QString MealCode;
QString MealName;
QString MealPrice;
QString MealType;
QTreeWidgetItem * itemm_CancelButton_From_Kitchen ;
QVector <QString> KitechenItemPrice;
QVector <QString> KitechenItemName;
QString All_Added_ItemOfKitechen;
QString KitchenTotalPrice;
};
and this private slots of profile3 class and the function that i want to use pass the instance to
private slots:
void Kitchen_DoubleClicked(Kitchen_Data &Kitchen);
As mentioned in the comments, passing a reference to a local variable in the lambda is a bad idea. The instance kitchenData will already be out of scope/destroyed by the time you access it from within the Kitchen_DoubleClicked slot. To make it survive long enough to be used by the slot, you need to either dynamically allocate it (e.g. Kitchen_Data* kitchenData = new Kitchen_Data;), or make kitchenData a member of the Profile3 class, e.g.:
class Profile3 {
Kitchen_Data kitchenData;
// other members, methods, slots, etc...
};

c++ Use a class variable in a non-class function

I'm facing this novice issue. Assume the class MainFrame (the following code isn't going to compile - I'm trying to give a basic idea of what I'm doing because I think my problem is easy to solve by someone more knowledgeable than me) which lives on file gui.cxx along with other functions. Note that this is part of a larger project so I'm skipping the main.cxx which I have included gui.h.
In the function start_gui_with_config() I'm trying to use an object from MainFrame. At the moment is declared as private so I'm expecting to have an text_data_path was not declared in this scope.
I also declared this variable as public and static in the class definition in gui.h but then I get the same error when using either text_data_path ->SetText(data_path);.
When I'm using MainFrame::text_data_path ->SetText(data_path); (still text_data_path is declared as private and static) I get the error undefined reference to MainFrame::text_data_path in any line I'm using text_data_path within the MainFrame::MainFrame constructor (file gui.cxx) and strangely I get this error twice for each line.
Finally I tried making all the functions (start_gui(), start_gui_with_config()) part of MainFrame and I declared them as either static void (in this case I got an error error: cannot declare member function static void MainFrame::start_gui_with_config() to have static linkage on the gui.cxx ) or void (in this case I got the error error: cannot call member function void MainFrame::start_gui_with_config() without object on the main.cxx).
Any idea on how to use text_data_path in a function (i.e. start_gui_with_config()) that doesn't belong to the class?
gui.cxx
#include "../include/gui.h"
MainFrame::MainFrame(const TGWindow *p, UInt_t width, UInt_t height):TGMainFrame(p, width, height, kMainFrame|kHorizontalFrame){
// Define widgets
text_data_path = new TGTextEntry("/data/2020");
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// This is a virtual constructor
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MainFrame::~MainFrame() {
// Clean up used widgets: frames, buttons, layout hints
Cleanup();
}//_____MainFrame::~MainFrame()
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// This is to start the GUI with default settings
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void start_gui(){
// Popup the gui
std::cout << "Starting the gui" << std::endl;
new MainFrame(gClient->GetRoot(), 1000, 800);
}//_____start_gui()
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// This is to start the GUI using the configuration file from previous session
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void start_gui_with_config(){
TString data_path = gSystem->GetFromPipe("awk '{if(NR==1) print $NF}' Config/last_session.cfg.viewer");
start_gui();
MainFrame::text_data_path->SetText(data_path);
}//____MainFrame::start_gui_with_config()
gui.h
#ifndef ___GUI_H
#define ___GUI_H
//ROOT Includes
#include <TGTextEntry.h>
//C++ includes
using namespace std;
class MainFrame : public TGMainFrame {
private:
// Widgets
TGTextEntry *text_data_path;
public:
// Widgets
//static TGTextEntry *text_data_path;
MainFrame(const TGWindow *p, UInt_t width, UInt_t height);
virtual ~MainFrame();
//void start_gui_with_config();
//static void start_gui();
ClassDef (MainFrame,0);// Remove for ROOT6 and rootcling
};
void start_gui();
void start_gui_with_config();
#endif
I suggest you use a setter on the MainFrame class:
void setDatapathText(TString const& newDatapath) {
text_data_path->SetText(data_path);
}
You can then call it like so in your start_gui_with_config function :
auto frame = MainFrame(p, w, h);
frame.setDatapathText(data_path);
Be careful, your code clearly has memory management problems, and as a general rule you should never deal with raw new and delete outside of smart pointers. I suggest making sure you are comfortable with dynamic allocation, else I'm afraid you will be facing hard-to-debug errors earlier than expected
Your problem is you throw away the pointer to your MainFrame so you have no way to access it in start_gui_with_config() after you created the MainFrame.
One way to fix this is to change the signature of void start_gui(); to MainFrame* start_gui(); in your gui.h header.
In the gui.cxx change the implementation to
MainFrame* start_gui() {
return new MainFrame(gClient->GetRoot(), 1000, 800);
}
And then in your start_gui_with_config() use the pointer like this:
void start_gui_with_config(){
TString data_path = gSystem->GetFromPipe("awk '{if(NR==1) print $NF}' Config/last_session.cfg.viewer");
MainFrame* frame = start_gui();
frame->text_data_path->SetText(data_path);
}//____MainFrame::start_gui_with_config()
This code assumes the MainFrame object destroys itself otherwise the code will leak memory. I assume this destruction happens after the window closes. I have seen other GUI frameworks like Qt do this.

Binding instance of C++ object to QML object

I'm new to Qt, and have written a basic application which has one class which inherits from QObject and is bound to a QML file.
I now want that class to contain a Vector of objects (let's say from a class Customers), which contains some data, such as a QString for name, etc.
To make life easier I'll create these objects manually in main, and place some text fields in my QML file.
I now want to be able to bind specific objects to specific text fields in the QML file, such that when a value changes, the value in the text field updates.
How can this be done? It looks like QML statically calls methods of the classes it's bound to, instead of on an assigned object.
I feel like QAbstractList may have some use here, but not too sure. Would rather not have to inherit from anything for my Customers class.
EDIT:
I think I may be able to do what I want with a QObjectList-based Model (https://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html). I notice it says at the bottom that "There is no way for the view to know that the contents of a QList has changed. If the QList changes, it is necessary to reset the model by calling QQmlContext::setContextProperty() again."
Does this mean that if a value inside DataObject (such as name) changes, the model has to be reset, or only when the Qlist itself changes (i.e. new item added, or item deleted)? If the latter, I would think this should be fairly easy to maintain as I would only need to set the context property whenever anything is added or deleted.
This may be usefull if you want to process raw QObject instance in QML script. You can append properties to Element class and modify them from qml.
class Element : public QObject {
Q_OBJECT
private:
QString type;
QLinkedList<Element*> child;
public:
explicit Element(QString type, QLinkedList<Element*> child);
virtual ~Element();
public:
QLinkedList<Element*> getChild() const;
QString getType() const;
public:
static void printTree(Element* root);
};
this is so simple you need to use NOTIFY
define your properties like this :
Q_PROPERTY (QString name READ name WRITE setName NOTIFY nameChanged)
then you need to define each one like this :
public : QString name() const;
signals :
void nameChanged(QString name);
public slots:
void setName(const QString &name);
private QString _name;
and then you should define body in cpp like this :
QString className::name() const{
return _name;
}
void className::setName(const QString &name){
if(name==_name) return;
_name = name;
Q_EMIT nameChanged(_name);
}
after registering it to QML with qmlRegisterType<ClassName>("com.className",1,0,"className");
simply set name it will notify if it changes for example in a textfield set text to that name property