Temporarily deactivating a connection Qt C++

1k Views Asked by At

I am trying to temporarily remove this connection:

connect(clipBoard, SIGNAL(dataChanged()), this, SLOT(copiage()));  (line 20)

I have tried all I could but it always end up with a crash. I really have no clue about what causes this. It always crash at the moment I try to deactivate the connection (line 93) just before the line:

clipBoard->setText(messageRecu); (line 94)

The idea is that I don't want the connection when it is the program itself that changes the clipboard.

Anyone can help me on why it crashes?

Here is the .h:

#ifndef FENCLIENT_H
#define FENCLIENT_H

#include <QtWidgets>
#include <QtNetwork>
#include <QClipboard>
#include "ui_fenclient.h"


class FenClient : public QWidget, private Ui::FenClient
{
    Q_OBJECT

    public:
        FenClient();

    private slots:
        void on_boutonConnexion_clicked();
        void on_boutonEnvoyer_clicked();
        void on_message_returnPressed();
        void donneesRecues();
        void connecte();
        void deconnecte();
        void erreurSocket(QAbstractSocket::SocketError erreur);
        void copiage();

    private:
        QTcpSocket *socket; // Représente le serveur
        quint16 tailleMessage;
        QClipboard *clipBoard;

};


#endif // FENCLIENT_H

Here is the .cpp

#include "fenclient.h"

using namespace std;
#include<iostream>
#include <ostream>//sinon cout marche pas

FenClient::FenClient()
{
    setupUi(this);

    socket = new QTcpSocket(this);
    connect(socket, SIGNAL(readyRead()), this, SLOT(donneesRecues()));
    connect(socket, SIGNAL(connected()), this, SLOT(connecte()));
    connect(socket, SIGNAL(disconnected()), this, SLOT(deconnecte()));
    connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(erreurSocket(QAbstractSocket::SocketError)));

    tailleMessage = 0;

    QClipboard *clipBoard = QGuiApplication::clipboard();//Ca a été long mais il me faut ca...pas tout compris
    connect(clipBoard, SIGNAL(dataChanged()), this, SLOT(copiage()));
}

// Tentative de connexion au serveur
void FenClient::on_boutonConnexion_clicked()
{
    // On annonce sur la fenêtre qu'on est en train de se connecter
    listeMessages->append(tr("<em>Tentative de connexion en cours...</em>"));
    boutonConnexion->setEnabled(false);

    socket->abort(); // On désactive les connexions précédentes s'il y en a
    socket->connectToHost(serveurIP->text(), serveurPort->value()); // On se connecte au serveur demandé
}

// Envoi d'un message au serveur
void FenClient::on_boutonEnvoyer_clicked()
{
    QByteArray paquet;
    QDataStream out(&paquet, QIODevice::WriteOnly);

    // On prépare le paquet à envoyer
    QString messageAEnvoyer = message->text();//on enlève tr("<strong>") + pseudo->text() +tr("</strong> : ") +

    out << (quint16) 0;
    out << messageAEnvoyer;
    out.device()->seek(0);
    out << (quint16) (paquet.size() - sizeof(quint16));

    socket->write(paquet); // On envoie le paquet

    message->clear(); // On vide la zone d'écriture du message
    message->setFocus(); // Et on remet le curseur à l'intérieur
}

// Appuyer sur la touche Entrée a le même effet que cliquer sur le bouton "Envoyer"
void FenClient::on_message_returnPressed()
{
    on_boutonEnvoyer_clicked();
}

// On a reçu un paquet (ou un sous-paquet)
void FenClient::donneesRecues()
{
    /* Même principe que lorsque le serveur reçoit un paquet :
    On essaie de récupérer la taille du message
    Une fois qu'on l'a, on attend d'avoir reçu le message entier (en se basant sur la taille annoncée tailleMessage)
    */
    QDataStream in(socket);

    if (tailleMessage == 0)
    {
        if (socket->bytesAvailable() < (int)sizeof(quint16))
             return;

        in >> tailleMessage;
    }

    if (socket->bytesAvailable() < tailleMessage)
        return;


    // Si on arrive jusqu'à cette ligne, on peut récupérer le message entier
    QString messageRecu;
    in >> messageRecu;

    // On affiche le message sur la zone de Chat
    listeMessages->append(messageRecu);


    //clipBoard->disconnect();
    //const QSignalBlocker blocker(clipBoard);
    //on met dans le clipBoard
    cout << "Avant " << endl;
    bool oldState = clipBoard->blockSignals(true);
    clipBoard->setText(messageRecu);
    clipBoard->blockSignals(oldState);
    cout << "Après " << endl;

    //connect(clipBoard, SIGNAL(dataChanged()), this, SLOT(copiage()));


    // On remet la taille du message à 0 pour pouvoir recevoir de futurs messages
    tailleMessage = 0;
}

// Ce slot est appelé lorsque la connexion au serveur a réussi
void FenClient::connecte()
{
    listeMessages->append(tr("<em>Connexion réussie !</em>"));
    boutonConnexion->setEnabled(true);
}

// Ce slot est appelé lorsqu'on est déconnecté du serveur
void FenClient::deconnecte()
{
    listeMessages->append(tr("<em>Déconnecté du serveur</em>"));
}

// Ce slot est appelé lorsqu'on que le presse-papiers change
void FenClient::copiage()
{   cout << "Copiage= " << endl;
/*    QString textCopie;
    textCopie = clipBoard->text();


    QByteArray paquet;
    QDataStream out(&paquet, QIODevice::WriteOnly);

    // On prépare le paquet à envoyer
    QString messageAEnvoyer = textCopie;

    out << (quint16) 0;
    out << messageAEnvoyer;
    out.device()->seek(0);
    out << (quint16) (paquet.size() - sizeof(quint16));

    socket->write(paquet); // On envoie le paquet

    //message->clear(); // On vide la zone d'écriture du message
    //message->setFocus(); // Et on remet le curseur à l'intérieur */

}



// Ce slot est appelé lorsqu'il y a une erreur
void FenClient::erreurSocket(QAbstractSocket::SocketError erreur)
{
    switch(erreur) // On affiche un message différent selon l'erreur qu'on nous indique
    {
        case QAbstractSocket::HostNotFoundError:
            listeMessages->append(tr("<em>ERREUR : le serveur n'a pas pu être trouvé. Vérifiez l'IP et le port.</em>"));
            break;
        case QAbstractSocket::ConnectionRefusedError:
            listeMessages->append(tr("<em>ERREUR : le serveur a refusé la connexion. Vérifiez si le programme \"serveur\" a bien été lancé. Vérifiez aussi l'IP et le port.</em>"));
            break;
        case QAbstractSocket::RemoteHostClosedError:
            listeMessages->append(tr("<em>ERREUR : le serveur a coupé la connexion.</em>"));
            break;
        default:
            listeMessages->append(tr("<em>ERREUR : ") + socket->errorString() + tr("</em>"));
    }

    boutonConnexion->setEnabled(true);
}


1

There are 1 best solutions below

1
On

In your constructor definition, you have written:

QClipboard *clipBoard = QGuiApplication::clipboard(); // Bad because it shadows FenClient::clipBoard

You should have written instead:

clipBoard = QGuiApplication::clipboard();

Since clipBoard is a field member of your FenClient class, why do you try to declare another local variable with the same name of an already existing one (which will likely remains uninitialized) ?

Actually, this is probably the reason why your clipBoard::blockSignals() failed.
You have shadowed your clipBoard field member. In other words, it was never initialized.

Dereferencing a uninitialized pointer leads to undefined behaviour. Anything can happen, in your case you got a crash.

I have not read your whole code so it may contain other issues.


Note:

In order to remove a connection, you better have to use the QObject::disconnect() method.

It allows you to be more accurate/specific (about which connections to remove, ...). QObject::blockSignals() does not give you this granularity since it blocks all connections.

Other thing, you should stop to use the old macros SIGNAL() and SLOT() and use the new signal-slot syntax instead.

So in your case, the connection would be something like:

connect(clipBoard, &QClipboard::dataChanged, this, &FenClient::copiage);

And the symmetric disconnection:

disconnect(clipBoard, &QClipboard::dataChanged, this, &FenClient::copiage);

Note that QObject::disconnect() really removes the connection so if you want to get it back, you'll need to recreate it by calling QObject::connect() again.