QT how to pass Qlist to class Constructor - c++

am trying to pass Qlist to class constructor but no success with it. I can pass basic variables but with Qlist am getting error in editor
error: no matching constructor for initialization of 'Worker'
compiler error
error: no matching function for call to 'Worker::Worker(QList<MainWindow::MainWindow(QWidget*)::pnp_com_info>&)'
Worker* worker = new Worker(pnp_data);
here is what am doing.
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// my sample structure
struct pnp_com_info{
QString com_name = "";
int x = 0;
int y = 0;
int angle = 0;
bool status = false;
};
QList<pnp_com_info> pnp_data; // Qlist container
pnp_com_info pnp_component_data; // struct
// fill with data
pnp_component_data.com_name = "e18";
pnp_component_data.angle = 600;
// add it to Qlist container
pnp_data.append(pnp_component_data);
// Worker worker(5); // sample int passed OK.
// try to pass Qlist to worker constructor
Worker* worker = new Worker(pnp_data); // no success get error : no matching constructor for initialization of 'Worker'
}
worker.h source code
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
class Worker : public QObject {
Q_OBJECT
public:
struct pnp_com_info{
QString com_name = "";
int x = 0;
int y = 0;
int angle = 0;
bool status = false;
};
// Worker(int sampleVar);
Worker(QList<pnp_com_info> pnpData);
~Worker();
public slots:
void doWork();
signals:
private:
QList<pnp_com_info> pnp_components_data;
};
#endif // WORKER_H
worker.cpp
#include "worker.h"
// --- CONSTRUCTOR ---
Worker::Worker(QList<pnp_com_info> pnp_data) {
// Worker::Worker(int sampleVar) {
this->pnp_components_data = pnp_data;
}
// --- DECONSTRUCTOR ---
Worker::~Worker() {
// free resources
}
// --- PROCESS ---
// Start processing data.
void Worker::doWork() {
// do some work
}
so any idea what am doing wrong. thanks

In the worker.cpp, you are not "inside" the class scope. So there you need to fully qualify the type:
Worker::Worker(QList<Worker::pnp_com_info> pnp_data) {
And then in MainWindow you of course need to use the same struct, Worker::pnp_com_info and not define a new struct type.
You might want to put the struct definition somewhere else than under Worker too. But where, that's impossible to advice on based on just the code you are showing; perhaps having it as nested struct inside Worker is a fine place for it.
I personally like to use Qt Creator (or whatever IDE I might be using, for any programming language) refactoring functionality to generate the method definition to .cpp file. Write the declaration inside th class in .h file as usual, then right click it to get context menu, select refactoring and select the generate option you want. Avoids mistakes like this and can save quite a lot if head banging especially when coding while a bit tired.

Related

Creating a global object in QT GUI

I am trying to create an object called x from a class "Fan" inside the QT GUI mainwindow file, where I want it to be global. I want QT's button slot functions to be able to perform operations on the object. However, a compiler error "error: C4430: missing type specifier - int assumed" always occurs. Here is the header file:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_btOn_clicked();
void on_btOff_clicked();
private:
Ui::MainWindow *ui;
Fan x; // This doesn't work
Fan * x; // This doesn't either
int x; // This does work
};
#endif // MAINWINDOW_H
And here is the cpp file:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "fan.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_btOn_clicked()
{
ui->lblState->setText("Fan is on");
}
void MainWindow::on_btOff_clicked()
{
x.turnOff(); // This does not work of course
x->turnOff(); // Or this
ui->lblState->setText("Fan is off");
}
I already told the cpp file to include the Fan class from the fan.h file. If I create the object within the window constructor, it initializes fine but is not global. Also, there is no circular inclusion of header files. Fan class does not include mainwindow.
Perhaps I don't know how to search for it, but I've already done some research into it to no avail. Any help is appreciated.
Edit:
Here is the fan.cpp file
#include "fan.h"
Fan::Fan(){
speed = 0;
isOn = false;
}
void Fan::setSpeed(int s){
speed = s;
}
int Fan::getSpeed(){
return speed;
}
void Fan::turnOn(){
isOn = true;
speed = 1;
}
void Fan::turnOff(){
isOn = false;
speed = 0;
}
bool Fan::getState(){
return isOn;
}
And the fan.h file:
#ifndef FAN_H
#define FAN_H
class Fan
{
private:
int speed;
bool isOn;
public:
Fan();
void setSpeed(int);
void turnOn();
void turnOff();
int getSpeed();
bool getState();
};
#endif // FAN_H
You forget to include or declare the class Fan in your Header File. If you use
Fan * x;
You could use
class Fan;
as a forward declaration at the beginning of your Header File. The Compiler only need to know that there is a class called Fan but inside the Header you only use a pointer. Butt don't forget to #include the real file in your CPP file.
If you use
Fan x;
you have to #include the Fan.h in your Header-File

Qt: passing objects to every window

Im a beginner at C++ since I'm a Java-Dev. I'm learning Qt right now.
Now I want in my widget application on central object for holding special functionality (for example a bunch of methods for sending different network-command or something like that). In my mainwindow.cpp I've got this
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
//...
BusinessLogic* bl = new BusinessLogic;
bl->setMyValue(44);
this->setBusinessLogic(bl);
this->getBusinessLogic();
//...
}
BusinessLogic* MainWindow::getBusinessLogic()
{
return this->bl;
}
void MainWindow::setBusinessLogic(BusinessLogic* newbl)
{
this->bl = newbl;
}
Where BusinessLogic.cpp is the class which I want to access from all windows in my application. So in my Dialog which get opend when the pushButton is clicked, I try to use the businesslogic instance like this in the constructor
Dialog::Dialog(QDialog *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
//...
((MainWindow*)parent)->getBusinessLogic();
}
Unfortunately the program crashes everytime the dialog get instanciated (the line with ((MainWindow*)parent)->getBusinessLogic(); get called.
What can I do?
There are several methods for achieving your goal(all depends on your requirements) but one approach is you can create Singleton class of your BusinessLogic and then access it anywhere. have a look here. OR you can also pass object of class one class to another. OR you can use signal slot mechanism.
For you best Solution can be
Class BLogic{
public:
static BLogic* instance(){
static BLogic ins;
return &ins;
}
void setVal(int v){
val = v;
}
private:
BLogic(){}
int val;
};
Now you can call functions of BLogic from any class like
BLogic::instance()->setVal(10);
OR Example of passing objects can be
class ClassA
{
public:
void setClassB(ClassB *ob){
m_classB = ob;
}
ClassB* getClassB(){
return m_classB;
}
private:
ClassB* m_classB;
};
class ClassB
{
public:
void setClassA(ClassA *ob){
m_classA = ob;
}
ClassA* getClassA(){
return m_classA;
}
private:
ClassA* m_classA;
};
Now from main.cpp
ClassA* obA = new ClassA;
ClassB* obB = new ClassB;
obA->setClassB(obB);
obB->setClassA(obA);
Don't pass a zero parent or a dangling pointer to the dialog.
But more seriously, verify your assumptions:
qDebug() << "the parent object is" << parent;
auto p = qobject_cast<MainWindow*>(parent);
if (p)
p->getBusinessLogic();
Debug output will give you some idea of whether a parent is set, and of what type it is at the moment. Remember that during the construction of a MainWindow instance, it goes through being different types (quite literally). So depending on when you construct the child, you might get a parent of type QWidget* or QMainWindow* or MainWindow*. During the destruction you could even get a QObject* parent!

Why does my attempt at connecting a pushbutton to a lambda fail?

I have some issues while trying to use lambda expression to make connections between a pushbutton and a function I want to call when I click the button.
I am using Qt 5.6, with the compiler MinGW 4.9.2 (the default one). My code is the following :
In mainwindow.cpp :
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
initBuildings();
initPage();
for (int i(0); i<buildings.size(); ++i) {
connect(static_cast<QAbstractButton*>(widgetlist.at(i).at(2)), &QAbstractButton::clicked, [this, i]() {
buildings.at(i).buy(amountMultiplier);});
}
}
void MainWindow::initBuildings()
{
Building b1 = Building("Building 1",100,1,200);
Building b2 = Building("Building 2",1000,10,2000);
buildings.append(b1);
buildings.append(b2);
}
void MainWindow::initPage()
{
for (int i(0); i<buildings.size(); i++) {
QList<QWidget *> buttons;
QLabel *namelabel = new QLabel(buildings.at(i).getName());
QLabel *amountlabel = new QLabel;
QPushButton *buybutton = new QPushButton(this);
QPushButton *upgradebutton = new QPushButton(this);
amountlabel->setFixedSize(50,40);
buybutton->setFixedSize(100,40);
upgradebutton->setFixedSize(100,40);
buttons.append(namelabel);
buttons.append(amountlabel);
buttons.append(buybutton);
buttons.append(upgradebutton);
widgetlist.append(buttons);
}
}
In mainwindow.h :
#include <QMainWindow>
#include <QScrollArea>
#include <QList>
#include <building.h>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
void initBuildings();
void initPage();
Ui::MainWindow *ui;
int amountMultiplier;
QList<Building> buildings;
QList<QList<QWidget*>> widgetlist;
};
And "Building" is a class I have created which does not inherit from another class. The function I want to use is a public funtion of this class:
void buy(int amount) const;
It doesn't compile and I get several errors :
no matching function for call to 'MainWindow::connect(QAbstractButton*, void (QAbstractButton::*)(bool), MainWindow::MainWindow(QWidget*)::<lambda()>)
invalid use of incomplete type 'struct QtPrivate::QEnableIf< false, QMetaObject::Connection>
cannot convert '<lambda closure object>MainWindow::MainWindow(QWidget*)::< lambda()>{((MainWindow*)this), i}' (type 'MainWindow::MainWindow(QWidget*)::< lambda()>') to type 'const QObject*
I tried to change the lambda capture list, or to change the way I get the value in the lists but it doesn't change anything and I don't figure what is the problem. Maybe I am wrong in the use of the lambda ?
Two problems:
buildings.at() returns a const Building &, and the buy method is not const. You must index the buildings using [] instead.
The type returned from widgetlist.at(i).at(2) is definitely not QPushButton* - if it was, the code would compile. Even the error message indicates what the issue is:
no matching function for call to 'MainWindow::connect(QWidget* const&, void (QAbstractButton::*)(bool), [...])
This compiles:
// https://github.com/KubaO/stackoverflown/tree/master/questions/lambda-list-37615204
#include <QtWidgets>
struct Building {
void buy() {}
};
class Class : public QObject {
QList<Building> m_buildings;
QList<QList<QWidget*>> m_widgets;
public:
Class() {
for (int i = 0; i<m_buildings.size(); ++i)
connect(static_cast<QAbstractButton*>(m_widgets.at(i).at(2)), &QAbstractButton::clicked, [=] {
m_buildings[i].buy();
});
}
};
int main() {}
If you wish an extra measure of safety in face of programming errors on your part, replace the static_cast with a qobject_cast, it'll then abort if you cast a non-button instead of doing something possibly misleading.
According to the documentation, your lambda should accept a bool argument.

Using Signals/Slots to avoid circular dependencies?

I've got an unelegant chunk of C++ Qt code where main creates a graphics item (the parent) which creates a bunch of child graphics items. The child and parent have to call each others methods, i.e. the parent needs to tell its children to do some things (move, change color, etc), and the children will signal the parent to do things to its other children. Having both call each others' methods is leading to some ugly circular code, and it's getting frustrating dodging C2027 errors. Would it make any sense to use a custom signal/slot system as a method of communication between the child and parent? Or should I stay the course with my current design and just try and solve these kinds of bugs?
For example, this code (my current design) generates C2027:
Mainwindow:
#include "mainwindow.h"
#include "ui_mainwindow.h"
vector<Foo*> FooArray;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
int viewwidth = ui->graphicsView->width();
...
FooArray.push_back(new Foo(5, viewwidth, scene));
FooArray[0]->loadBars();
}
Foo:
#include "Foo.h" //includes bar.h
vector<int> ActiveList;
vector<Bar*> BarArray;
Foo::Foo(int id, int w, QGraphicsScene* scene)
{
this->id = id;
this->width = w;
this->scene = scene;
}
...
void Foo::loadBars()
{
...
BarArray.resize(nitems);
BarArray[k] = new Bar(id, k, this);
BarArray[k]->setPos(...);
scene->addItem(BarArray[k]);
...
}
void Foo::doSomething()
{
...
}
Bar:
#include "Bar.h" //forward declares Foo; isn't executed until Foo exists.
Bar::Bar(int setid, int num, Foo* foo)
{
this->s = setid;
this->n = num;
this->owner = foo;
}
...
void Bar::someFunction()
{
...
owner->doSomething();
...
}
Yes, that's precisely what signals and slots are for.
Right now you have Bar::someFunction() which calls Foo::doSomething()
What you can do instead is:
Declare doSomething() as a slot
Have Bar emit a signal somethingHappened()
When creating the children, connect their somethingHappened() signal to the parent's doSomething() slot
This is an example of dependency injection, and it allows you to swap the parent class for something else in the future without having to change Bar at all.

c++ destructors

consider this scenario:
I need to create a ui for some settings. As, data and ui should be separated in theory, I defined a separate class which takes care of the configuration data. The question I have is how to instantiate the data class inside the settings class.
One way is to create the data class in the caller object, I mean the object that calls the settings menu class.
The other way, which my question is involved with, is to create a DATA class variable inside the settings class. I doubt what happens when the settings class gets destroyed then! would the data class object inside settings class also get destroyed? what about if it is defined as a static member of settings class?
#ifndef SETTINGSWINDOW_H
#define SETTINGSWINDOW_H
#include <QMainWindow>
#include <QModelIndex>
#include <QSignalMapper>
#include <QRadioButton>
#include <QSpinBox>
#include <QTimer>
#include "cameracommands.h"
struct Config
{
/* General Options */
QString general_key_lock;
QString general_back_light;
};
//class IConfigSource
//{
//public:
// virtual Config config() const;
// virtual void setConfig(const Config& cfg);
//};
class ConfigSource /* : public IConfigSource*/
{
public:
ConfigSource() {
config_.general_back_light = "OFF";
config_.general_key_lock = "OFF";
}
Config config() const {return config_;}
void setConfig(const Config& cfg) {config_ = cfg;}
private:
Config config_;
};
class ConfigUpdater : public QObject
{
Q_OBJECT
public:
ConfigUpdater(ConfigSource& src) : src_(src) {}
public slots:
void apply () {src_.setConfig(tempConfig_);}
void cancel() {tempConfig_ = src_.config();}
public:
void updateGeneralBackLight(QString s) {tempConfig_.general_back_light = s; qDebug() << "BackLight updated :)";}
void updateGeneralKeyLock(QString s) {tempConfig_.general_key_lock = s; qDebug() << "KeyLock updated :)";}
Config tempConfig_;
ConfigSource& src_;
};
//----------------------------
namespace Ui {
class SettingsWindow;
}
class SettingsWindow : public QMainWindow
{
Q_OBJECT
public:
explicit SettingsWindow(QWidget *parent = 0);
~SettingsWindow();
signals:
void clicked(const QString &text);
void sendToPLC(QByteArray );
public slots:
void updateGeneralBackLight();
void updateGeneralKeyLock();
void getRow(QModelIndex);
void MySlot(QString);
private slots:
void on_pushButton_5_clicked();
void on_pushButton_3_clicked();
private:
void set_mappings();
Ui::SettingsWindow *ui;
ConfigUpdater *config_updater;
QSignalMapper *mapper;
};
#endif // SETTINGSWINDOW_H
and this is the source:
QMainWindow(parent),
ui(new Ui::SettingsWindow)
{
/* initializations */
ui->setupUi(this);
ConfigSource src;
config_updater = new ConfigUpdater(src);
That depends on how do you need to use it.
Scenario 1. The settings need to be held in memory when the program is working.
Scenario 2. The settings need to be saved to the disc immediately, and then will be read on-demand.
In scenario 1, you need to be able to always access the data in the memory. So it is better to separate the settingsUI class and the settingsData class, so you will have access to the latter.
class settingsUI
{
<...>
private:
settingsData * data;//pointer to the data object
}
class settingsData
{
}
In scenario 2, you can aggregate settingsData into the settingsUI, and save the data to a file when the UI is destroyed.
class settingsUI
{
public:
<...>
~settingsUI();
private:
class settingsData
{
<..>
}data;
<...>
}
class settingsUI::~settingsUI()
{
data.saveToFile();
}
And yes, uf you aggregate settings into the UI, it will be destroyed when the UI is destroyed. Holding data as a static member is not the best idea, it is better to separate the data from the visual representation (which is in your case the UI class).
UPD:
If you want to hold it just until the program exits, I would suggest you to hold a static pointer to the data in the UI class. Here is an example with raw pointers, but you can use smart pointers too, ofc.
class data
{
}
class UI
{
private:
static data * data_;
}
data* UI::data_;
When your program starts, allocate memory for the data: UI::data_ = new data(), and when your program ends (or if you don't need the data anymore), free the memory: delete UI::data_. Once again, it is better to use smart pointers, so this is just an example.
If the settings class is used by only the UI then it makes sense to keep it within the UI class:
class Settings {
int a;
int b;
};
class Ui {
private:
Settings settings;
};
settings will be destroyed during the destruction of Ui.
If you are using the Settings object in many places, it makes more sense to keep a shared pointer to it:
class Ui {
public:
Ui(std::shared_ptr<Settings> someSettings)
: settings(someSettings)
{}
private:
std::shared_ptr<Settings> settings;
};
This Settings object will be destroyed when the last owner of the shared_ptr is destroyed.
Yes the data object would get destroyed when the settings object is destroyed. If you make it a static member then it would not. But that's probably not such a good idea. A better way would be to persist the data object to a file (say). You can read the file in the settings object constructor and write the file in the settings object destructor.
EDIT
class SettingsWindow : public QMainWindow
{
Q_OBJECT
public:
explicit SettingsWindow(ConfigSource& src , QWidget *parent = 0);
...
}
SettingsWindow::SettingsWindow(ConfigSource& src , QWidget *parent)
QMainWindow(parent),
ui(new Ui::SettingsWindow)
{
ui->setupUi(this);
config_updater = new ConfigUpdater(src);
...
}
thanks, it is correct. The program terminates when I attempt to pass the below variable to the user-defined function:
(inside header)
void print_config(Config cfg);
Ui::SettingsWindow *ui;
ConfigUpdater *config_updater;
inside cpp:
void SettingsWindow::print_config(Config config)
{
qDebug() << config.general_back_light;
qDebug() << config.general_key_lock;
}
void SettingsWindow::on_sendToMainButton_clicked() /* cancel */
{
print_config(config_updater->tempConfig_);
print_config(config_updater->src_.config());
}
the first, print_config instruciton works fine, as for tempConfig_, but the when I pass src_ in the second statement, it jump outta program.
//------------
I know where the problem comes from, but I cannot solve it, i hope this can help:
class ConfigUpdater : public QObject
{
Q_OBJECT
public:
ConfigUpdater(ConfigSource& src) : src_(src) {}
public slots:
void apply () {src_.setConfig(tempConfig_);}
void cancel() {tempConfig_ = src_.config();}
public:
Config tempConfig_;
ConfigSource& src_;
};
Here, src_ is passed by reference, everywhere, even in the constructor of Settings window.
the program fails when I attemp to access it inside memory, for example:
config_updater->cancel();
which does:
void cancel() {tempConfig_ = src_.config();}