Solved Signal no being emitted from within slot
-
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 :(
-
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; }
-
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; }
-
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. -
@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.
-
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();
-
-
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!
-
@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.