I recently started programming in C ++ and am having some difficulties in relation to the exchange of data between classes.
I searched many tutorials and examples, but none worked. I finally decided to ask for help because I do not know what do ...
PS: I want to call keyPressEvent function from my B (solEditor) class
thanks.
addons/soleditor.h (class)
#include <Qsci/qsciscintilla.h>
#include <QWidget>
#include <QKeyEvent>
class Editor; // main class
class solEditor : public QsciScintilla
{
public:
explicit solEditor(QWidget *parent = 0);
Editor editor; // error <<
protected:
void keyPressEvent(QKeyEvent *e);
};
editor.h (main window)
#include <QMainWindow>
#include "about.h"
#include "data.h"
#include "addons/codeeditor.h"
#include "addons/highlighter.h"
#include "addons/soleditor.h"
#include "plugins/headergenerator.h"
#include "plugins/updatescreen.h"
namespace Ui {
class Editor;
}
class solEditor;
class Editor : public QMainWindow
{
Q_OBJECT
solEditor *sE;
public:
QsciScintilla* ce;
Highlighter *Hl;
solEditor *e;
Ui::Editor *ui;
explicit Editor(QWidget *parent = 0);
~Editor();
public slots:
void on_KeyPress(QKeyEvent *e);
};
Error:
SOLEditor\addons\soleditor.h:14: error: C2079: 'solEditor::editor' uses undefined class 'Editor'
You are using a forward declaration
class Editor; // main class
with a local instance of that class
Editor editor; // error <<
Unfortunately, that is not possible, as in this case the compiler needs to know the full details of the Editor class.
There are two possible solutions:
Make the member a pointer: Editor* editor
Use an #include instead of a forward declaration.
If you want to make your code flexible, you could do it like this:
class solEditor : public QsciScintilla
{
public:
explicit solEditor(Editor* editor, QWidget* parent = 0);
inline Editor* editor() const { return _editor; }
private:
Editor* _editor;
}
and in the cpp file:
solEditor::solEditor(Editor* editor, QWidget* parent)
// TODO: call parent constructor
{
_editor = editor;
}
solEditor::~solEditor()
{
_editor = NULL;
}
You can then create a solEditor instance like this:
QWidget* optionalParentWidget = GetParentWidgetFromSomewhere();
Editor* editor = GetEditorInstanceFromSomewhere(); // or create it yourself
solEditor* myEditor = new solEditor(editor, optionalParentWidget);
(As a side node, classes in C++ usually start with a capital letter: QWidget, Editor, SolEditor. That makes it easier to spot if something is a class, a function or a variable).
About the key press event: If you want one class to handle certain events of another class, it's best to use the eventFilter mechanism:
http://qt-project.org/doc/qt-5/qobject.html#installEventFilter
Related
We are developing in C++ (and Qt) using Visual Studio 2015 and the Qt Designer for our UI (via Form / .ui files).
We now need to share some Common Data between our UI elements (e.g. most recently used paths etc.) and I would like to do this via dependency injection (i.e. providing the UI with a Reference to the common object during construction) instead of e.g. (ab)using the singleton pattern.
Has someone faced (and solved) similar problems, and is there a sensible way to do this?
Update (to elaborate):
For example I have a custom FooWidget which I wish to use in my FooDialog.ui form file.
// My custom Widget
class FooWidget : public QWidget {
Q_OBJECT
public:
FooWidget(QWidget* parent);
//...
}
// The FooDialog class (scaffolding created by Qt Designer)
class FooDialog : public QDialog {
Q_OBJECT
public:
FooDialog(QWidget* parent) : QDialog(parent), ui (new Ui::FooDialog()) {
ui->setupUp(this);
//...
}
private:
Ui::FooDialog* ui;
}
// The Ui::FooDialog class autogenerated(!) by Qt Designer
// I cannot (must not) change this code, as it will be regenerated every time
class Ui_FooDialog {
public:
FooWidget* widget;
void setupUi(QWidget *fooDialog) {
//...
widget = new FooWidget(fooDialog);
//...
}
}
namespace Ui { class ScannerStatus: public Ui_ScannerStatus {}; }
I would like to provide the FooWidget with a common data object (e.g. text size and colours shared across all my Ui classes), but I can't do so in the constructor (since the autogenerated Ui_FooDialog treats FooWidget as a generic QWidget, which only needs/takes a QWidget* parent in the constructor - I cannot provide a pointer or reference to my shared TextColourAndSize object.
I am aware I could create a second ui->widget->setupTextColourAndSize(...) step in FooDialog (after the initial ui->setupUi(this)) which provides that common data object, but having two init() type functions seems like a rather bad code smell (one is bad enough).
FooWidget needs two constructors, and a setter for the dependency:
explicit FooWidget(QObject *parent = nullptr) : QWidget(parent), … {
…
}
FooWidget(Dependency *dep, QObject *parent = nullptr) : FooWidget(parent) {
setDependency(dep);
}
void setDependency(Dependency *dep) {
…
}
Then you’d set the dependency after the widget is constructed:
FooDialog(Dependency *dep, …) … {
setupUi(this);
ui->fooWidget->setDependency(dep);
}
This could be automated: the parent widget can have a property that holds the pointer to the dependency, and the child widgets can find it automatically:
FooDialog(Dependency *, …) : … {
setProperty("dependency", dep);
setupUi(this);
}
FooWidget(QWidget *parent) : … {
auto *dep = parent() ? parent()->property("dependency").value<Dependency*>() : nullptr;
if (dep) setDependency(dep);
}
This will work with no extra effort if Dependency derives from QObject. Otherwise, you’ll need to have the following in a suitable header file:
class Dependency { … };
Q_DECLARE_METATYPE(Dependency*)
In all circumstances, you do need to promote the fooWidget object to FooWidget class within Qt Designer.
Ok from what I'm seeing you do not need "dependency injection". Question was incorrectly stated.
You can use this custom widget directly from Qt designer.
When you create your FooDialog place regular widget QWidget in place where you need to have a FooWidget.
Then "promote" regular this widget to FooWidget (possibly you have to add some simple information about that type) - (I did that long time ago and do not remember all details).
For detailed instruction just google: qt promote widget qt designer, you will find lots of examples how to do it.
These were good solutions, but talking about dependency injections, there is also an option to have some fun with C++. It's not a wise solution at all, of course I know it, but nevertheless...
foowidget.h
#ifndef FOOWIDGET_H
#define FOOWIDGET_H
#include <QWidget>
class Something
{
public:
QString getHello() const
{ return "Hello world!"; }
};
/***************************************************/
template<typename T>
class Injector
{
public:
QString getHello() const
{ return m_dataContainer.getHello(); }
private:
T m_dataContainer;
};
/***************************************************/
class FooWidget : public QWidget, public Injector<Something>
{
Q_OBJECT
public:
explicit FooWidget(QWidget* parent = nullptr);
protected:
virtual void mousePressEvent(QMouseEvent*) override;
};
#endif // FOOWIDGET_H
foowidget.cpp
#include "foowidget.h"
#include <QMessageBox>
FooWidget::FooWidget(QWidget *parent)
: QWidget(parent)
{ }
void FooWidget::mousePressEvent(QMouseEvent*)
{
QMessageBox::information(nullptr, "Test", getHello());
}
foodialog.h
#ifndef FOODIALOG_H
#define FOODIALOG_H
#include <QDialog>
class SomethingElse
{
public:
QString getHello() const
{ return "OMG! OMG"; }
};
#include "foowidget.h"
namespace Ui {
class FooDialog;
}
class FooDialog : public QDialog, public Injector<SomethingElse>
{
Q_OBJECT
public:
explicit FooDialog(QWidget *parent = nullptr);
~FooDialog();
protected:
void showEvent(QShowEvent *) override;
private:
QScopedPointer<Ui::FooDialog> ui;
};
#endif // FOODIALOG_H
foodialog.cpp
#include "foodialog.h"
#include "ui_foodialog.h"
#include <QMessageBox>
FooDialog::FooDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::FooDialog)
{
ui->setupUi(this);
}
FooDialog::~FooDialog()
{ }
void FooDialog::showEvent(QShowEvent *)
{
QMessageBox::information(nullptr, "Test", getHello());
}
Multiple inheritance + deriving widgets from some small template proxy class works for both custom widgets and those, having UI forms. I've put a FooWidget on a FooDialog (via propagation mechanizm) in the sketch above and got two message boxes.
The idea itself can be implemented better, with smarter template usage, just tried to reduce sample code, anyway it's an unnessesary complication. But technically it works without any additional initializations =)
I am new in C++ Qt and struggling with the correct use of forward declarations and #include.
What I want to do:
I have a Qt Gui (Class Ui::Gui) where we can set values.
I want to save these values in Gui Class variables.
As soon as a button (Generate Xml) is clicked, I want to pass the object
'ui' to the XmlGeneratorClass, So i can use the values to generate a Xml.
gui.h
#ifndef GUI_H
#define GUI_H
#include <QMainWindow>
#include <QDebug>
#include "xmlgeneratorqobject.h"
namespace Ui {
class Gui;
}
class Gui : public QMainWindow
{
Q_OBJECT
public:
explicit Gui(QWidget *parent = nullptr);
~Gui();
qint8 testvalue = 1;
signals:
void transmitToXmlGen(Ui::Gui*);
private slots:
void on_pushButtonGenerateXml_clicked();
private:
Ui::Gui *ui;
XmlGeneratorQObject *xmlgenerator = new XmlGeneratorQObject();
};
#endif // GUI_H
gui.cpp
#include "gui.h"
#include "ui_gui.h"
Gui::Gui(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Gui)
{
ui->setupUi(this);
connect(this,SIGNAL(transmitToXmlGen(Ui::Gui*)),xmlgenerator,SLOT(receiveFromGui(Ui::Gui*)));
}
Gui::~Gui()
{
delete ui;
}
void Gui::on_pushButtonGenerateXml_clicked()
{
emit transmitToXmlGen(ui);
}
xmlgeneratorqobject.h
#ifndef XMLGENERATORQOBJECT_H
#define XMLGENERATORQOBJECT_H
#include <QObject>
#include <QDebug>
namespace Ui {
class XmlGeneratorQObject;
class Gui;
}
class XmlGeneratorQObject : public QObject {
Q_OBJECT
public:
explicit XmlGeneratorQObject(QObject * parent = nullptr);
private slots:
void receiveFromGui(Ui::Gui*);
};
#endif // XMLGENERATORQOBJECT_H
xmlgeneratorqobject.cpp
#include "xmlgeneratorqobject.h"
XmlGeneratorQObject::XmlGeneratorQObject(QObject *parent){}
void XmlGeneratorQObject::receiveFromGui(Ui::Gui* objectFromGui)
{
qDebug() << objectFromGui->testvalue; // ERROR member access into incomplete type 'Ui::Gui'
}
Expected result:
Access to public variables from passed gui-object should be possible
Actual result:
member access into incomplete type 'Ui::Gui'
Can you please help me learn forward declaration / include?
Is my approach in general okay?
Your xmlgeneratorqobject.cpp needs the line
#include "ui_gui.h"
This gives it the details of the ui widgets. This file is generated by the Qt build system.
A have a class, inherited from QWidget and Ui_Form (automaticaly generated class, appears when you create a .ui in Qt). It looks like
class MyClass: public QWidget, public Ui_Form {}
Ui_Form has some members, which connected with relevant widgets in the .ui file (for example, QLineEdits, QButtons, etc).
class Ui_Form {
public:
QLineEdit *fileNameEdit;
void setupUi(QWidget *Form) {
fileNameEdit = new QLineEdit(layoutWidget);
fileNameEdit->setObjectName(QStringLiteral("fileNameEdit"));
}
}
As MyClass is inherited from Ui_Form, I can use this membes. But, when I try to do something, I have an exeption "Access violation reading location". For example:
fileNameEdit->setText("String");
Can somebody give an advice?
The way you are incorporating the Ui_Form part is not how Qt proposes it by default. If you look into this button example you can see how the ui part is incorporated diferently:
Header file
#ifndef BUTTON_H
#define BUTTON_H
#include <QWidget>
namespace Ui {
class Button;
}
class Button : public QWidget
{
Q_OBJECT
public:
explicit Button(int n, QWidget *parent = 0);
~Button();
private slots:
void removeRequested();
signals:
void remove(Button* button);
private:
Ui::Button *ui;
};
#endif // BUTTON_H
CPP code
#include "button.h"
#include "ui_button.h"
Button::Button(int n, QWidget *parent) :
QWidget(parent),
ui(new Ui::Button)
{
ui->setupUi(this);
ui->pushButton->setText("Remove button "+QString::number(n));
addAction(ui->actionRemove);
connect(ui->actionRemove,SIGNAL(triggered()),this,SLOT(removeRequested()));
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(removeRequested()));
}
Button::~Button()
{
delete ui;
}
void Button::removeRequested()
{
emit remove(this);
}
The main difference is that I believe you are not calling Ui_From::setupUi function. It is clear to me that you do not need to follow the Qt suggested template (incorporating the ui as a class member rather than inheriting from it), however, it is much clearer from my point of view if you follow the Qt suggestions.
Material class has a mainwindow with a menu bar. When i click one of the elements in the menu bar i want to open the Fiction Qdialog window.
material.h
#ifndef MATERIALS_H
#define MATERIALS_H
#include <QMainWindow>
#include "materialinner.h"
class FictionSection;
namespace Ui {
class Materials;
}
class Materials : public QMainWindow, public MaterialInner
{
Q_OBJECT
public:
explicit Materials(QWidget *parent = 0);
~Materials();
private:
Ui::Materials *ui;
FictionSection *fiction;
};
#endif // MATERIALS_H
materials.cpp
#include "materials.h"
#include "ui_materials.h"
#include "fictionsection.h"
#include <QDebug>
#include <QMessageBox>
Materials::Materials(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Materials)
{
ui->setupUi(this);
// connect(ui->ficti,SIGNAL(textChanged(const QString &)),this,SLOT(displaySearch()));
}
Materials::~Materials()
{
delete ui;
}
void Materials::on_actionFiction_section_triggered()
{
this->hide();
fiction = new FictionSection();
fiction->show();
}
fictionsection.h
#ifndef FICTIONSECTION_H
#define FICTIONSECTION_H
#include <QDialog>
#include "materials.h"
namespace Ui {
class FictionSection;
}
class FictionSection : public QDialog, public Materials
{
Q_OBJECT
public:
explicit FictionSection(QWidget *parent = 0);
~FictionSection();
private:
Ui::FictionSection *ui;
};
#endif // FICTIONSECTION_H
When i compile it gives an error which is
Request for member 'show' is ambiguous.
Please help me to solve this. Thank you in advance.
The problem is that your FictionSection class inherits from both QDialog and Materials, but your Materials class also inherits from QMainWindow. Both QMainWindow and QDialog have a virtual show() method (inherited from QWidget), which causes the ambiguity. In other words: do you intend to call QMainWindow::show's implementation or QDialog::show's implementation? No one knows.
To solve this, you should use inheritance properly. Inherit from either QMainWindow or QDialog, but not both.
You need to understand why it is that you're inheriting the way you are (which is wrong) and improve the logic of the relationship between your classes to avoid problems like this one.
Also, class names should be singular, so Materials should be Material. If it needs to handle multiple things, then it could be MaterialManager or something similar.
I have a problem with accessing ui elements from another class(with instance). I have a second QMainWindow in my application, I can access in secondWindow.cxx class all ui elements but not in read.cxx class. My code looks like following. Where is my mistake? Thank you for your help.
-------------------------------secondWindow.h------------------------------------
#ifndef __secondWindow_h
#define __secondWindow_h
#include "ui_secondwindow.h"
class secondWindow : public QMainWindow
{
friend class read;
igstkStandardClassBasicTraitsMacro(secondWindow, QMainWindow);
Q_OBJECT
public:
igstkStateMachineMacro();
secondWindow();
virtual ~secondWindow();
void createSignalAndSlots();
public slots:
void secondWindowTest();
protected:
private:
Ui::secondMainWindow m_secondWindowUI;
};
#endif
-------------------------------secondWindow.cxx------------------------------------
#include "secondWindow.moc"
#include "secondWindow.h"
#include "read.h"
secondWindow::secondWindow() :m_StateMachine(this)
{
m_secondWindowUI.setupUi(this);
createSignalAndSlots();
}
void secondWindow::createSignalAndSlots()
{
connect(m_secondWindowUI.pushButton1, SIGNAL(clicked()),this, SLOT(secondWindowTest()));
connect(m_secondWindowUI.pushButton2, SIGNAL(clicked()), read::instance(), SLOT(readTest()));
}
void secondWindow::secondWindowTest()
{
m_secondWindowUI.pushButton1->setEnabled(true); //OK
}
secondWindow::~secondWindow(){}
---------------------------------read.h--------------------------------------
#pragma once
#include "secondWindow.h"
class read : public QObject
{
Q_OBJECT
public:
static read *instance();
read();
virtual ~read() {}
public slots:
void readTest();
protected:
secondWindow *m_readUI;
static read *m_read;
private:
};
---------------------------------read.cxx--------------------------------------
#include <read.moc>
#include "secondWindow.h"
#include "read.h"
read *read::m_read= NULL;
read::read()
{
m_readUI = dynamic_cast<secondWindow*>( QApplication::instance() );
}
read *read::instance()
{
if(m_read == NULL)
m_read = new read();
return m_read;
}
void read::readTest()
{
m_readUI->m_secondWindowUI.qlabelTest->setText("test"); //segmentation fault
}
You are casting a QApplication::instance(), which is a QApplication * deriving from QCoreApplication * deriving from QObject *. That won't work, it's not a secondWindow *, not even a QMainWindow *, not even a QWidget *.
Apart from that, your coding style is rather strange -- in Qt, it's customary to use CamelCase for classes, not thisStuff which usually applies to functions and methods. Including <read.moc> is just wrong. Why is read::m_read static? Finally, the coupling between the two window classes is set up in a strange way (accessing global stuff like QApplication just to get a reference to another window smells ugly code). A much better and more obvious approach is to either wrap all of your windows in a parent object or setting up the dependencies explicitly, perhaps like this:
MainWindow *mainWindow = new MainWindow();
SecondWindow *second = new SecondWindow(mainWindow);
UtilityWindow *utilityWin = new UtilityWindow(second);