Qt's slot(?) inserts redundant namespace into connect - c++

The problem I get is the following error message when calling connect, with MRC being the redundant namespace which I think Qt shouldn't have added - boundSubWindow isn't defined inside MRC. My understanding is the slot function isn't found, because MRC:: was prepended to it's name.
QObject::connect: No such slot MRC::boundSubWindow::myFunc(unsigned char *, int) in z:\mrc\mrc\mrc.h:23
QObject::connect: (receiver name: 'MRCClass')
The code is
---------- mrc.h ----------
#include <QtWidgets/QMainWindow>
#include "ui_MRC.h"
#include "myThread.h"
#include "boundsubwindow.h"
class MRC : public QMainWindow
{
Q_OBJECT
public:
MRC(QWidget *parent = Q_NULLPTR) : QMainWindow(parent)
{
ui.setupUi(this);
m_Thread = new myThread;
m_Subwindow = new boundSubWindow;
connect(MRC::m_Thread, SIGNAL(mySignal(char *, int)),
this, SLOT(boundSubWindow::myFunc(unsigned char *, int)));
}
static inline myThread *m_Thread;
boundSubWindow *m_Subwindow;
private:
Ui::MRCClass ui;
};
---------- boundsubwindow.h ----------
#include <QMdiSubWindow>
class boundSubWindow : public QMdiSubWindow
{
public:
boundSubWindow() {}
public slots:
void myFunc(unsigned char *, int);
};
---------- boundsubwindow.h ----------
void boundSubWindow::myFunc(unsigned char *, int) {}
---------- myThread.h ----------
#include <QThread>
class myThread : public QThread
{
Q_OBJECT
public:
myThread() {}
signals:
void mySignal(char *, int);
};
I've skipped an auto generated main.cpp for Qt GUI application, and the MRC.ui - auto generated then added a QMdiArea with Qt Creator. I'm using Visual Studio 2017 and Qt 5.13

This is wrong:
connect(MRC::m_Thread, SIGNAL(mySignal(char *, int)),
this, SLOT(boundSubWindow::myFunc(unsigned char *, int)));
boundSubWindow::myFunc is not slot of this. Also, specifying the namespace for m_Thread member variable seems quite redundant. You probably want this:
connect(m_Thread, SIGNAL(mySignal(char *, int)),
m_subWindow, SLOT(myFunc(unsigned char *, int)));
Additionally, add Q_OBJECT macro to boundSubWindw class and re-run qmake explicitly (you have to do that when adding these Qt macros to files which didn't previously have them).
Also, you should use the new connect syntax so you get compile time errors instead of run time errors:
connect(m_Thread, &myThread::mySignal,
m_subWindow, &boundSubWindow::myFunc);
Finally, it's common Qt convention to have class names start with capital, so consider renaming to BoundSubWindow and MyThread, if you want other Qt programmers to be able to easily read your code.

Related

Unable to find the slot of arduino though Qt

#include "dialog.h"
#include "ui_dialog.h"
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QDebug>
#include <QtWidgets>
#include <QString>
#include <string>
#include <QObject>
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
//ui->degree_lcdNumber->display("---");
// ui->distance_lcdNumber->display("---");
arduino_is_available = false;
port_name = "";
arduino =new QSerialPort;
serialBuffer = "";
foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) {
if(serialPortInfo.hasVendorIdentifier() &&serialPortInfo.hasProductIdentifier()){
if(serialPortInfo.vendorIdentifier() == arduino_uno_vendorid){
if(serialPortInfo.productIdentifier()== arduino_uno_productid){
port_name = serialPortInfo.portName();
arduino_is_available = true;
}
}
}
}
if(arduino_is_available){
//open and configure the port
arduino->setPortName(port_name);
arduino->open(QSerialPort::ReadOnly);
arduino->setBaudRate(QSerialPort::Baud9600);
arduino->setDataBits(QSerialPort::Data8);
arduino->setParity(QSerialPort::NoParity);
arduino->setStopBits(QSerialPort::OneStop);
arduino->setFlowControl(QSerialPort::NoFlowControl);
QObject::connect(arduino,SIGNAL(readyRead()),this,SLOT(&serialReceived()));
}else{
//give error message
QMessageBox::warning(this,"Port Error","Couldn't find the Arduino!");
}
}
Dialog::~Dialog()
{
if(arduino->isOpen()){
arduino->close();
}
delete ui;
}
void Dialog::serialReceived(){
qDebug()<<"works" ;
QStringList bufferSplit = serialBuffer.split(".");
serialData = arduino->readAll();
serialBuffer += QString::fromStdString(serialData.toStdString());
serialBuffer = ",";
qDebug()<<bufferSplit;
}
void Dialog::updateLCD(const QString sensor_reading){
// ui->degree_lcdNumber->display(sensor_reading);
}
(.h)
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QSerialPort>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
QSerialPort *arduino;
static const quint16 arduino_uno_vendorid =9025;
static const quint16 arduino_uno_productid =67;
void updateLCD(const QString);
void serialReceived();
QString port_name;
//void readSerial();
QByteArray serialData;
QString serialBuffer;
bool arduino_is_available;
};
#endif // DIALOG_H
I just started the Qt. I want to connect Qt with arduino serially. I am reading the data but I am not able to connect with arduino slot.
I am getting a message after compilation. The message is QObject::connect: No such slot Dialog::&serialReceived() in ..\serial_sensor\dialog.cpp:45
QObject::connect: (receiver name: 'Dialog').
Can I know why?
As per the Qt Signals and Slot documentation, the Qt signals and slots have to be declared under signals: and public slots: respectively.
Why do we do that ?
Since slots are normal member functions, they follow the normal C++ rules when called directly. However, as slots, they can be invoked by any component, regardless of its access level, via a signal-slot connection. This means that a signal emitted from an instance of an arbitrary class can cause a private slot to be invoked in an instance of an unrelated class.( as per Qt Documentation)
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
public slots :
void serialReceived();
signals :
// Declare Signals here.
private:
// other private declarations.
};
The reason your connection is failing is that your connect syntax is wrong. Either you have mixed Qt's functor and string based connections or accidentally added & in front of serialReceived. Below you can find two ways to do your connection. The first one is preferred. You can read more from here. Because Dialog is QObject based class you can just call connect.
Functor based connection:
connect(arduino, &QSerialPort::readyRead, this, &Dialog::serialReceived);
String based connection:
connect(arduino, SIGNAL(readyRead()), this, SLOT(serialReceived()));
If you are using Qt4 you have to use slots in your declaration. In Qt5 slots is not strictly required for connections but it should still be used. If you don't use it you can't use introspection. You can't e.g. call QMetaObject::invokeMethod. So, in short add slots to your header file as others have already suggested.
public slots:
void serialReceived();

Error when using Qt connect with interface and new synthax

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.

Threading and QRegisterMetatype issue

I have develop an app in Qt/C++, the app is currently working in one thread and and based on a UI and a framework. the UI and framework discuss together using the signal/slot mecanism provided by Qt. I have added threading because some operation inside the framework freeze UI.
The issue I'm facing is that now the app is not working anymore because of
QObject::connect: Cannot queue arguments of type 'uint32_t'
(Make sure 'uint32_t' is registered using qRegisterMetaType().)
What I have done is, declare in the main the qRegisterMetatype but it still complaining. I don't really know what I have to do in addition.
I have gave you below the basic process for a deletion for example.
main.cpp
qRegisterMetaType<uint32_t>("uint32_t");
qRegisterMetaType<QList<QTreeWidgetItem*> >("QList<QTreeWidgetItem*>");
Treewidget.cpp
void TreeWidget::DeleteAction() {
....
connect(this,&PulsTreeWidget::RequestDelete, &m_Framework, &PulsFramework::DeleteItem);
emit RequestDelete(item, nb_items);
}
Framework.cpp
void Framework::DeleteItem(QList<QTreeWidgetItem *> item, uint32_t total_item) {...}
Any idea ? do I need to not use the uint32_t as it is but change it's definition
Thanks
You are doing something worng. My example:
Object.h
#ifndef OBJECT_H
#define OBJECT_H
#include <QtCore>
class Object : public QObject
{
Q_OBJECT
public:
explicit Object(QObject *parent = 0);
void emitSignal(uint32_t v);
public slots:
void mySlot(uint32_t v);
signals:
void mySignal(uint32_t v);
};
#endif // OBJECT_H
Object.cpp
#include "Object.h"
Object::Object(QObject *parent) :
QObject(parent)
{
}
void Object::emitSignal(uint32_t v)
{
emit mySignal(v);
}
void Object::mySlot(uint32_t v)
{
qDebug() << v;
}
main.cpp
#include "Object.h"
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
qRegisterMetaType < uint32_t >("uint32_t"); // <--------------
Object o1, o2;
QThread t1, t2;
o1.moveToThread(&t1);
o2.moveToThread(&t2);
QObject::connect(&o1, SIGNAL(mySignal(uint32_t)), &o2, SLOT(mySlot(uint32_t)));
QObject::connect(&o2, SIGNAL(mySignal(uint32_t)), &o1, SLOT(mySlot(uint32_t)));
t1.start();
t2.start();
o1.emitSignal(5);
o2.emitSignal(10);
return app.exec();
}
Output:
5
10
When removing qRegisterMetaType < uint32_t >("uint32_t"); line, also complains:
QObject::connect: Cannot queue arguments of type 'uint32_t'
(Make sure 'uint32_t' is registered using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'uint32_t'
(Make sure 'uint32_t' is registered using qRegisterMetaType().)
P.S.: I don't like your connect+emit pair. You do know, that you need to connect signal to slot only once in order it to work? You do not need to do it before each signal emit.

Qt Undo/Redo implementation, can’t connect to a button

I post the question also in the Qt Forum, here
I am trying to implement an undo and redo commands in my application. I have a QTreeWidget and I’d like to let the user undo and redo an action (ex. change a value in a QTreeWidgetItem columns in the QTreeWidget and undo/redo it).
Here part of my code:
class A.h
class A : public QWidget
{
Q_OBJECT
public:
explicit A(...);
~A();
ChangeValueTreeCommand *commands;
QUndoStack *undoStack;
QPushButton *undoBtn;
QPushButton *redoBtn;
QString newValue;
void changeItem(QTreeWidgetItem* treeWidgetItemChanged, int col);
};
class A.cpp
A::A(...){
undoStack = new QUndoStack(this);
}
void A::changeItem(QTreeWidgetItem* treeWidgetItemChanged, int col){
....
commands = new ChangeValueTreeCommand(treeWidgetItemChanged, col, newValue);
connect(undoBtn, SIGNAL(clicked()), commands, SLOT(undo()));
undoStack->push(commands);
}
class Commands.h
#ifndef COMMANDS_H
#define COMMANDS_H
#include <QApplication>
#include <QUndoCommand>
#include <QTreeWidgetItem>
class ChangeValueTreeCommand : public QUndoCommand
{
public:
explicit ChangeValueTreeCommand(QTreeWidgetItem* treeWI = NULL, int c = 0, const QString changedV = "");
~ChangeValueTreeCommand();
QTreeWidgetItem* treeWItem;
const QString changedValue;
int col;
public slots:
void undo();
void redo();
};
#endif // COMMANDS_H
class Commands.cpp
#include "Commands.h"
ChangeValueTreeCommand::ChangeValueTreeCommand(QTreeWidgetItem* treeWI, int c, const QString changedV)
: treeWItem(treeWI), col(c), changedValue(changedV)
{}
ChangeValueTreeCommand::~ChangeValueTreeCommand(){}
void ChangeValueTreeCommand::undo()
{
const QString oldValue = treeWItem->text(col);
treeWItem->setText(col, oldValue);
}
void ChangeValueTreeCommand::redo()
{
treeWItem->setText(col, changedValue);
}
The problem is that when the user changes the value in the QTreeWidgetItem, it automatically appears the previous value. Moreover, I would like to connect the undo and redo functions to two buttons, but the compiler says that
1543: error: C2664: ‘QMetaObject::Connection QObject::connect(const QObject *,const char *,const QObject *,const char *,Qt::ConnectionType)‘ÿ: cannot convert parameter 3 from ‘ChangeValueTreeCommand *’ to ‘const QObject *’
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
Can someone help me? Thx
Your undo and redo Buttons should call undoStack->undo() / undoStack->redo(). This will move the stack pointer and will call the undo/redo function of the current command.
See the Qt Documentation for a detailed Explanation: http://qt-project.org/doc/qt-4.8/qundostack.html#undo
Escpecially this part:
New commands are pushed on the stack using push(). Commands can be
undone and redone using undo() and redo(), or by triggering the
actions returned by createUndoAction() and createRedoAction().
QUndoStack keeps track of the current command. This is the command
which will be executed by the next call to redo(). The index of this
command is returned by index(). The state of the edited object can be
rolled forward or back using setIndex(). If the top-most command on
the stack has already been redone, index() is equal to count().

QT Connection between classes

I think i have some troubles getting this right: I have a QMainWindow class. In my programm I want to create other classes e.g. for input handling, computation...
Now first from my mainwindow class i want to send to my fileselector (file handler) class to open a file dialog, thus save the selected files internally. Unfortunately I am having troubles to connect the slots.
main window:
MA_FEX::MA_FEX(QWidget *parent)
: QMainWindow(parent), fileSelector(this)
{
ui.setupUi(this);
//this works:
fileSelector.openFiles(this);
//this doesn't:
connect(ui.actionOpenFiles, SIGNAL(triggered()), fileSelector, SLOT(openFiles(this)));
}
MA_FEX::~MA_FEX()
{
}
mainwindow header:
class MA_FEX : public QMainWindow
{
Q_OBJECT
public:
MA_FEX(QWidget *parent = 0);
~MA_FEX();
private:
Ui::MA_FEXClass ui;
FileSelection fileSelector;
};
file coordination class:
FileSelection::FileSelection(QObject *parent)
: QObject(parent)
{
}
FileSelection::~FileSelection()
{
}
void FileSelection::openFiles(QWidget *parent){
QStringList files = QFileDialog::getOpenFileNames(
parent,
"Select one or more files to open",
"c:",
"Images (*.csv *.txt )");
}
header:
class FileSelection : public QObject
{
Q_OBJECT
public:
FileSelection(QObject *parent);
~FileSelection();
public slots:
void openFiles(QWidget *parent);
private:
};
Am I missing something ? Executing i get Error C2664 on the connect line saying that Parameter 3 'FileSelection' cannot be converted to 'const QObject'.
Look at the declaration of the QObject::connect:
QObject::connect(const QObject * sender, const char * signal,
const QObject * receiver, const char * method,
Qt::ConnectionType type = Qt::AutoConnection);
It takes pointers, so you need to pass a pointer to fileSelector.
Another problem there is incompatible SIGNAL and SLOT. The slot specification in connect is declaration, so you cannot pass arguments as you did with this. If you use Qt 5 and C++11 you can do that by passing lambda instead of slot specification:
QObject::connect(ui.actionOpenFiles, &QAction::triggered,
[this]() { fileSelector.openFiles(this); });
For Qt 4 you need to create wrapping slot in your MA_FEX class which takes no arguments and which will invoke the slot of the fileSelector:
class MA_FEX {
...
Q_SLOT void openFileSelector() { fileSelector.openFiles(this); }
...
public:
MA_FEX(QWidget *parent) : QMainWindow(parent), fileSelector(this) {
ui.setupUi(this);
connect(ui.actionOpenFiles, SIGNAL(triggered()), SLOT(openFileSelector()));
}
...
};