First let me quickly introduce myself.
My name is Jonathan and I'm a video game technical artist and developer from Belgium.
I work mainly with C# or other script languages like Max Script, Python or Mel, and I begin to code in C++. I already did some little software in Visual Studio with WinForm and WPF.
StackOverflow was/and will be always an incredible resource for me.
I register because I moved further in my C++/Qt learning and I am now stuck with a Qt design and code problem.
I used the MVP pattern by the past for WinForm applications, and try to do the same with Qt. So I investigate and found the interface with Q_DECLARE_INTERFACE(MyInterfaceClass, "interfaceNameString") and QT_INTERFACES in the class that will implement the interface.
But I have a problem to connect the signal from the interface to a slot from and in my presenter.
error: no matching function for call to 'Presenter::connect(QObject*&, void (IView_Creator::)(), Presenter, void (Presenter::*)())'
QObject::connect(object,&IView_Creator::CreatorTest, this, &Presenter::Create);
error: no type named 'type' in 'struct std::enable_if'
The interface : (iview_creator.h)
#ifndef IVIEW_CREATOR_H
#define IVIEW_CREATOR_H
#include <QtPlugin>
class IView_Creator
{
public:
virtual ~IView_Creator(){}
virtual void WriteSomething() = 0;
signals:
virtual void CreatorTest() = 0;
};
Q_DECLARE_INTERFACE(IView_Creator, "interface")
#endif // IVIEW_CREATOR_H
The main class : (mainWindow.h)
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "iview_creator.h"
namespace Ui
{
class MainWindow;
}
class MainWindow : public QMainWindow ,public IView_Creator
{
Q_OBJECT
Q_INTERFACES(IView_Creator)
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
// IView_Creator interface
signals:
void CreatorTest();
};
#endif // MAINWINDOW_H
The presenter class : (presenter_creator.h)
#ifndef PRESENTER_H
#define PRESENTER_H
#include <QObject>
#include "mainwindow.h"
class Presenter : private QObject
{
Q_OBJECT
public:
Presenter(const MainWindow* mw);
private:
void Initialize(IView_Creator* mw);
private slots:
void Create();
};
#endif // PRESENTER_H
The implementation of the presenter :
#include "presenter_creator.h"
Presenter::Presenter(const MainWindow *mw)
{
IView_Creator *i = qobject_cast<IView_Creator*>(mw);
if(i != NULL)
Initialize(i);
}
void Presenter::Initialize(IView_Creator *mw)
{
auto object = dynamic_cast<QObject*>(mw);
Q_ASSERT(object);
QObject::connect(object, SIGNAL(CreatorTest()), this, SLOT(Create()));
//QObject::connect(object,QOverload<QObject*>::of(&IView_Creator::CreatorTest), this, &Presenter::Create);
QObject::connect(object,&IView_Creator::CreatorTest, this, &Presenter::Create);
mw->WriteSomething();
}
void Presenter::Create()
{
printf("Create");
}
The main class :
#include "mainwindow.h"
#include "presenter_creator.h"
#include <QApplication>
static Presenter* pt = NULL;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
MainWindow *mw = &w;
pt = new Presenter(mw);
w.show();
return a.exec();
}
The problem appear when I try to use the new synthax system of the connect function. I seems to work with the old SIGNAL SLOT string system.
I already try everything I found on the net but with no luck.
Maybe someone with more C++ and Qt knowledge could know how to solve this problem.
This can't work with the new signal-slot syntax since QObject doesn't inherit from IView_Creator.
The fundamental difference between the old and the new syntax is that with the old syntax QObject::connect checks at runtime whether the signal and the slot of the connection actually exist, while this check is performed at compile time with the new syntax.
However, after your cast of mw to QObject* the information that object actually also is an instance of IView_Creator is lost to the implementation of QObject::connect. All it knows is that &IView_Creator::CreatorTest needs an object of a subtype of IView_Creator and that not every QObject (that's all it knows about object) is also an IView_Creator, so it can't guarantee that this connection can always be created. Therefore it fails to compile.
Related
I've been following a simple QT tutorial and came up with a weird noob question.
https://www.youtube.com/watch?v=F56fSKoNCtk&list=PLS1QulWo1RIZiBcTr5urECberTITj7gjA&index=5
this is the tutorial.
Here's the my_window.h
#ifndef MY_WINDOW_H
#define MY_WINDOW_H
#include <QMainWindow>
namespace Ui {
class MyWindow;
}
class MyWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MyWindow(QWidget *parent = nullptr);
~MyWindow();
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
private:
Ui::MyWindow *ui;
};
#endif // MY_WINDOW_H
and my_window.cpp.
#include "my_window.h"
#include "ui_mywindow.h"
MyWindow::MyWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MyWindow)
{
ui->setupUi(this);
connect(ui->horizontalSlider,SIGNAL(valueChanged(int)),
ui->progressBar,SLOT(setValue(int)));
}
MyWindow::~MyWindow()
{
delete ui;
}
void MyWindow::on_pushButton_clicked()
{
ui->label->setText("Clicked!");
}
void MyWindow::on_pushButton_2_clicked()
{
ui->label->setText("Why...?");
}
In my_window.cpp, the definition of the constructor,
it does the tasks via the member pointer, 'ui' which is a pointer of 'MyWindow type' instance.
I thought 'this' pointer is also a 'MyWindow' class type pointer so i thought i can access the horizontalSlider and progressBar with this pointer too.
But i couldn't.
what makes the difference between two of them?
Your class MyWindow that you define in my_window.h and implement in my_window.cpp is ::MyWindow. Then you have ::Ui::MyWindow which is a totally separate class, and is defined and implemented in auto-generated files by Qt and the Qt tools.
You can have many symbols with the same name, as long as they are defined in different scopes. These symbols can even be different types, like one could be a class, one could be a variable, one could be a function, etc.
I have a problem in Qt. I want to use "ui" in another class function.
With this code:
void test::TextAp()
{
MainWindow::ui->QTextBrowser->append("Test");
}
I get these errors:
error C2227: left of '->qTextBrowser' must point to class/struct/union
error C2227: left of '->append' must point to class/struct/union
And with this code:
void test::TextAp()
{
Ui::MainWindow::QTextBrowser->append("Test");
}
I get this error:
error C2227: left of '->append' must point to class/struct/union
MainWindow.h:
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
Ui::MainWindow *ui;
private:
};
What can I do?
ps:Excuse my bad English, i'm French
If you are referring to default project created by Qt, ui can't be used as it is private. Make a MainWindow object and use it (like it is used in main()).
Now, if you have a QTextBrowser object created in MainWindow, call using that object and not class signature as:
ui->objTextBrowser->append("Test")
If "test" is class or struct it has to know about MainWindow object or in particular about it's child object TextBrowser.
Ui creates in the MainWindow constructor so, before using it you have to create it.
And in addition it's a bad practice to do what you want to do, the better solution is to connect signals from your test class (that have to be inherit from QObject) to slot of MainWindow
So bad practice looks:
//main.cpp
#include "test.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//instance of MainWindow
MainWindow w; // here constructor of MainWindow creates ui and all the childs
w.show();
//instance of test struct
test t;
//behind the design mode is creation of code with objects that you can create "manually" typing them
//to see the ui additional files just press Ctrl and mouse click (for example) on function ui->setupUi(this) in MainWindow constructor
//it's automatically generated code for ui created according to what you've created in design mode
//so here textBrowser pointer of object t is points to textBroswer of ui of object w
t.textBrowserFromTestStruct = w.findChild<QTextBrowser*>("textBrowser");
//get error if object f ui has no QTextBrowser named textBrowser
Q_ASSERT(t.textBrowserFromTestStruct);
//invoke t object function to append text to f textBrowser 10 times
for(int i = 0; i < 10; ++i)
t.TextAp("Hello World ");
return a.exec();
}
//test.h
#ifndef TEST_H
#define TEST_H
#include "mainwindow.h"
#include <QTextBrowser>
struct test
{
QTextBrowser *textBrowserFromTestStruct;
public:
void TextAp(QString text){textBrowserFromTestStruct->append(text);}
};
#endif // TEST_H
//mainwindow.h
#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();
Ui::MainWindow *getUI(){return ui;}
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
//mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
}
Read about signals and slots to get own solution of what you want using signals and slots. And of course read more about theory of C++ to understand what is private members of classes and structures, what is namespaces and scoping
I'm trying to use QTimer, which inherits QObject, in my newly created class. However I try it I keep getting the error 'QObject' is an ambiguous base of 'Recorder' . I did try my best to avoid ambiguity in my simple program but still got stuck with it.
Here's the structure of my classes.
#include "dialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();
return a.exec();
}
dialog.h: mainwindow UI
#ifndef DIALOG_H
#define DIALOG_H
#include "detector.h"
#include <QDialog>
#include <QtCore>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
Detector myDetector;
detector.h: detector window UI
#ifndef DETECTOR_H
#define DETECTOR_H
#include <QDialog>
#include <QtCore>
#include <QObject>
#include "actualrec.h"
namespace Ui {
class Detector;
}
class Detector : public QDialog
{
Q_OBJECT
public:
explicit Detector(QWidget *parent = 0);
~Detector();
void run();
private:
ActualRec theDetector;
Ui::Detector *ui;
actualrec.h: detector code
#ifndef ACTUALREC_H
#define ACTUALREC_H
#include <QtCore>
#include <QObject>
#include <QImage>
#include "recorder.h"
class ActualRec : public QThread
{
public:
ActualRec();
void run();
private:
Recorder theRecorder;
recorder.h: recorder code, where I want to use my QTimer
#ifndef RECORDER_H
#define RECORDER_H
#include <QtCore>
class Recorder : public QThread, public QObject
{
public:
Recorder();
void run();
private:
QTimer* theTimer;
recorder.cpp constructor has
*theTimer = new QTimer(this);
the output is following:
http://i.imgur.com/Awb6qhd.png
Any help would be much appreciated
You have several issues in your code:
1) Wrong usage of thread with Qt
class Recorder : public QThread, public QObject
a) It is enough to inherit QThread without explicitly inheriting QObject since QThread inherits QObject.
b) Even if you did this, historically, QObject ought to be the first base in the list in a general case.
c) However, you may wish to reconsider how to use your threads. This is one way, but necessarily the best.
2) Allocating an object for QTimer on the heap
Why are you allocating memory on the heap for a timer in the first place? It is OK to allocate it on the stack, especially since it is a member. That way, you would not need to deal with the this hassle either. The whole memory management becomes a lot simpler.
3) Not utilizing Q_NULLPTR
You ought to use it instead of 0 for the default values of the parents.
4) Including the whole QtCore module
#include <QtCore>
You should only include the parts that you eventually use. This is a brute-force way of including things.
Therefore, write something like this instead:
class Recorder : public QThread
{
public:
Recorder();
void run();
private:
QTimer theTimer;
Of course, if you use the threading mechanism the other way around in Qt, then it is perfectly fine to write this instead for the inheritance:
class Recorder : public QObject
but then your code would need some other change, so the code is broken as it is now, either way.
QThread already inherits QObject, and you can't inherit from two classes both inheriting QObject themselves.
You shall no inherit QObject twice. This is because signals and slots are mapped by integers and the ids can collide with each.
This also applies to any object that inherits from QObject.
class BadClass : public QTimer, public Dialog
{
};
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);
I'm new to C++ and QT, I'm using QT Creator, I created a QT Widget project named nGui, added a QT-QT Designer Form Class named mydlg, I've been trying to create a button in a window, when you click it opens another window while the original windows keeps showing. And here's my codes, but it always show the error: 'my2'was not declared in this scope. I have declared 'my2' in widget.h, and I included the widget.h file in mydlg.cpp, I don't know where is wrong, can someone help me out? Thank you so much!
mydlg.cpp
#include "mydlg.h"
#include "ui_mydlg.h"
myDlg::myDlg(QWidget *parent) :
QDialog(parent),
ui(new Ui::myDlg)
{
ui->setupUi(this);
}
myDlg::~myDlg()
{
delete ui;
}
void myDlg::on_pushButton_clicked()
{
my2.show();
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include"mydlg.h"
namespace Ui
{
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
myDlg my2;
private slots:
void on_pushButton_clicked();
};
#endif // WIDGET_H
main.cpp
#include <QtGui/QApplication>
#include "widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
my2 is declared in the Widget class, but you are trying to access it in a member function of the myDlg class.
Try replacing my2.show() with show()
When you are writing in the myDlg class you are writing the behaviour of every object that can be instantiated from that class (including my2).
It does not make sense to refer to my2 within the MyDlg class then, since someone else using your class could instead instantiate another object called (for example) my3 with it instead. What you want to do is tell the compiler when on _pushButton_clicked() is called on an object of class MyDlg go ahead and call the show() function on the same object. You can do this by writing this->show() or simply show().