• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Qt C++, wywołanie metody pomiędzy klasami

Object Storage Arubacloud
0 głosów
311 wizyt
pytanie zadane 19 listopada 2020 w C i C++ przez Foszy Początkujący (250 p.)

Witam,

od jakiegoś czasu uczę się framework'a Qt i jakieś dwa dni temu pojawił się pewien problem, a mianowicie utknąłem na próbie wywołania metody z klasy A (przykładowa nazwa dla zobrazowania) w klasie B.

Szukałem po forach, stronach, czytałem dużo o slotach i sygnałach próbując działać, niestety z marnym skutkiem, ponieważ albo generowałem błędy a jak udało mi się je zwalczyć to program po prostu nie działał jak powinien.

Metoda w klasie A którą chciałbym wywołać (umieszczałem ją w A.h jako slot oraz jako public i z pliku main mogłem utworzyć obiekt i ją wywołać lecz w klasie B już nie) :

void MainWindow::sendMessage(QString message){

    ui->mainLog->append(message);

}

 

Klasa B(tutaj mam metodę w pliku B.h jako public connect):

void ConnectToServer::Connect()

{

   socket = new QTcpSocket(this);   //tworzenie gniazdka o nazwie socket  

   socket -> connectToHost("192.168.1.3", 1234);   // próba podłaczenia pod dany adres i port

   if(socket->waitForConnected(3000))

   {

       qDebug() << "Connected";

       socket -> write("TestServer");      //wysłanie wiadomosci do servera

       socket -> waitForBytesWritten(1000);    // czas na wysłanie

      
       socket -> waitForReadyRead(3000);      // czas na nasłuch

       qDebug() <<"Reading: " << socket -> bytesAvailable();   //czeka na liczbe bitów do odczytu

       qDebug() << socket -> readAll();         //odczytuj       

       socket -> close();         //zamkniecie polaczenia

   }

 

Przed wywołaniem socket -> close() próbowałem wywołać właśnie metodę sendMessage.

próbowałem tworzyć przed if'em w funkcji connect MainWindow *user = new MainWindow(); i działać na tym obiekcie lecz tak jak wspomniałem wcześniej z marnym skutkiem, czy mógłby ktoś mnie nakierować/pomóc przy okazji tłumacząc w miare dlaczego tak mam to wykonać?

 

 

 

 

komentarz 19 listopada 2020 przez tangarr Mędrzec (154,860 p.)
To jest kod wielowątkowy? Podrzuć więcej kodu.
komentarz 19 listopada 2020 przez Foszy Początkujący (250 p.)

Multithreading posiadam na osobnej aplikacji jako serwer tutaj jest tylko połączenie do tego serwera.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QDebug>
#include "connecttoserver.h"



QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    void sendMessage(QString message);



private:
    Ui::MainWindow *ui;


};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->mainLog->setDisabled(true);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::sendMessage(QString message)
{
    ui->mainLog->append(message);
}
#ifndef CONNECTTOSERVER_H
#define CONNECTTOSERVER_H

#include <QObject>
#include <QTcpSocket>
#include <QDebug>
#include "mainwindow.h"



class ConnectToServer : public QObject
{
    Q_OBJECT
public:
    explicit ConnectToServer(QObject *parent = nullptr);
    void Connect();

private:
    QTcpSocket *socket;

};

#endif // CONNECTTOSERVER_H
#include "connecttoserver.h"

ConnectToServer::ConnectToServer(QObject *parent) : QObject(parent)
{

}

void ConnectToServer::Connect()
{
   socket = new QTcpSocket(this);   //tworzenie gniazdka o nazwie socket  

   socket -> connectToHost("192.168.1.3", 1234);   // próba podłaczenia pod dany adres i port
   if(socket->waitForConnected(3000))
   {
       qDebug() << "Connected";
       socket -> write("TestServer");                       //wysłanie wiadomosci do servera
       socket -> waitForBytesWritten(1000);                          // czas na wysłanie

       socket -> waitForReadyRead(3000);                           // czas na nasłuch
       qDebug() <<"Reading: " << socket -> bytesAvailable();      //czeka na liczbe bitów do odczytu
       qDebug() << socket -> readAll();                          //odczytuj


       socket -> close();                                      //zamkniecie polaczenia


   }else
   {
      qDebug() << "Problem with connected";

   }

}

 

komentarz 19 listopada 2020 przez tangarr Mędrzec (154,860 p.)
Gdzie tworzysz obiekt klasy ConnectToServer?
komentarz 19 listopada 2020 przez tangarr Mędrzec (154,860 p.)
Dlaczego pliki nagłówkowe dołączają się nawzajem? Będziesz miał przez to problemy.
komentarz 19 listopada 2020 przez Foszy Początkujący (250 p.)

Hmm nie tworzyłem obiektu klasy ConnectToServer tylko MainWindow w funkcji Connect() zaraz po utworzeniu

socket = new QTcpSocket(this);

a do wysłania sygnału używałem właśnie obiektu socket. Tak teraz patrzę, że to obiekt nie klasy connecttoserver a QTcpSocketu czy to mogła być przyczyna braku reakcji programu na connect? Bo w sumie socket to też obiekt który ma możliwość wysłania sygnału jeśli się nie myle. A może jest inna możliwość wywołania metody?

A co do dołączenia plików nagłówkowych to było to już takie próbowanie wszystkiego jak tyle czasu się zmagałem i dalej nie działało.

1 odpowiedź

0 głosów
odpowiedź 19 listopada 2020 przez tangarr Mędrzec (154,860 p.)
wybrane 19 listopada 2020 przez Foszy
 
Najlepsza

W kodzie który pokazałeś nie ma ani sygnałów ani slotów ani tworzenia obiektów które mają się komunikować.
Aby używać mechanizmu sygnałów i slotów musisz:
- zdefiniować sygnał
- zdefiniować slot
- połączyć sygnał ze slotem (możesz łączyć wiele sygnałów do wielu slotów)
- wyemitować sygnał

class Nadawca : public QObject {
Q_OBJECT
signals:
    void sygnal(QString argument);
public:
    void wyslijSygnal(const QString &argument) {
        emit sygnal(argument);
    }
};

class Odbiorca : public QObject {
Q_OBJECT
public slots:
    void slot(const QString &argument) {
        qDebug() << Q_FUNC_INFO << argument;
    }
};

//------ połączenie--------
auto nadawca = new Nadawca();
auto odbiorca = new Odbiorca();
QObject::connect(nadawca, &Nadawca::sygnal, odbiorca, &Odbiorca::slot);
nadawca.wyslijSygnal("Ala ma kota");
komentarz 19 listopada 2020 przez Foszy Początkujący (250 p.)

Pozmieniałem kod według twojego wzorca, program nie wyrzuca mi żadnych błędów ale niestety nie działa.

Wrzucam kod:

#ifndef CONNECTTOSERVER_H
#define CONNECTTOSERVER_H

#include <QObject>
#include <QTcpSocket>
#include <QDebug>
#include "mainwindow.h"

class ConnectToServer : public QObject
{
    Q_OBJECT
signals:
    void sygnal(QString argument);
public:
    explicit ConnectToServer(QObject *parent = nullptr);
    void Connect();
    void wyslijSygnal(const QString &argument);

private:
    QTcpSocket *socket;

};

#endif // CONNECTTOSERVER_H
#include "connecttoserver.h"

ConnectToServer::ConnectToServer(QObject *parent) : QObject(parent)
{

}

void ConnectToServer::wyslijSygnal(const QString &argument)
{
    emit sygnal(argument);
}
void ConnectToServer::Connect()
{
   socket = new QTcpSocket(this);   //tworzenie gniazdka o nazwie socket  
   MainWindow *odbiorca = new MainWindow();
   ConnectToServer *sender = new ConnectToServer();

   socket -> connectToHost("192.168.1.3", 1234);   // próba podłaczenia pod dany adres i port
   if(socket->waitForConnected(3000))
   {
       qDebug() << "Connected";
       socket -> write("TestServer");                       //wysłanie wiadomosci do servera
       socket -> waitForBytesWritten(1000);                          // czas na wysłanie

       socket -> waitForReadyRead(3000);                           // czas na nasłuch
       qDebug() <<"Reading: " << socket -> bytesAvailable();      //czeka na liczbe bitów do odczytu
       qDebug() << socket -> readAll();                          //odczytuj

       connect(sender, &ConnectToServer::sygnal,odbiorca,&MainWindow::sendMessage);
       sender->wyslijSygnal("Test");
       
       socket -> close();                                      //zamkniecie polaczenia


   }else
   {
      qDebug() << "Problem with connected";

   }

}
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QDebug>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

public slots:
    void sendMessage(const QString& message);



private:
    Ui::MainWindow *ui;


};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->mainLog->setDisabled(true);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::sendMessage(const QString& message)
{
    ui->mainLog->append(message);
}

 

komentarz 19 listopada 2020 przez tangarr Mędrzec (154,860 p.)
Czy masz uruchomioną pętlę zdarzeń (event loop)?
Pokaż kod funkcji main.
W tym kodzie tworzysz okno, ale nigdy go nie wyświetlasz.
komentarz 19 listopada 2020 przez Foszy Początkujący (250 p.)
#include "mainwindow.h"
#include "connecttoserver.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    ConnectToServer _socket;    
    _socket.Connect();
    return a.exec();
}

 

komentarz 19 listopada 2020 przez tangarr Mędrzec (154,860 p.)

Chyba nie rozumiesz czym jest klasa a czym instancja danej klasy.
Połączenie robisz między dwoma konkretnymi obiektami. A nie między klasami. Obiekty odbiorca i sender, które utworzyłeś to niezależne obiekty, które nie biorą udziału w tym co się dzieje. Usuń je z kodu oraz cały kod, który się do nich odwołuje.
Połączenie między istniejącymi obiektami musisz zdefiniować w funkcji main.

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    ConnectToServer _socket;
    
    QObject::connect(&_socket, &ConnectToServer::sygnal, &w, &MainWindow::sendMessage);

    _socket.Connect();
    return a.exec();
}

Tak utworzone połączenie będzie działać tylko między obiektem _socket i w. Jeżeli potworzysz nowe instancje klas MainWindow lub ConnectToServer to one nie będą widziały (ani używały) tego połączenia.

komentarz 19 listopada 2020 przez tangarr Mędrzec (154,860 p.)
Aha i jeszcze jedno:
Funckję wyslijSygnal musisz wykonać na aktualnym obiekcie (this). A jeszcze lepiej usuń tą funkcję i bezpośrednio emituj sygnał.
komentarz 19 listopada 2020 przez Foszy Początkujący (250 p.)
Bardzo Ci dziękuje, rozjaśniłeś mi teraz sprawę i w miare rozumiem. Pozmieniałem co trzeba i wszystko działa, jeszcze raz dzięki wielkie!

Edit: Tak tak do tego już doszedłem gdy mi to wyjaśniłeś.
komentarz 19 listopada 2020 przez tangarr Mędrzec (154,860 p.)
Polecam się na przyszłość :)

Podobne pytania

+1 głos
1 odpowiedź 481 wizyt
pytanie zadane 9 grudnia 2017 w C i C++ przez Marcin_N_97 Stary wyjadacz (10,290 p.)
+1 głos
1 odpowiedź 164 wizyt
pytanie zadane 8 kwietnia 2016 w PHP przez Niespecjalny Gaduła (4,180 p.)
0 głosów
3 odpowiedzi 434 wizyt
pytanie zadane 16 czerwca 2015 w C i C++ przez tarnasm Gaduła (3,030 p.)

92,575 zapytań

141,424 odpowiedzi

319,649 komentarzy

61,960 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...