Qt/C++ - Call of overriden method from derived class - c++

I have the following code:
void AppMPhase::closeEvent(QCloseEvent *closeEvent) {
QMessageBox* dialog = new QMessageBox(this);
dialog->setText("Warning: Initial configuration changed\nDo you want to restore it ?");
dialog->setIcon(QMessageBox::Warning);
dialog->addButton(QMessageBox::Yes);
dialog->addButton(QMessageBox::No);
connect(dialog, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(restoreInitialConfig(QAbstractButton*)));
dialog->exec();
}
void AppMPhase::restoreInitialConfig(QAbstractButton *button) {
if(!button->text().compare(QString("Yes"))) {
// restore Config
}
else {
// don't restore
}
MainWindow::closeEvent(closeEvent);
}
with AppMPhase the derived class of MainWindow
I would like to call the method closeEvent of the base class MainWindow in the "restoreInitialConfig" method, to close the window after we restore the config.
Is it possible ? it's different from the other questions I have seen because the method closeEvent is overriden in the AppMPhase class.
the AppMPhase class:
class AppMPhase : public QtUi::MainWindow
{
Q_OBJECT
public:
AppMPhase(QWidget *const parent = Q_NULLPTR, const Qt::WindowFlags flags = 0);
~AppMPhase();
int readConfigFromExternFile(QString path);
int readCalibrationDate(QString path);
QSize sizeHint() const Q_DECL_OVERRIDE;
QtWrapperTestManager * testManager;
public Q_SLOTS:
void show();
public slots:
void currentTestFinished();
void createTest(unsigned int,QString);
void restoreInitialConfig(QAbstractButton* button);
signals:
void notifyPageTestCurrentTestFinished();
private:
enum AppPage
{
PAGE_START,
PAGE_ABOUT
};
bool isTestMangaerCreated;
std::map<QString, std::map<std::string, std::string> > conversion_Table_Cable_Ref_sensorParamMap;
Pages::GenericAppPage * appPage(const int index) const;
QToolButton * appPageButton(const int index) const;
virtual void closeEvent(QCloseEvent *closeEvent) Q_DECL_OVERRIDE;
The MainWindow class:
class SHARED_EXPORT_LIB_QT_UI MainWindow : public QMainWindow
{
Q_OBJECT
signals:
void aboutToClose();
public slots:
virtual void show();
private slots:
void changeLanguage(const QString &language);
public:
MainWindow(QWidget *const parent = Q_NULLPTR, const Qt::WindowFlags flags = 0);
virtual ~MainWindow();
protected:
void showCopyright(const QString &copyRightHeader);
void showLanguageSelector(const QStringList &languages);
void setupUi(const MainPageList &pageList);
void setupUi(QWidget *centerWidget = Q_NULLPTR);
virtual void closeEvent(QCloseEvent *closeEvent) Q_DECL_OVERRIDE;
const Ui::MainWindow *const _ui;
MainPageItemList _mainPageItemList;
};
Thanks in advance.
Flo

There is a far easier way to achieve what you're wanting to do, without having to use signals and slots, and call base class functions from your slot.
It is possible to do the restoration directly from within your closeEvent handler.
This is made possible by the fact that QMessageBox::exec returns an integer code which matches one of the values in the StandardButton enum, depending on what button was pressed.
That then allows you to call restoreInitialConfig directly from within your closeEvent handler, as you know which button was pressed.
void AppMPhase::closeEvent(QCloseEvent* ev)
{
int res = QMessageBox(
QMessageBox::Icon::Warning,
"Restore configuration?",
"Warning: Initial configuration changed\nDo you want to restore it?",
QMessageBox::Yes | QMessageBox::No,
this).exec();
if (res == QMessageBox::Yes)
restoreInitialConfig();
MainWindow::closeEvent(ev);
}
Note that this also simplifies your restoreInitialConfig function, as there is no need to check button text, you know the answer was yes.
Note also I made use of this QMessageBox constructor which makes it very easy to create simple message boxes.

Related

How to link a particular function in SLOT

This is my Wavefrontrenderer class.
Class WavefrontRenderer : public QMainWindow , private
Ui::WavefrontRendererClass
{
Q_OBJECT
//Q_PROPERTY( QColor m_color READ m_color NOTIFY colorChanged)
public:
WavefrontRenderer(TreeModel* model , QWidget *parent = Q_NULLPTR);
void iterate(const QModelIndex & index, const QAbstractItemModel * model);
void render();
void RenderTreeElement(QModelIndex index);
private:
//Ui::WavefrontRendererClass ui;
TextureManager textureManager;
TextureManagerCubeMap textureManagerCubeMap;
QColor m_color;
void FillComboBox();
private slots:
void PositionXYZ();
};
/////////////////////////////////////////////////////////////////////////////////
WavefrontRenderer::WavefrontRenderer(TreeModel* model , QWidget *parent) :
QMainWindow(parent)
{
setupUi(this);
treeView->setModel(model);
treeView->setDragEnabled(true);
treeView->setAcceptDrops(true);
treeView->installEventFilter(this);
connect(doubleSpinBoxPositionX, SIGNAL(valueChanged(double)), this ,
SLOT(PositionXYZ()));
}
/////////////////////////////////////////////////////////////////////////////////
I am creating controls at runtime from another class to which i pass the Wavefrontrenderer class as a pointer.
void Container::CreateUI(QHBoxLayout* layout)
{
wavefrontrenderer // Pointer defined as a private member
QDoubleSpinBox *PositionXSpinBox = new QDoubleSpinBox;
PositionXSpinBox->setRange(-10000, 10000);
PositionXSpinBox->setSingleStep(.1);
PositionXSpinBox->setValue(x);
layout->addWidget(PositionXSpinBox);
bool ok = QObject::connect(PositionXSpinBox,
SIGNAL(valueChanged(double)), wavefrontrenderer , SLOT(print()));
qDebug() << "The slot is connected =" << ok;
}
I have defined print as a public slot member in Container class.
The issue is that the connect tries to locate print() function in WavefrontRenderer class rather than Container class.
How can i make connect call the print() funtion of the Container class.

Using the autogenerated Ui for both sender and receiver with qt

I need to call a method after the ui has been shown,so i want to connect
the frame with itself,in particular using the show signal.
I've created a new form with auto generated code by qtcreator.This is the auto generated header.
#define STARTWINDOW_H
#include <QMainWindow>
namespace Ui {
class StartWindow;
}
class StartWindow : public QMainWindow
{
Q_OBJECT
public:
explicit StartWindow(QWidget *parent = 0);
~StartWindow();
private:
Ui::StartWindow *ui;
public slots:
void doSomething();
};
#endif // STARTWINDOW_H
in the cpp file no one of the following codes work
connect(ui,SIGNAL(QEvent::Show),this,SLOT(doSomething()));
connect(*ui,SIGNAL(QEvent::Show),this,SLOT(doSomething()));
connect(this->ui,SIGNAL(QEvent::Show),this,SLOT(doSomething()));
What's the right way to do it?
That signal does not exist by default, we must create it, we can override the showEvent() method:
.h
protected:
void showEvent(QShowEvent *event);
signals:
void showSignal();
.cpp
connect(this, &StartWindow::showSignal, this, &StartWindow::doSomething);
void StartWindow::showEvent(QShowEvent *event)
{
emit showSignal();
QMainWindow::showEvent(event);
}
void StartWindow::doSomething()
{
qDebug()<<"show";
}
Or you can override the eventFilter method.
.h
protected:
bool eventFilter(QObject *watched, QEvent *event);
signals:
void showSignal();
.cpp
installEventFilter(this);
connect(this, &StartWindow::showSignal, this, &StartWindow::doSomething);
bool StartWindow::eventFilter(QObject *watched, QEvent *event)
{
if(watched==this && event->type() == QEvent::Show)
emit showSignal();
return QMainWindow::eventFilter(watched, event);
}
There are a few things wrong here:
There is no show() signal and
Even if there were, you aren't using connect correctly.
First, if your class were defined like this:
namespace Ui { class MainWindow; }
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
signals:
void someSignal();
public slots:
void doSomething() {}
private:
Ui::MainWindow *ui;
};
The appropriate call to connect in the constructor would be:
QWidget::connect(this, SIGNAL(someSignal()), this, SLOT(doSomething()));
Even if there were a show signal, you wouldn't get it from ui, you would get it from this. The UI classes are just dumb containers for widgets that you add through the designer.
To perform some action when your class is shown, you can either override
virtual void showEvent(QShowEvent *); (more robust, but slightly more complex)
or simply define your own show() slot that does what you want and calls QWidget::show() at the end of it. I prefer the latter, so I will show you that.
Start by defining your show slot like this:
namespace Ui { class MainWindow; }
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void doSomething() {}
void show();
private:
Ui::MainWindow *ui;
};
Then, in your implementation file, do this:
void MainWindow::show()
{
doSomething();
QWidget::show();
}
I have worked with the Qt framework for quite some time now, and I have never needed to override the show event; it is simply not worth it for most use cases. If you really want a show signal that others can connect to, just add a custom signal for it and emit in in MainWindow::show(). Only resort to overriding event handlers if you can't make this work for what you are doing(very rarely necessary).

QT extend MainWindow to other class or diffrent way

I have class printrectangle
class PrintRectangle : public QWidget
{
Q_OBJECT
public:
explicit PrintRectangle(QWidget *parent = 0);
private:
void resetClickedIndex();
void updateIndexFromPoint( const QPoint& point);
public:
int mXIndex;
int mYIndex;
QVector<QPoint> points;
bool clicked[5][5] = {};
teacher tech;
perceptron p[5][5];
double techconst = 0.1;
signals:
public slots:
protected:
void paintEvent(QPaintEvent *);
void mousePressEvent(QMouseEvent *eventPress);
};
and MainWindow
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_learn_clicked();
void on_classify_clicked();
private:
Ui::MainWindow *ui;
};
When I click button I call to on_learn_clicked() function. I would like to transfer clicked[5][5] array into on_learn_clicked becasue I send this array to other object when user click button. How to do this?
It is not clear what is exactly the relation between MainWindow and the PrintRectangle widget. I suppose the button signal and PrintRectangle slot are connected somewhere in the MainWindow implementation.
One way to solve the problem would be to use to use the QSignalMapper as #Noidea stated.
Another way would be to use a lambda as a slot when connecting. This way you could capture the sender/receiver or other objects in scope and use their members.
You can find some information about the connect syntax in New Signal Slot Syntax
But basically you could write something like:
connect(button, &QPushButton::clicked, this, [this, printRectangle]()
{
// do smth with clicked[5][5] from printRectangle or just
// retrieve it and call another method like:
// this->processClicked(printRectangle->clicked);
// or pass it to another object
}
This way you could modify your on_classify_clicked slot to a regular method with bool[5][5] argument to do the processing.

"Reparent" classes from compiled code

Following case:
Let's say there is a binary library which defines the class "Base", and many subclasses ("Derivative1", "Derivative2" etc) of it.
I want to extend these subclasses in my own code, but because my extensions are the same for all subclasses as they only deal with parts of Base, it would be tedious to subclass every Derivative class and add the same code over and over again.
My first idea was to simply write a class template which would do the work for me, but because the library I'm dealing with is Qt, QObject has foiled me.
My second idea was to use macros to generate each class structure, but this was also thwarted by moc.
The "reparent" in the title is because I thought of deriving from Base and creating BaseExtended, and then somehow tell the compiler to reparent every Derivative to this extended class. Isn't there a way to for example declare the "Base" in "BaseExtended" virtual, and then just write
class Derivative1Extended : public Derivative1, public BaseExtended {}
and have the virtual Base in BaseExtended point to the Base in Derivative1, thus basically "squeezing ing" my extensions between Base and Derivative1?
(By the way, I tried to keep the above as generic as possible, but what I'm actually doing is trying add signals for "focusIn" and "focusOut" to every QWidget derivative without writing the same code over and over again for every QWidget subclass I use)
EDIT:
For reference, here's my current implementation:
// qwidgetfs.h
class QLineEditFS : public QLineEdit
{
Q_OBJECT
private:
void focusInEvent(QFocusEvent *);
void focusOutEvent(QFocusEvent *);
public:
QLineEditFS(QWidget *parent = 0);
signals:
void focusReceived(QWidgetFS::InputType);
void focusLost();
};
// qwidgetfs.cpp
QLineEditFS::QLineEditFS(QWidget *parent /*= 0*/)
: QLineEdit(parent)
{}
void QLineEditFS::focusInEvent(QFocusEvent *e)
{
QLineEdit::focusInEvent(e);
emit focusReceived(QWidgetFS::InputText);
}
void QLineEditFS::focusOutEvent(QFocusEvent *e)
{
QLineEdit::focusOutEvent(e);
emit focusLost();
}
And this repeated for QSpinBoxFS, QComboBoxFS, QCheckBoxFS and so on...
Instead I would like to just define this logic in a common class QWidgetFS, and then "inject" it into other classes derived from QWidget
I'm not sure you'll really be able to do what you are suggesting without modifying Qt and recompiling it.
Perhaps to do what you want, you could use event filters installed on the objects that you want to handle focus events from?
little test app:
header:
class FocusEventFilter : public QObject
{
Q_OBJECT
public:
FocusEventFilter(QObject* parent)
: QObject(parent)
{}
Q_SIGNALS:
void focusIn(QWidget* obj, QFocusEvent* e);
void focusOut(QWidget* obj, QFocusEvent* e);
protected:
bool eventFilter(QObject *obj, QEvent *e);
};
class testfocus : public QMainWindow
{
Q_OBJECT
public:
testfocus(QWidget *parent = 0, Qt::WFlags flags = 0);
~testfocus();
public Q_SLOTS:
void onFocusIn(QWidget*, QFocusEvent*);
void onFocusOut(QWidget*, QFocusEvent*);
private:
Ui::testfocusClass ui;
};
Implementation
#include <QFocusEvent>
#include "testfocus.h"
bool FocusEventFilter::eventFilter(QObject *obj, QEvent *e)
{
if (e->type() == QEvent::FocusIn) {
bool r = QObject::eventFilter(obj, e);
QFocusEvent *focus = static_cast<QFocusEvent*>(e);
QWidget* w = qobject_cast<QWidget*>(obj);
if (w) {
emit focusIn(w, focus);
}
return r;
}
else if (e->type() == QEvent::FocusOut) {
bool r = QObject::eventFilter(obj, e);
QFocusEvent *focus = static_cast<QFocusEvent*>(e);
QWidget* w = qobject_cast<QWidget*>(obj);
if (w) {
emit focusOut(w, focus);
}
return r;
}
else {
// standard event processing
return QObject::eventFilter(obj, e);
}
}
testfocus::testfocus(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
FocusEventFilter* filter = new FocusEventFilter(this);
ui.lineEdit->installEventFilter(filter);
ui.lineEdit_2->installEventFilter(filter);
connect(filter, SIGNAL(focusIn(QWidget*, QFocusEvent*)), this, SLOT(onFocusIn(QWidget*, QFocusEvent*)));
connect(filter, SIGNAL(focusOut(QWidget*, QFocusEvent*)), this, SLOT(onFocusOut(QWidget*, QFocusEvent*)));
}
testfocus::~testfocus()
{
}
void testfocus::onFocusIn(QWidget* obj, QFocusEvent*)
{
obj->setStyleSheet("background-color:#aaaaff;");
}
void testfocus::onFocusOut(QWidget* obj, QFocusEvent*)
{
obj->setStyleSheet("background-color:#ffaaaa;");
}
Of course, YMMV. You could always have a separate filter per object. This method means you can avoid deriving from everything. Not as efficient but it should work.
You may be able to do what you want in the event filter itself rather than using signals/slots.
I have done stuff like this in the past with templates. The problem is that you can't use signals.
I'm typing this up without a compiler so please be kind :):
template<typename T>
class FSWidget: public T
{
public:
FSWidget()
{
_delegate = NULL;
}
setDelegate(FSDelegate *delegate)
{
_delegate = delegate;
}
protected:
virtual void focusInEvent(QFocusEvent *e)
{
T::focusInEvent(e);
if (_delegate) {
_delegate->focusInEvent(this);
}
}
virtual void focusOutEvent(QFocusEvent *e)
{
T::focusOutEvent(e);
if (_delegate) {
_delegate->focusOutEvent(this);
}
}
private:
FSDelegate *_delegate;
};
So, the advantage is when you need to use this you can basically create a class like this:
FSWidget<QLineEdit *> lineEdit = new FSWidget<QLineEdit *>;
lineEdit->setDelegate(delegate);
You can put in whatever you want instead of QLineEdit and it will work.
And then teh FSDelegate could be just an interface that you mix into whatever class needs to act on the info. It could be one of these:
class FSDelegate
{
public:
virtual void focusInEvent(QWidget *w) = 0;
virtual void focusOutEvent(QWidget *w) = 0;
};
If you're always doing the same thing in on focusInEvent and focusOutEvents, you can implement these functions and make a real Mixin class.
Hopefully this can avoid some code duplication for you.

How to connect focus event from QLineEdit?

I have to connect focus event from some QLineEdit element (ui->lineEdit) to the method focus(). How can I do this?
There is no signal emitted when a QLineEdit gets the focus. So the notion of connecting a method to the focus event is not directly appropriate.
If you want to have a focused signal, you will have to derive the QLineEdit class. Here is a sample of how this can be achieved.
In the myLineEdit.h file you have:
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
MyLineEdit(QWidget *parent = 0);
~MyLineEdit();
signals:
void focussed(bool hasFocus);
protected:
virtual void focusInEvent(QFocusEvent *e);
virtual void focusOutEvent(QFocusEvent *e);
};
In the myLineEdit.cpp file you have :
MyLineEdit::MyLineEdit(QWidget *parent)
: QLineEdit(parent)
{}
MyLineEdit::~MyLineEdit()
{}
void MyLineEdit::focusInEvent(QFocusEvent *e)
{
QLineEdit::focusInEvent(e);
emit(focussed(true));
}
void MyLineEdit::focusOutEvent(QFocusEvent *e)
{
QLineEdit::focusOutEvent(e);
emit(focussed(false));
}
You can now connect the MyLineEdit::focussed() signal to your focus() method (slot).
I assume you mean connect as in signals/slots, focus event isn't a signal it's a virtual method you have to override in order to change the behavior:
http://doc.qt.io/qt-5/qlineedit.html#focusInEvent