I have a question:
I have a class userinterface that has a class MoveSeries. From MoveSeries I want to have access to the methods of my class userinterface. In this example I want to have access to the method get_MoveCurve_Delta() of userinterface. How do I get access to the creating class (userinterface) from the created class (MoveSeries ? I tried the Signal-Slot-Approach but since I have to use several methods of userinterface several times this makes lots of signal-slots...
here is my code:
Userinterface.h:
class UserInterface : public QMainWindow
{
Q_OBJECT
public:
UserInterface(QWidget *parent = 0, Qt::WFlags flags = 0);
~UserInterface();
...
private:
double MoveCurve_Delta;
MoveSeries *MOVE_SERIES ;
public:
void set_MoveCurve_Delta( double val) { MoveCurve_Delta = val;}
double get_MoveCurve_Delta() { return MoveCurve_Delta ;}
}
Userinterface.cpp:
UserInterface::UserInterface(QWidget *parent, Qt::WFlags flags) :
QMainWindow(parent, flags)
{
ui.setupUi(this);
...
MOVE_SERIES = new MoveSeries( this);
}
MoveSeries.h:
class MoveSeries : public QDialog
{
Q_OBJECT
public:
explicit MoveSeries(QWidget *parent = 0);
~MoveSeries();
...
MoveSeries.cpp:
MoveSeries::MoveSeries(QWidget *parent) :
QDialog(parent),ui(new Ui::MoveSeries)
{
ui->setupUi(this);
this->parent = parent;
parent->set-MoveSeries_Delta_Val();
}
Rather than assume that the parent QWidget in MoveSeries is UserInterface, you can also require that it is.
MoveSeries.h:
class UserInterface; // only need a forward declaration
class MoveSeries : public QDialog
{
Q_OBJECT
public:
explicit MoveSeries(UserInterface *parent = 0);
~MoveSeries();
...
UserInterface * uiparent;
}
MoveSeries.cpp:
#include "Userinterface.h" // include the header where it is required
MoveSeries::MoveSeries(UserInterface *parent) :
QDialog(parent), ui(new Ui::MoveSeries), uiparent(parent)
{
ui->setupUi(this);
uiparent->set-MoveSeries_Delta_Val();
}
It looks like you want to cast the parent to the class you want:
static_cast<UserInterface *>(parent)->get_MoveCurve_Delta();
Bear in mind that this could be dangerous as it makes an assumption about the type of the parent.
If you want only UserInterface be the parent of MoveSeries, say so:
explicit MoveSeries(UserInterface *parent = 0);
If you want any widget to be able to act as the parent, you cannot access UserInterface methods because the parent does not necessarily have them.
Related
I am concerned about making possible a library of widgets developed under Qt 5.9 to be upgraded in the future without having to recompile the code that already uses it. Of course I've started with the PImpl idiom and the Qt version of it described here and here.
However while trying to adapt my code, I came up with the idea, that instead of adding new data members and moving them to a separate private class, I could use the Qt's signal/slot mechanism with lambda functions and have only local variables. Let's illustrate the idea with the following example:
Variant A:
class Foo : public QWidget
{
Q_OBJECT
public:
explicit Foo(QWidget *parent = nullptr);
private:
// A bunch of data members
QPushButton *m_button;
QLineEdit *m_lineEdit;
QCheckBox *m_checkBox;
QString m_str;
private slots:
void on_pushButtonClicked();
void on_checkBoxStateChanged(int state);
};
Foo::Foo(QWidget *parent) :
QWidget(parent),
m_button(new QPushButton("Click me", this));
m_lineEdit(new QLineEdit(this)),
m_checkBox(new QCheckBox(this)),
m_str("Initial text")
{
connect(button, &QPushButton::clicked, this, &Foo::on_pushButtonClicked);
connect(checkBox, &QCheckBox::stateChanged, this, &Foo::on_checkBoxStateChanged);
}
Foo::on_pushButtonClicked()
{
m_str = m_lineEdit->text();
m_lineEdit->setDisabled(m_checkBox->isChecked());
}
Foo::on_checkBoxStateChanged(int state)
{
m_button->setText(state == Qt::Checked ? m_str : "Click me")
}
Variant B:
class Foo : public QWidget
{
Q_OBJECT
public:
explicit Foo(QWidget *parent = nullptr);
};
Foo::Foo(QWidget *parent) : QWidget(parent)
{
QPushButton *button = new QPushButton("Click me", this);
QLineEdit *lineEdit = new QLineEdit(this);
QCheckBox *checkBox = new QCheckBox(this);
QString str("Initial text");
connect(button, &QPushButton::clicked, [=](){
str = lineEdit->text();
lineEdit->setDisabled(checkBox->isChecked());
});
connect(checkBox, &QCheckBox::stateChanged, [=](int state){
button->setText(state == Qt::Checked ? str : "Click me")
});
}
So, for Variant B - apart from being more compact, it does not contain any class data members, so there are no variables to hide, hence no need for a D-pointer. The binary compatibility is still guaranteed though (or is it?), if in the future the constructor is reimplemented with additional local variables used in the same signal/slot manner. Am I right to think this will work or such an approach won't do the trick at all?
Note: For more info about using lambdas as slots in Qt check the comment by #Igor Tandetnik here.
I came up with the idea, that instead of adding new data members and moving them to a separate private class [...]
That's the wrong way to think about it. The interface has no data members. Whatever members you have, go directly into the PIMPL. You don't "move" anything, you don't add them in the wrong place to start with.
Furthermore, heap allocations of members that have the same lifetime as the parent object is a premature pessimization. Store them by value in the PIMPL.
[...] I could use the Qt's signal/slot mechanism with lambda functions and have only local variables
This won't work as soon as you need to store something more than QObject children without abusing the property system.
It's not a flexible approach, and it's really not hard to do it correctly. Qt establishes all the necessary patterns. See this question for some details.
Classes that you don't intend to derive from don't need separate Class_p.h headers. You can add the ClassPrivate definition to the beginning of the Class.cpp file itself.
// Foo.h
#include <QWidget>
class FooPrivate;
class Foo : public QWidget {
Q_OBJECT
Q_DECLARE_PRIVATE(Foo)
QScopedPointer<FooPrivate> const d_ptr;
public:
explicit Foo(QWidget *parent = {});
~Foo();
protected:
Foo(FooPrivate &, QWidget *parent = {}); // for expansion
};
// Bar.h
#include "Foo.h"
class BarPrivate;
class Bar : public Foo {
Q_OBJECT
Q_DECLARE_PRIVATE(Bar)
Q_PROPERTY(int data READ data)
public:
explicit Bar(QWidget *parent = {});
~Bar();
int data() const;
protected:
Bar(BarPrivate &, QWidget *parent = {}); // for expansion
};
// Foo_p.h
#include "Foo.h"
class FooPrivate {
Q_DECLARE_PUBLIC(Foo)
Q_DISABLE_COPY(Foo) // usually desired
Foo * const q_ptr;
public:
QVBoxLayout m_layout{q_ptr};
QPushButton m_button{q_ptr->tr("Hello!")};
QLineEdit m_lineEdit;
QCheckBox m_checkBox{q_ptr->tr("Active")};
void on_pushButtonClicked();
void on_checkBoxStateChanged(int state);
explicit FooPrivate(Foo *);
virtual ~FooPrivate() {} // we're meant to be derived from!
};
// Bar_p.h
#include "Foo_p.h"
#include "Bar.h"
class BarPrivate : public FooPrivate {
Q_DECLARE_PUBLIC(Bar)
public:
int m_data = 44;
explicit BarPrivate(Bar *);
};
// Foo.cpp
#include "Foo_p.h"
Foo::Foo(QWidget * parent) :
Foo(*new FooPrivate(this), parent)
{}
Foo::Foo(FooPrivate & d_ptr, QWidget * parent) :
QWidget(parent),
d_ptr(d_ptr)
{}
Foo::~Foo() {}
FooPrivate::FooPrivate(Foo * q_ptr) :
q_ptr(q_ptr)
{
m_layout.addWidget(&m_button);
m_layout.addWidget(&m_lineEdit);
m_layout.addWidget(&m_checkBox);
connect(&m_button, &QPushButton::clicked, [=]{ on_pushButtonClicked(); });
connect(&m_checkBox, &QCheckBox::stateChanged, [=](int s){ on_checkBoxStateChanged(s); });
}
// Bar.cpp
#include "Bar_p.h"
Bar::Bar(QWidget * parnet) :
Bar(*new BarPrivate(this), parent)
{}
Bar::Bar(BarPrivate & d_ptr, QWidget * parent) :
Foo(d_ptr, parent)
{}
Bar::~Bar() {}
BarPrivate::BarPrivate(Bar * q_ptr) :
FooPrivate(q_ptr)
{}
int Bar::data() const {
Q_D(const Bar);
return d->m_data;
}
I have a class, MainWindow with a pointer to a Canvas, mCanvas...
mainwindow.h...
#include "canvas.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
//snip
private:
Canvas* mCanvas;
};
canvas.h...
class MainWindow;
class Canvas
{
public:
Canvas(MainWindow* parent);
//snip
public slots:
void doSomething();
private:
MainWindow* mParent;
};
Canvas.cpp...
Canvas::Canvas(MainWindow* parent)
{
mParent = parent;
}
void Canvas::doSomething()
{
//snip
}
In MainWindow.cpp, within the MainWindow constructor, I point mCanvas to an Canvas(this). I then attempt to create a new QShortcut with the action Canvas::doSomething().
MainWindow.cpp...
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
new QShortcut(QKeySequence(Qt::Key_BracketLeft),
mCanvas, SLOT(doSomething()) );
However, when I attempt to run the program, I recieve the error NO MATCHING FUNCTION CALL for doSomething(), meaning the compiler does not think that doSomething() exists. In the new QShortcut, I have written mCanvas as mCanvas, *mCanvas, &mCanvas; nothing works.
What is going wrong?
To use signals and slots in Canvas you need to inherit it from QObject (from QWidget in your case) and use Q_OBJECT macro. Also your mCanvas is not initialized before using in new QShortcut ....
Or do something like this:
auto shortcut = new QShortcut(QKeySequence(Qt::Key_BracketLeft), this);
QObject::connect(shortcut, &QShortcut::activated, this, [ this ] { mCanvas->doSomething(); } );
When i try to put QLabel in QWidget class its not work properly (no hover event or click event only the label pixmap is show) only the last instance work properly, when not use set parent, it create in new window for each label but its work correctly
this gif show the problem:
https://media.giphy.com/media/3o7TKKmZSISGXN4Opq/giphy.gif
this is QLabel subclass header:
#include <QObject>
#include <QLabel>
class myLabel : public QLabel
{
Q_OBJECT
public:
myLabel();
protected:
void mousePressEvent(QMouseEvent *);
void enterEvent(QEvent *);
void leaveEvent(QEvent *);
signals :
void labelClicked();
void enterSignal();
void leaveEventSignal();
private:
};
this class to make a labelButton:
#include <QObject>
#include <QWidget>
#include "mylabel.h"
class labelButton : public QWidget
{
Q_OBJECT
public:
labelButton();
//some functions
private slots:
//slots
private:
//private member
};
and this the class that i want to use the labelButtons in:
#include <QWidget>
#include "labelbutton.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
labelButton *b_1, *b_2, *b_3;
};
here is widget.cpp:
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
b_1 = new labelButton;
b_1->setParent(this);
b_1->moveButton(70, 100);
//some functions to initialize the labelButton
b_1->show();
//-----------------------
b_2 = new labelButton;
b_2->setParent(this);
b_2->moveButton(70, 200);
//some functions to initialize the labelButton
b_2->show();
//-----------------------
b_3 = new labelButton;
b_3->setParent(this);
b_3->moveButton(70, 300);
//some functions to initialize the labelButton
b_3->show();
}
here its work, the problem was in passing the parent
i made a function that take a widget and set buttons parent from the function value
b_1 = new labelButton;
//b_1->setParent(this);
b_1->setParentFunc(this);
b_1->moveButton(70, 100);
//some functions to initialize the labelButton
// b_1->show();
in labelButton:
void labelButton::setParentFunc(QWidget *p)
{
myParent = p;
}
mLabel_1->setParent(myParent); // myParent instead of this
I am using Qt and C++, after click on menu item second window appears, and after click on a button in second menu (slot saveData()), I want to change object (obj_map) of class MainMenu. Is it possible, and how to do it the best way? Because I now cannot modify obj_map, because it is in different class. I tried to do something with pointers, but the result was a segmentation fault.
Main Window:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
map obj_map;
public Q_SLOTS:
void saveMap();
private:
Ui::MainWindow *ui;
};
Other window which appears after click in on menu item in main window.
namespace Ui
{
class PreferencesWindow;
}
class PreferencesWindow : public QWidget
{
Q_OBJECT
public:
explicit PreferencesWindow(QWidget *parent = 0);
public Q_SLOTS:
void saveData();
private:
Ui::PreferencesWindow *uip;
};
From here I need to change obj_map
void PreferencesWindow::saveData()
{
// FROM HERE I NEED TO CHANGE obj_map
}
Preferences object is created in a slot:
void MainWindow::saveMap()
{
PreferencesWindow *p = new PreferencesWindow();
p->show();
}
You could use signals and slots: when saveData() is called, emit a signal, like emit saveDataClicked() and catch that signal in the MainWindow with a slot called change_obj_map. There, you can do your changes.
So, in MainWindow you can write:
connect (PreferencesWindow, SIGNAL(saveDataClicked()), this, SLOT(change_obj_map());
and then in the slot:
void change_obj_map()
{
// Do your changes here
}
Another way is having a local obj_map in PreferencesWindow that is a pointer to the address of obj_map in MainWindow. So, when you create PreferencesWindow, you can just pass the address of MainWindow's obj_map to the constructor and assign that address to the local variable obj_map.
As PreferencesWindow objects are created by MainWindow, the easiest is to have PreferencesWindow objects store a pointer to MainWindow:
class MainWindow;
class PreferencesWindow : public QWidget
{
Q_OBJECT
public:
explicit PreferencesWindow(MainWindow *parent = 0);
public Q_SLOTS:
void saveData();
private:
Ui::PreferencesWindow *uip;
MainWindow* m_mainwindow;
};
Pass the pointer upon construction:
void MainWindow::saveMap()
{
PreferencesWindow *p = new PreferencesWindow( this );
p->show();
}
Then use it:
PreferencesWindow::PreferencesWindow(MainWindow *parent) :
QWidget( parent ),
m_mainwindow( parent )
{
}
void PreferencesWindow::saveData()
{
// FROM HERE I NEED TO CHANGE obj_map
m_mainwindow->obj_map.....it's accessible!
}
I need to simulate mouse click on UI button using QTest but I can't figure out how to access it.
I've got a MediaPanel class :
class PhMediaPanel : public QWidget
{
Q_OBJECT
public:
explicit PhMediaPanel(QWidget *parent = 0);
//... a lot of functions
private:
Ui::PhMediaPanel *ui;
};
And a MediaPanelTest :
#include "MediaPanelTest.h"
#include <QObject>
class MediaPanelTest : public QObject
{
Q_OBJECT
public:
explicit MediaPanelTest(QObject *parent = 0);
private slots:
//The tests
};
So how can I simulate button click on Ui::PhMediaPanel *ui member?
Try the following approach:
BUTTONCLASS* button = WIDGET->findChild<BUTTONCLASS*>("name of the button");
As far is i know this should give you the widget without exposing the UI pointer.