How to connect QObbject (QPushButton) to a method from other class? - c++

I'm currently working on a project that need the connection between a QPushButton of a Qwidget class (window) and a void method from a "classical" class.
I've tried to connect them with all the solution that I've read but none works correctly.
Either the compiler returns me
QObject::connect: No such slot QWidget::Class::metoh()
or it won't compile at all without errors.
Here's the simpliest code that I've tried. I read the Qt documentation but it didn't help me. I've also tried to include the Q_OBJECT Macro but it lead to errors. I've also read that with Qt5 it's no more mandatory to define slots. Have I understood correctly ?
How can I connect the Some_Class method to the QPushButton ?
// Classical class header //
#ifndef DEF_CLASS
#define DEF_CLASS
#include <iostream>
#include <cstdlib>
#include <string>
class Some_class
{
protected: // permet l'acces pour les methodes style soin
Some attributes;
public:
Some_Class(int id);
//Personnage(int id, int vieAtStart, int degatsArmeAtStart);
void method();
// obligation de passer par des references pour avoir une modification effective
~Some_Class();
};
#endif
// Classical class cpp //
#include "Some_Class.h"
#include <QObject>
#include <iostream>
#include <cstdlib>
#include <string>
#include <vector>
using namespace std;
Some_Class::Some_Class(int id)
{
Id = id;
some attributes;
};
void Some_Class::method()
{
modification of attributes;
};
// Window class header //
#ifndef DEF_WINDOW
#define DEF_WINDOW
#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QIcon>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QImage>
#include <QPixmap>
#include <QLabel>
#include <QGraphicsPixmapItem>
#include "Some_Class.h"
class Window : public QWidget // On hérite de QWidget (IMPORTANT)
{
public:
Window(Some_Class test);
// public slots:
// void go_right();
private:
QPushButton *m_button;
};
#endif
// Window class cpp //
#include "Window.h"
#include <string>
#include <QObject>
Window::Window(Some_Class test) : QWidget()
{
setFixedSize(874, 968);
m_button = new QPushButton("test", this);
QObject::connect(m_button, SIGNAL(clicked()), this, SLOT(Some_Class::method()));
//QObject::connect(m_bouton_droite, SIGNAL(clicked()), qApp, Personnage::go_right());
//QObject::connect(m_bouton_droite, &QPushButton::clicked,qApp, Personnage::go_right());
}
#include <QApplication>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLabel>
#include <QIcon>
#include "Window.h"
#include "Some_Class.h"
#include <QObject>
// main.cpp //
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Window win(Heros);
win.show();
return app.exec();
}

First, you will need an object of Some_Class with an appropriate scope. Currently you only have test in your constructor which is a value parameter and thus gets destroyed when the constructor returns. One option would be to pass in test as a pointer if the object you are passing in has the correct lifetime.
Window::Window(Some_Class *test)
If that is not appropriate in your case you will need to keep a copy inside your Window object. For the rest of this answer I will however assume you pass in a pointer.
With a normal C++ object (not a QObject) you cannot use the SIGNAL/SLOT macro's because they require the use of the slot/signal markers in the class definition.
I see you tried to use the modern method pointer syntax but you made one error. The third parameter needs to be the address of an object of type Some_Class.
QObject::connect(m_button, &QPushButton::clicked, test, &Some_Class::method);
However that is not all, for this to work the signature of clicked has to match with Some_Class::method which it doesn't. clicked has a bool checked parameter.
The construct with the SIGNAL/SLOT macro's allows the slot to have less parameters but this version of connect is more strict and requires a strict match.
You can either add the parameter to method or use a lambda if you have C++11.
QObject::connect(m_button, &QPushButton::clicked, [test] (bool) {
test->method();
});

Related

Undefined struct 'addrinfo' winsock2

I encountered an error and I didn't find any solution (even over the internet)
I created aQt app to receive data using a TCP protocol and plot them using QcustomPlot.
I have the following files:
mainwindow.h :
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_mainwindow.h"
#include <QVector>
#include <iostream>
class MainWindow: public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = Q_NULLPTR);
// ...
private:
struct addrinfo _hints;
struct addrinfo* _result = NULL;
// ...
};
mainwindow.cpp :
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
#include "mainwindow.h"
#include <QVector>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
//...
}
and the main.cpp file:
#include "mainwindow.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
I have the following error:
'MainWindow::hints' uses undefined struct 'addrinfo' (compiling source file main.cpp).
I don't understand why I have this error, because I tested the same program in a classic consol app following the microsoft tutorial and it was working.
I believe it comes from the includes, but I still dont have a clue about which one causes that.
You need to #include something in your mainwindow.h that defines struct addrinfo, because your MainWindow class has a member variable of that type. At the moment you include all the socket stuff only in your *.cpp file.
You use #define WIN32_LEAN_AND_MEAN that prevents including many dependent header files and makes you include required header files explicitly. As for addrinfo you have to #include <ws2def.h>.

How do I connect this function to my connectButton?

I am trying to connect the addDevice() function from my Device class to my connectButton on my GUI. However no matter how I try and code the connect function, it does not work. Currently it is giving me the error:
primary expression expected before the ',' token.
I have tried the follow syntaxes:
connect(ui->connectButton,SIGNAL(clicked(bool)),d,SLOT(startDeviceDiscovery()));
connect(ui->connectButton,SIGNAL(clicked(bool)),d,&Device::startDeviceDiscovery());
connect(ui->connectButton,SIGNAL(clicked(bool)),this,SLOT(startDeviceDiscovery()));
connect(ui->connectButton,SIGNAL(clicked(bool)),this,Device::startDeviceDiscovery());
MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QObject>
#include <QBluetoothDeviceDiscoveryAgent>
#include <QtBluetooth>
#include <QDebug>
#include <QtWidgets>
#include "device.h"
#include "deviceinfo.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
Device d;
connect(ui->connectButton,SIGNAL(clicked(bool)),Device,SLOT(startDeviceDiscovery()));
//
.
.
.
}
Device.h
#ifndef DEVICE_H
#define DEVICE_H
#include <QObject>
#include <qbluetoothglobal.h>
#include <qbluetoothlocaldevice.h>
#include <QBluetoothDeviceDiscoveryAgent>
#include <QLowEnergyController>
#include <QBluetoothDeviceInfo>
#include <QBluetoothServiceInfo>
#include "deviceinfo.h"
#include <QList>
#include <QVariant>
class Device : public QObject
{
Q_OBJECT
public:
explicit Device(QObject *parent = 0);
QVariant name();
~Device();
signals:
void address(QVariant);
public slots:
void startDeviceDiscovery();
void connectDeivce(const QString &address);
};
#endif // DEVICE_H
For a connect you need a pointer, and you created your Device on the constructor, this means that just after the connect is used, constructor would finish, and this would destroy your device, disconnecting the function.
Correct syntax:
Device *myDevice = new Device();
connect(
ui->connectButton, // the pointer of the signal emitter
&QPushButton::clicked, // the signal you are interested
myDevice, // the pointer to receiving end
&Device::startDeviceDiscovery); // what you wanna trigger
you mixed every possibility in your tests, but in all of them you treated the slot as a method, calling the () operator. you can't call the call operator, on the connect you are passing the pointer of the method to a function that will call that for you when the time is right.

QTCreator extern not working on specific PC

Hi I am currently working on a tournament creator program using QT Creator. I have been working on it at work during my lunch breaks and it has ran fine, but I have brought it home to get it finished for this weekend and it doesnt work.
The error which I am getting is
F:\Documents\Coding\TournamentOrganiser\startscreen.cpp:-1: error: multiple
definition of `StartScreen::StartScreen(QWidget*)'
I have literally only taken the folder placed it on a USB, copied it onto my desktop and ran it and this occurs, when it worked fine at home.
I assume that it is some kind of QT Creator configuration setting but just in case these are the files which are involved in the issue. If anyone can help me out with this it would be much appreciated as I need this working on my desktop for Saturday when I will need to use the app.
template <typename T> using shp = std::shared_ptr<T>;
globals.h
#ifndef GLOBALS_H
#define GLOBALS_H
#include "startscreen.h"
#include "tournamentcreator.h"
#include "player.h"
#include <memory>
#include "util.h"
#include "matchups.h"
namespace globals{
extern shp<StartScreen> g_StartScreen;
extern shp<TournamentCreator> g_TournamentCreator;
extern shp<std::vector<Player>> g_PlayerData;
extern shp<MatchUps> g_MatchUps;
}
#endif // GLOBALS_H
main.cpp
#include "startscreen.h"
#include "tournamentcreator.h"
#include "matchups.h"
#include <QApplication>
#include "util.h"
namespace globals{
shp<StartScreen> g_StartScreen;
shp<TournamentCreator> g_TournamentCreator;
shp<std::vector<Player>> g_PlayerData;
shp<MatchUps> g_MatchUps;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
globals::g_StartScreen = std::make_shared<StartScreen>();
globals::g_TournamentCreator = std::make_shared<TournamentCreator>();
globals::g_PlayerData = std::make_shared<std::vector<Player>>();
globals::g_MatchUps = std::make_shared<MatchUps>();
globals::g_StartScreen->show();
return a.exec();
}
startscreen.h
#ifndef STARTSCREEN_H
#define STARTSCREEN_H
#include <QWidget>
namespace Ui {
class StartScreen;
}
class StartScreen : public QWidget
{
Q_OBJECT
public:
explicit StartScreen(QWidget *parent = 0);
~StartScreen();
private slots:
void on_newEventButton_clicked();
private:
Ui::StartScreen *ui;
};
#endif // STARTSCREEN_H
startscreen.cpp
#include "startscreen.h"
#include "ui_startscreen.h"
#include "globals.h"
StartScreen::StartScreen(QWidget *parent) :
QWidget(parent),
ui(new Ui::StartScreen)
{
ui->setupUi(this);
}
StartScreen::~StartScreen()
{
delete ui;
}
void StartScreen::on_newEventButton_clicked(){
this->hide();
globals::g_TournamentCreator->show();
}

C++ accessing object, QT

I'd appreciate it, when someone could help me. I am not used to C++. I am new to it.
My problem: I want to make an object "player" usable for another class. I don't get how to archive this.
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#include <QMainWindow>
#include <QMediaPlayer>
#include <QDebug>
#include "Leap.h"
#include <leapmotionlistener.h>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
QMediaPlayer* player;
private slots:
....
private:
Ui::MainWindow *ui;
void initialize();
Controller controller;
LeapMotionListener leapMotionListener;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QSound>
#include <iostream>
#include <QfileDialog>
using namespace std;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
player = new QMediaPlayer(this);
connect(player, &QMediaPlayer::positionChanged, this, &MainWindow::on_positionChanged);
connect(player, &QMediaPlayer::durationChanged, this, &MainWindow::on_durationChanged);
initialize();
}
QString path;
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::initialize(){
controller.addListener(leapMotionListener);
leapMotionListener.setPlayer(player);
controller.setPolicy(Leap::Controller::POLICY_BACKGROUND_FRAMES);
}
...
leapmotionlistener.h
#ifndef LEAPMOTIONLISTENER
#define LEAPMOTIONLISTENER
#include <iostream>
#include <cstring>
#include "Leap.h"
#include <QFile>
#include <QAudioOutput>
#include <QMediaPlayer>
using namespace Leap;
class LeapMotionListener : public Listener {
public:
LeapMotionListener();
void setPlayer(QMediaPlayer&);
//... some more methods
private:
QMediaPlayer player;
};
#endif // LEAPMOTIONLISTENER
leapmotionlistener.cpp
//calls the player object in one method like the following
player.stop();
My main questions are: What am I doing wrong while referencing and instantiating? And how can leapmotionlistener access the same player object (I want to influence the audio)?
I get the Error:
MusicPlayer\mainwindow.cpp:32: Error: C2664: 'void LeapMotionListener::setPlayer(QMediaPlayer &)' : converting from argument 1 'QMediaPlayer *' in 'QMediaPlayer &' not possible
This little project is downloadable for a quick view with the following link:
https://www.dropbox.com/s/igr7ywnvicdlxxd/MusicPlayer.zip?dl=0
Thanks in advance!
All you need to do is
leapMotionListener.setPlayer(*player);
An lvalue reference binds to an object, not to the pointer to the object. In order to get the object from a pointer to it, you need to dereference the pointer using the *.
Among other problems, the QMediaPlayer you're trying to pass to setPlayer is a pointer, not a reference to an object.
You can either instantiate your player object like this:
QMediaPlayer player;
Or you can change your setPlayer function signature to this:
void setPlayer(QMediaPlayer* mplayer);
If you update your function signature, you'll also need fix other function signatures and leave the ampersands out of your connect() statements when you're referencing the player.
the following worked now:
in MainWindow.h:
public:
QMediaPlayer* player;
in MainWindow.cpp:
player = new QMediaPlayer(this);
leapMotionListener.setPlayer(player);
controller.addListener(leapMotionListener);
in LeapMotionListener.h:
private:
QMediaPlayer *player;
public:
void setPlayer(QMediaPlayer *mplayer);
in LeapMotionListener.cpp:
LeapMotionListener::LeapMotionListener()
: player(0)
{}
void LeapMotionListener::setPlayer(QMediaPlayer *mplayer){
player = mplayer;
}

QT connect crash using signal accepted

I have a problem with my Qt code. I wanted to write an program which are taking a coordinates of point and then that point is drawing in point with that coordinates. My program doesn't have any errors or warnings when i built it but it's crashing at start(MainWindow doesn't show). This is my code:
main.cpp
#include < QApplication >
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow win;
win.show();
return app.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWidget>
#include <QAction>
#include <QToolBar>
#include <QTextCodec>
#include <QObject>
#include <QDialog>
#include <QLineEdit>
#include <QPushButton>
#include <QString>
#include "addpoint.h"
class MainWindow: public QMainWindow
{
Q_OBJECT
private:
QToolBar *AddToolbar;
QAction *AddPointAction;
AddPoint *AddPointDialog;
QLineEdit *x;
public:
MainWindow();
void createToolbar();
void createActionAdd();
signals:
public slots:
void PointClicked();
void DialogAccepted();
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow()
{
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
createActionAdd();
createToolbar();
connect(AddPointAction, SIGNAL(triggered(bool)), this, SLOT(PointClicked()));
connect(AddPointDialog, SIGNAL(accepted()), this, SLOT(DialogAccepted()));
setMinimumSize(480, 320);
}
/**/
void MainWindow::createToolbar()
{
AddToolbar = new QToolBar;
AddToolbar->addAction(AddPointAction);
addToolBar(AddToolbar);
}
/**/
void MainWindow::createActionAdd()
{
AddPointAction = new QAction("Add Road", this);
x = new QLineEdit(this);
x->setFixedSize(100, 30);
x->move(100, 100);
}
/**/
void MainWindow::PointClicked()
{
AddPointDialog = new AddPoint(this);
AddPointDialog->setModal(true);
AddPointDialog->exec();
}
/**/
void MainWindow::DialogAccepted()
{
x->setText("abc");
}
addpoint.h
#ifndef ADDPOINT_H
#define ADDPOINT_H
#include <QWidget>
#include <QTextCodec>
#include <QDialog>
#include <QObject>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QString>
class AddPoint : public QDialog
{
Q_OBJECT
private:
QLabel *XpointL;
QLineEdit *XPoint;
QPushButton *OKButton;
public:
AddPoint(QWidget *parent);
void createButton();
signals:
public slots:
};
#endif // ADDPOINT_H
addpoint.cpp
#include "addpoint.h"
AddPoint::AddPoint(QWidget *parent) :QDialog(parent)
{
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
createButton();
connect(OKButton, SIGNAL(clicked(bool)), this, SLOT(accept()));
setMinimumSize(320, 240);
}
/**/
void AddPoint::createButton()
{
XpointL = new QLabel("Point X:", this);
XpointL->setFixedSize(100, 30);
XpointL->move(10, 10);
XPoint = new QLineEdit(this);
XPoint->setFixedSize(180, 30);
XPoint->move(120, 10);
OKButton = new QPushButton("OK", this);
OKButton->setFixedSize(100, 30);
OKButton->move(200, 150);
}
After running the program i see in aplication output lap:
"The program has unexpectedly finished."
"C:\QT\build-xxx-Desktop_Qt_5_4_2_MSVC2013_64bit-Debug\debug\xx.exe crashed"
I note that i made some experiments with this code and i saw that i have problem with signal accpeted() at mainwindow.cpp. I don't know what can i do with this problem. I hope you will help me.
AddPointDialog is uninitialized pointer, it does not yet point to valid AddPoint in MainWindow's constructor. You cannot call connect on that. Its value will change later, when you do AddPointDialog = new AddPoint(this); and only then will you be able to call connect.
Simply, you should move your connect call to void MainWindow::PointClicked() after you've initialized your pointer. I'd also make AddPointDialog local to that function and store it on the stack (you don't use it anywhere else and you're leaking memory).
The code would be:
void MainWindow::PointClicked()
{
AddPoint AddPointDialog(this);
AddPointDialog.setModal(true);
connect(&AddPointDialog, SIGNAL(accepted()), this, SLOT(DialogAccepted()));
AddPointDialog.exec();
}