In order to react to an event in the Qt framework I have reimplemented a Qt class (QLabel), i.e. its default constructor with a single argument. Since that gave an error, I also reimplemented the constructor with an additional argument. Now it works.
Class:
class myLabel : public QLabel
{
Q_OBJECT
public:
explicit myLabel(QWidget *parent = 0);
explicit myLabel(QString x, QWidget *parent = 0);
void mousePressEvent( QMouseEvent* e );
signals:
void clicked();
};
Constructors:
myLabel::myLabel(QWidget *parent) : QLabel(parent)
{
}
myLabel::myLabel(QString x, QWidget *parent) : QLabel(parent)
{
setText(x);
}
My (beginner) question is: why isn't the respective constructor of the base class run, as with all other methods [of the base class (e.g. I can use setText() without reimplementing it)]?
And the extreme: why do I need to reimplement a constructor at all, although it does not contain any code?
Edit:
Before posting, I was not sure what to search for, but this question has essentially been answered in https://stackoverflow.com/a/347362/1619432
Edit:
As bartimar pointed out, the constructor is not empty in that it calls the base class' constructor.
This can apparently be done with passing the respective parameters like so:
myLabel::myLabel( const QString& x, QWidget* parent, Qt::WindowFlags f ) :
QLabel( x, parent, f ) {}
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 difficulties in understanding how to pass parent object to child.
In Qt, I have a MainWindow class and a DoSomething() function. Then I created a Job object within MainWindow and tried to call DoSomething within Job's DoItNow() function. But I just don't know how to do it.
MainWindow.h
class Job;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
int value;
void DoSomething();
private:
Job *job;
}
MainWindow.cpp
#include "mainwindow.h"
#include "job.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
job = new Job(this); // passing this pointer to child
}
void MainWindow::DoSomething() { // do something }
Job.h
class Job : public QObject
{
Q_OBJECT
private:
void DoItNow();
public:
explicit CDMcommand(QObject *parent = 0);
}
Job.cpp
#include "job.h"
#include "mainwindow.h"
Job::Job(QObject *parent) : QObject(parent)
{
// some setups
parent->value = 0; // this is not working
}
void Job::DoItNow()
{
parent->DoSomething(); // What is the pointer to MainWindow instance?
}
How to access non-static public register in *parent?
How to pass *parent to function in job instance?
Maybe I missunderstand the question, but I think you are a bit confused about inheritance. Your Job is a child class of QObject and MainWindow indirectly inherits also form QObject, but there is no direct relation between MainWindow and Job. I am not too familiar with Qts signal and slot mechanism, which is probably the way to go here, but maybe I can offer you a different solution:
Job::Job(QObject *parent) : QObject(parent)
{
// some setups
parent->value = 0; // this is not working
}
This is not working, because QObject has no member called value. If you can live with Jobs constructor not taking a QObject* as parameter, then just declare a
MainWindow* parentWindow;
as a private member in Job and change the constructor to
Job::Job(MainWindow *parentWindow) : QObject(parentWindow)
{
// some setups
parentWindow->value = 0; // this will work now
}
then also
void Job::DoItNow()
{
parentWindow->DoSomething();
}
will work without problems.
How can I call the Qt 'parent' object method from the 'child'
object method?
The safe and simple way to do it:
void Job::DoItNow()
{
// first evaluate the pointer: is that of type we expect?
MainWindow* pMainWindow = qobject_cast<MainWindow*>(parent());
if (pMainWindow)
pMainWindow->DoSomething(); // MainWindow::DoSomething must be exposed to class Job
}
But of course making two classes dependent on each other too much is a violation of OOP principles: these two objects become tightly coupled now. And there is already a good suggestion in comments: use an explicit signal-slot mechanism for that or providing the interface to interact between decoupled objects.
I am attempting to subclass a QLabel using a header file and I get the error on constructor
IntelliSense: indirect nonvirtual base class is not allowed
class foo : public QLabel
{
Q_OBJECT
foo(QWidget* parent = 0) : QWidget(parent)
{
}
void mouseMoveEvent( QMouseEvent * event )
{
//Capture this
}
};
Any suggestions why this is happening and how I can fix it ?
The problem is here:
foo(QWidget* parent = 0) : QWidget(parent)
You are inheriting from QLabel, but you specify QWidget for the base. You should write this intead:
explicit foo(QWidget* parent = Q_NULLPTR) : QLabel(parent)
// ^^^^^^
Also, please use explicit for that constructor as well as Q_NULL_PTR or at least NULL instead of 0.
I'm a Qt newbie and all I'm trying to do is create a custom QLineEdit class with a few customizations (default alignment and default text). Right now I'm just trying to establish a base class, inheriting only QWidget. This is what I have (very bad code I know):
userText (utxt.h):
#ifndef UTXT_H
#define UTXT_H
#include <QWidget>
#include <QLineEdit>
class utxt : public QWidget
{
Q_OBJECT
public:
explicit utxt(QWidget *parent = 0);
QString text () const;
const QString displayText;
Qt::Alignment alignment;
void setAlignment(Qt::Alignment);
signals:
public slots:
};
#endif // UTXT_H
utxt.cpp:
#include "utxt.h"
utxt::utxt(QWidget *parent) :
QWidget(parent)
{
QString utxt::text()
{
return this->displayText;
}
void utxt::setAlignment(Qt::Alignment align)
{
this->alignment = align;
}
}
I know this is really wrong, and I keep getting "local function definition is illegal" errors on the two functions in utxt.cpp. Can someone please point me in the right direction? I'm just trying to create a custom QLineEdit to promote my other line edits to.
QLineEdit already has the alignment that can be set and also placeholderText.
LE: As I said there is no need to inherit from QLineEdit (or QWidget) for this functionality, but if you really want to do it you can just create your class and code a constructor that takes the parameters you want and call QLineEdit's functionality with that, something like:
//in the header
//... i skipped the include guards and headers
class utxt : public QLineEdit
{
Q_OBJECT
public:
//you can provide default values for all the parameters or hard code it into the calls made from the constructor's definition
utxt(const QString& defaultText = "test text", Qt::Alignment align = Qt::AlignRight, QWidget *parent = 0);
};
//in the cpp
utxt::utxt(const QString& defaultText, Qt::Alignment alignement, QWidget *parent) : QLineEdit(parent)
{
//call setPlaceHolder with a parameter or hard-code the default
setPlaceholderText(defaultText);
//same with the default alignement
setAlignment(alignement);
}
I'm studying the Qt4 library and I want to add some functionality to all the children of QWidget in my project. I need all widgets to have mousePressEvent overridden. Obviously I do not need to override it in every particular widget I use(I use many of them and I they to follow DRY rule) , instead I create a Foo class:
class Foo : public QWidget
{
Q_OBJECT
protected:
/* implementation is just a test */
virtual void mousePressEvent(QMouseEvent*) { this->move(0,0); }
};
And derive my button from it:
class FooButton : public QPushButton , public Foo
{
public:
FooButton (QWidget* parent) : QPushButton(parent) { };
};
But the event seems to be not overridden... What am I doing wrong?
Thanks in advance.
For the mousePressEvent access, try QObject::installEventFilter().
http://doc.qt.digia.com/stable/qobject.html
You are inheriting twice now from QWidget. This is problematic (see diamond problem).
Instead, drop your Foo class and move your custom mouse press event handler to your FooButton class:
class FooButton : public QPushButton
{
Q_OBJECT
protected:
/* implementation is just a test */
virtual void mousePressEvent(QMouseEvent*) { this->move(0,0); }
public:
FooButton (QWidget* parent) : QPushButton(parent) { };
};
If this doesn't suit the design of your application, then try using virtual inheritance instead. That is, change Foo to:
class Foo : public virtual QWidget
If that doesn't help, you should follow the advice of the other answers and install an event handler.
(You can read about virtual inheritance in its Wikipedia article.)
I suspect that the problem is that you're inheriting from QWidget twice, once through QPushButton and once through Foo.
From the way you phrased the question, I'm assuming that you want to do this for varying kinds of widgets, and thus don't want to have to subclass QPushButton, QLabel, QCheckBox, etc. If this is not the case then you should use Nikos's answer.
If not, your best bet is probably doing to be to use an event filter.
class MousePressFilter : public QObject {
Q_OBJECT
public:
MousePressFilter(QObject *parent) : QObject(parent) { }
protected:
bool eventFilter(QObject *watched, QEvent *event) {
QWidget *widget = dynamic_cast<QWidget*>(watched);
widget->move(0,0);
return false;
}
};
And then in your Foo class constructor:
class Foo {
Foo() {
installEventFilter( new MousePressFilter(this) );
}
};