【问题标题】:Temporarily deactivating a connection Qt C++暂时停用连接 Qt C++
【发布时间】:2020-01-20 14:44:21
【问题描述】:

我正在尝试暂时删除此连接:

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

我已尽我所能,但总是以崩溃告终。我真的不知道是什么原因造成的。当我尝试在该行之前停用连接(第 93 行)时,它总是崩溃:

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

我的想法是,当程序本身更改剪贴板时,我不想要连接。

任何人都可以帮助我了解它为什么会崩溃?

这是.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

这是.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);
}


【问题讨论】:

  • 建议:停止使用旧的基于字符串的SIGNALSLOT 宏,如果它们不匹配,它们会在运行时“静默”地失败。改用新的编译时检查(和更快)的基于成员函数指针的语法。

标签: c++ qt qclipboard


【解决方案1】:

在你的构造函数定义中,你写了:

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

你应该改写:

clipBoard = QGuiApplication::clipboard();

既然clipBoard 是您的FenClient 类的字段成员,您为什么要尝试声明另一个与现有变量同名的局部变量(可能仍未初始化)?

实际上,这可能是您的 clipBoard::blockSignals() 失败的原因。
您已屏蔽了您的 clipBoard 字段成员。 换句话说,它从未被初始化。

取消引用未初始化的指针会导致未定义的行为。任何事情都有可能发生,在你的情况下你遇到了崩溃。

我没有阅读你的整个代码,所以它可能包含其他问题。


注意:

要删除连接,最好使用QObject::disconnect() 方法。

它可以让您更准确/更具体(关于要删除哪些连接,...)。 QObject::blockSignals() 没有提供这种粒度,因为它会阻止所有连接。

另外,你应该停止使用旧的宏 SIGNAL()SLOT() 并改用 new signal-slot syntax

因此,在您的情况下,连接将类似于:

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

以及对称断开:

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

请注意,QObject::disconnect() 确实会删除连接,因此如果您想恢复连接,则需要再次调用 QObject::connect() 来重新创建它。

【讨论】:

  • 您的解释很有帮助!非常感谢 Fareanor 和 eyllanesc!问题解决了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-12
  • 2017-03-10
  • 1970-01-01
相关资源
最近更新 更多