Signal no being emitted from within slot



  • Hello!

    I am having a problem with a signal that's not being emitted from within a slot. I got the same signal being emmitted from another method and it works fine, but if I try to emmit the same signal from other part of the code, it simply does not work.

    I have 3 classes:

    OrderHandler:

    #ifndef ORDERHANDLER_H
    #define ORDERHANDLER_H
    
    #include <QObject>
    #include <QJsonDocument>
    #include <QJsonObject>
    #include <QVariantMap>
    #include <QTimer>
    #include <QNetworkAccessManager>
    #include <QNetworkRequest>
    #include <QNetworkReply>
    #include <QSettings>
    #include <QUrl>
    #include <QtCore/QDebug>
    
    #include "order.h"
    #include "dbhandler.h"
    
    
    //typedef QList<Order> OrderList;
    
    
    
    #define ORDERS_URL "http://usereserva.dyndns.org:8082/ReservaQuiosqueAPI/api/LojaPedido/ObterListaPedidos/2017-10-31"
    #define STATUS_URL "http://usereserva.dyndns.org:8082/ReservaQuiosqueAPI/api/LojaPedido/DefinirStatusPedido/"
    
    
    
    
    class OrderHandler : public QObject
    {
        Q_OBJECT
    public:
        explicit OrderHandler(QObject *parent = 0);
        ~OrderHandler();
        void  getNewOrders(void);
        void  processJsonOrder(QString);
        void  setOrderStatus(quint32, quint32);
    
        void storeOrder(Order *order) {
            orderList.append(order);
        }
    
        Order *getOrder(qint32 idx) {
            return orderList.at(idx);
        }
    
        size_t getOrderListSize() {
            return orderList.size();
        }
    
    
    
    
    private:
        QTimer                *timer;
        DbHandler     		  *dbhandler;
        QNetworkAccessManager *manager;
        QNetworkRequest       *request;
    
        OrderList orderList;
    
        enum PayStatus {
            NOT_PAID   = 10,
            PAID       = 20
        };
    
        enum ProdStatus {
            PENDING    = 10,
            PRODUCTION = 30,
            EXPEDITION = 40 //FINISHED
        };
    
        //INTERNAL CONTROL
    
        enum TermStatus {
            NOT_PRINT = 10,
            PRINT     = 20,
            COLLECTED = 30
        };
    
        enum DeliveryStatus {
            NOT_COLLECTED = 10,
            COLLECT       = 20,
            REJECTED      = 30,
            CANCELLED     = 50
        };
    
    
    public Q_SLOTS:
        bool checkNewOrders(void);
        void replyFinished (QNetworkReply *);
        bool receiveOrder(Order *);
    
    
    Q_SIGNALS:
        bool newOrderAvailable(Order *);
    
    
    };
    
    #endif // ORDERHANDLER_H
    

    This class emmits the signal newOrderAvailable(Order *) that is connected to the main window.

    MainWin:

    connect(order_handler, &OrderHandler::newOrderAvailable, this, &MainWin::addOrder);
    

    This is the MainWindow header file:

    #ifndef MAINWIN_H
    #define MAINWIN_H
    
    #include <QMainWindow>
    #include <QMessageBox>
    #include <QTableWidget>
    #include <QListWidgetItem>
    #include <QTextStream>
    #include <QFile>
    #include <QPrinter>
    #include <QDialog>
    #include <QPrintDialog>
    #include <QTextDocument>
    #include <QDebug>
    #include <QKeyEvent>
    #include <QSignalSpy>
    
    
    //#include "requestserver.h"
    #include "orderhandler.h"
    #include "order.h"
    //#include "dbhandler.h"
    
    
    namespace Ui {
    class MainWin;
    }
    
    class MainWin : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWin(QWidget *parent = 0);
        ~MainWin();
    
    private:
    
        Ui::MainWin   *ui;
        OrderHandler  *order_handler;
    
        //bool event(QEvent *event);
        enum Column {
            COD_ORDER            = 0,
            CLIENT_NAME          = 1,
            PAY_STATUS           = 2,
            NUM_ITEM_ORDER       = 3,
            PROD_STATUS          = 4,
            TERM_STAUS           = 5,
            DELIVERY_STATUS      = 6,
            PRED_DELIVERY_STATUS = 7
        };
    
        void addOrderFormmated(QTableWidget *, int, int, QTableWidgetItem *);
        void itemSelected(QListWidgetItem *);
        void printTerm(void);
    
    protected:
    
    
    public slots:
        void rowSelected(int, int);
        bool addOrder(Order*);
    };
    
    #endif // MAINWIN_H
    
    

    When I emmit newOrderAvailable from OrderHandler::processJsonOrder, it works fine, but I when I emmit the same signal from receiveOrder(Order *), the main windows does no receive it:

    bool OrderHandler::receiveOrder(Order *order) {
        qDebug() << "Order Received: " << order->id << order->client_name << order->delivery_status;
        storeOrder(order);
        emit newOrderAvailable(order);
    
        return true;
    }
    
    
    

    On the main window, the signal and slot is connected:

    connect(order_handler, &OrderHandler::newOrderAvailable, this, &MainWin::addOrder);
    

    Any help is appreciated! Thaks :D


  • Qt Champions 2016

    Hi
    Just to be sure , botch cases are in same class just different functions?
    And no threads involved ?

    Also is receiveOrder(Order *) involved in any kind of loop and processJsonOrder is not ?



  • Hi!
    Yes, both cases are in the same class, OrderHandler, no threads involved.
    processJsonOrder emmits the newOrderAvailable(Order*) signal from a for-loop, but receiveOrder has no loops. It only receives a signal from another class (DbHandler) and reemmits the received Order*.

    connect(dbhandler, &DbHandler::pendingOrders, this, &OrderHandler::receiveOrder);
    

    In DbHandler, I have a loop that emmits pendingOrders(Order *) and works fine, since the SLOT from OrderHandler is being called. The problem is when this SLOT tries to emmit the newOrderAvailable SIGNAL, nothing happens :(


  • Qt Champions 2016

    Hi
    Sounds very odd. ( as it so equal in use)
    So the working case have a for loop but the non working has not :)

    Could you try with

    connect(dbhandler, &DbHandler::pendingOrders, this, &OrderHandler::receiveOrder, Qt::DirectConnection);

    Ps. slots are just normal c++ member functions so it should be any different to emit from there than any place else.



  • @mrjj said in Signal no being emitted from within slot:

    connect(dbhandler, &DbHandler::pendingOrders, this, &OrderHandler::receiveOrder, Qt::DirectConnection);

    Yes, really odd, since it's working from another call. I tried your advice but nothing changed :( Take a look at the following code.
    emit newOrderAvailable(newOrder) works fine here and MainWin receives the data.

    void OrderHandler::processJsonOrder(QString orderRawData) {
    
        QJsonDocument jsonOrderData  = QJsonDocument::fromJson(orderRawData.toLocal8Bit());
    
        if(jsonOrderData.isNull()){
            qDebug() << "Failed to create JSON doc.";
            return;
        }
    
        if(!jsonOrderData.isObject()){
            qDebug() << "JSON is not an object.";
            return;
        }
    
        QJsonObject jsonObj = jsonOrderData.object();
    
        if (jsonObj.isEmpty()) {
            qDebug() << "JSON object is empty.";
            return;
        }
    
        QVariantMap   rootMap       = jsonObj.toVariantMap();
        QVariantList  infoResultado = rootMap["infoResultado"].toList();
    
        for (int i = 0; i < infoResultado.size(); i++) { //iterate over a list of orders
            QVariantMap orderInfo = infoResultado.at(i).toMap();
    
            quint32 orderId     = orderInfo["idPedido"].toInt();
            quint16 orderStatus = orderInfo["status"].toInt();
    
            bool orderExists = dbhandler->orderExists(orderId);
    
            if ((!orderExists) && (orderStatus == PayStatus::NOT_PAID)) {
                //qDebug() << "PEDIDO NOVO";
    
               //INSERT ORDER INTO DATABASE FROM HERE
                qDebug() << "Pedido: " << orderId;
    
                QVariantMap clientInfo = orderInfo["cliente"].toMap();
                qDebug() << "Cliente: " << clientInfo["nome"].toString().trimmed();
    
                QVariantList itemList = orderInfo["listaItensPreVenda"].toList();
    
                Order *newOrder = new Order(this);
    
                newOrder->id                   = orderId;
                newOrder->client_name          = clientInfo["nome"].toString().trimmed();
                newOrder->cpf                  = clientInfo["cpf"].toString();
                newOrder->payment_status       = PayStatus::NOT_PAID;
                newOrder->n_uniq_item          = itemList.size(); //numero itens unicos contidos no pedido
                newOrder->prod_status          = ProdStatus::PENDING;
                newOrder->term_status          = TermStatus::NOT_PRINT;
                newOrder->delivery_status      = DeliveryStatus::NOT_COLLECTED;
                //newOrder->pred_delivery_status = DeliveryStatus::NOT_COLLECTED;
    
                for(int j = 0; j < itemList.size(); j++) {
                    Item *newItem = new Item();
                    QVariantMap item = itemList.at(j).toMap();
                    QImage img, imgMini;
    
                    newItem->orderId       = newOrder->id;
                    newItem->prodCode      = item["codigoProduto"].toInt();
                    newItem->prodName      = item["descricao"].toString();
                    newItem->prodColorName = item["corDescricao"].toString();
                    newItem->prodSize      = item["grade"].toString();
                    newItem->numItens      = item["quantidade"].toInt();
    
                    //img.loadFromData(QByteArray::fromBase64(item["estampa"].toByteArray()));
                    //newItem->itemImg = img; //store big image
                    //qDebug() << "Image: " << item["miniatura"].toByteArray();
                    imgMini.loadFromData(QByteArray::fromBase64(item["miniatura"].toByteArray()), "PNG");
                    newItem->itemImgMini = imgMini; //store mini image
                    newOrder->addItem(newItem);
                }
    
                if(!dbhandler->insertOrder(newOrder))
                    return;
                else
                    storeOrder(newOrder);
    
                qDebug() << "Num. Itens: " << itemList.size();
                emit newOrderAvailable(newOrder);
    
            }
            else if (orderExists && (orderStatus == PayStatus::PAID) && (dbhandler->getPaymentStatus(orderId) == PayStatus::NOT_PAID)) {
                if (dbhandler->setPaymentStatus(orderId, PayStatus::PAID))
                    qDebug() << "Order " << orderId << " updated by POS and set to PAID";
            }
    
        }
    }
    
    

    Now, from bool OrderHandler::receiveOrder(Order *order), it does not emmit nothing or at least MainWin does not show anything.

    bool OrderHandler::receiveOrder(Order *order) {
        qDebug() << "Order Received: " << order->id << order->client_name << order->delivery_status;
        storeOrder(order);
        emit newOrderAvailable(order);
    
        return true;
    }
    

  • Qt Champions 2016

    ok
    That is odd. Must be related to a signal call the slot and in the slot we call emit but
    i dont see why. when using DirectConnection it should work like a function call.

    So whom send the signal that calls bool OrderHandler::receiveOrder(Order *order) ?

    As i understand it , the only difference is that
    in processJsonOrder, we emit directly newOrderAvailable .
    where as OrderHandler::receiveOrder is triggered via signal and then emit the newOrderAvailable ?
    Is that correctly understood?

    It seems this sends the signal ?
    connect(dbhandler, &DbHandler::pendingOrders, this, &OrderHandler::receiveOrder);
    can you try with QueuedConnection ? ( should not be needed. just testing if makes difference)



  • DbHandler calls bool OrderHandler::receiveOrder(Order *order) . Yes that'st the flow, you got it.

    DbHandler emits pendingOrder(Order *), OrderHandler receives the signal from DbHandler and emits newOrderAvailable(Order *) signal to MainWin::addOrder(Order *);

    connect(dbhandler, &DbHandler::pendingOrders, this, &OrderHandler::receiveOrder, Qt::DirectConnection);
    
    bool DbHandler::loadPendingOrders() {
    
        QSqlQuery orderQuery, itemQuery;
    
        // 10 == NOT_COLLECTED
        orderQuery.prepare("SELECT * from order_info WHERE delivery_status=10");
    
        if(!orderQuery.exec()) {
            qDebug() << orderQuery.lastError();
            return false;
        }
    
        int id              = orderQuery.record().indexOf("id");
        int client_name     = orderQuery.record().indexOf("client_name");
        int cpf             = orderQuery.record().indexOf("cpf");
        int n_uniq_itens    = orderQuery.record().indexOf("n_uniq_itens");
        int pag_status      = orderQuery.record().indexOf("pag_status");
        int prod_status     = orderQuery.record().indexOf("prod_status");
        int term_status     = orderQuery.record().indexOf("term_status");
        int delivery_status = orderQuery.record().indexOf("delivery_status");
    
        while (orderQuery.next()) {
            Order *order = new Order(this);
    
            order->id                   = orderQuery.value(id).toUInt();
            order->client_name          = orderQuery.value(client_name).toString();
            order->cpf                  = orderQuery.value(cpf).toString();
            order->payment_status       = orderQuery.value(pag_status).toUInt();
            order->n_uniq_item          = orderQuery.value(n_uniq_itens).toUInt();
            order->prod_status          = orderQuery.value(prod_status).toUInt();
            order->term_status          = orderQuery.value(term_status).toUInt();
            order->delivery_status      = orderQuery.value(delivery_status).toUInt();
    
            //qDebug() << "Load order from database: " << pendingOrder->id;
    
            //qDebug() << pendingOrder;
    
            emit pendingOrders(order);
        }
        return true;
    }
    

  • Qt Champions 2016

    Hi
    There must be something we are missing in regards to emit from a slot while
    a signal is in progress. ( i have not had this situation and it seems perfectly normal)

    I should be able to reproduce it if have
    a mainwindow and some widget i use for floating window
    that i show using ->show()
    in constructor (of floating window) i emit test("hello");

    and in the floating window i have a button and in its clicked, i also
    emit test("hello 2");

    Mainwindow should not get "hello 2" if something up.

    Does that sounds like same usage as you ?



  • Yes, looks like a similar case.
    Can I post my code somewhere? This way would be easier to debug or even see if the code has an explict error I'm not spotting.


  • Qt Champions 2016

    @Gabriel-Duarte
    Ok. super. I must do some shopping then i will try.
    You can use use google drive/dropbox and post link here (with zip file) or
    use https://www.filemail.com/
    ( you dont have to use real email adresses. just grab the URL in last page)
    and post url here. ( it expires in 6 days)

    Update:
    Tried a mock up example but in both cases it was emitted.

    The full source and data files would really help to spot it.


  • Qt Champions 2016

    Hi
    I asked for help/input and was suggested
    "my best guess is his DbHandler::loadPendingOrders simply is not called. make him break at the OrderHandler::receiveOrder at the qDebug statement and to pull the stack trace."

    Thats a good plan.

    Also full source code could also help to find out
    what goes wrong.
    It should work as far as i can see and understand from your code and
    explanations of the setup.



  • @mrjj REALLY thanks for your attention!
    You will post the source code.

    DbHandler::loadPendingOrders is being called, for sure, because my list of Orders is being increased and if I call qDebug() << "something" inside it, I can see some output coming from there but emit newOrderAvailable().

    emit pendingOrders(order) is being emitted from the method DbHandler:loadPendingOrders() at each order it gets from database.

    DbHandler->loadePendingOrders() is begin called inside OrderHandler constructor right after this:

    connect(dbhandler, &DbHandler::pendingOrders, this, &OrderHandler::receiveOrder, Qt::DirectConnection);
    
    dbhandler->loadPendingOrders();
    



  • Qt Champions 2016

    Hi
    Found it. ( i think) Logical error :)
    Would not have seen it without full code.
    In
    OrderHandler::OrderHandler(QObject *parent) : QObject(parent) {
    you hook up
    connect(dbhandler, &DbHandler::pendingOrders, this, &OrderHandler::receiveOrder, Qt::DirectConnection);
    // and call it
    dbhandler->loadPendingOrders();

    But since its inside the constructor of orderHandler,

    MainWin::MainWin(QWidget *parent) :
    {
    order_handler = new OrderHandler(this);// << loadPendingOrders() called here
    connect(order_handler, &OrderHandler::newOrderAvailable, this, &MainWin::addOrder); // but signal first hooked up here !

    so that is why nothing seems to happen.



  • @mrjj THANK YOU SO MUCH!

    Dumb logical error, thanks a lot for helping me out, for your attention and patience!


  • Qt Champions 2016

    @Gabriel-Duarte
    Well it was a sneaky one and easy to make.
    In fact, i mention as test case to emit in constructor and that
    would been same mistake.
    And you are welcome. happy saturday.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.