Please help with lambda sytax
-
I am looking at this
link textQObject::connect(ui->list, //object &QListWidget::itemClicked, //signal this, //object [this]( QListWidgetItem * pItem ) { this->ui->list_2->addItem( pItem ); };
And still getting an error
/media/f/QT/Qt/QT/qtconnectivity/examples/bluetooth/CAT_BT_18112020/device.cpp:181: error: expected ')' before ';' token [this]( QListWidgetItem * pItem ) { this->ui->list_2->addItem( pItem ); }; ^
the error "^" symbol points to the last ";" - it won't copy the "^" symbol at the correct place.
Please help me.
-
the kind of thing that a parenthesis checking editor would have found. LOL
-
OR RTFM as I did.
Now I am getting "no such number " ...no such soul...
Seriously - no such function errorthis->ui->list_2->addItem( pItem ); };
I give up...
-
@AnneRanch What is list_2?
Also, can you show the whole error? -
@AnneRanch
I think, you dont need lambdas for this.
You can just do this:// connection is correct, but wont work as expected or even crash QObject::connect(ui->list, &QListWidget::itemClicked, ui->list2, &QListWidget::addItem);
Note:
Warning: A QListWidgetItem can only be added to a QListWidget once. Adding the same QListWidgetItem multiple times to a QListWidget will result in undefined behavior.
(https://doc.qt.io/qt-5/qlistwidget.html#addItem-1)
If you want to use a lambda connection anyway, try without using
this
beforeui
.might be interesting
https://artandlogic.com/2013/09/qt-5-and-c11-lambdas-are-your-friend/ -
@Pl45m4
Untested by me, but, lambda or not, this (and the OP's original code) attempts to (re-)add an existingQListWidgetItem
which is inui->list
as an item in another list,ui->list2
. Doesn't runtime forbid this, doesn't a givenQListWidgetItem
have to belong to just oneQListWidget
(as returned byQListWidget *QListWidgetItem::listWidget() const
)? Don't you have to either remove it first or copy it? That's how it works in C#/.NET! (Or, does it move it across from the existingQListWidget
to the other one??)I will strike this out if you say it does work....
-
@JonB said in Please help with lambda sytax:
Doesn't runtime forbid this, doesn't a given QListWidgetItem have to belong to just one QListWidget (as returned by QListWidget *QListWidgetItem::listWidget() const)? (Or, does it move it across from the existing QListWidget to the other one??)
Haven't checked it either... Well, now that you mention it, it makes sense :)
But wouldn't it cause a runtime crash or error?! The connection as such, which is a problem apparently, shouldn't be the problem here.
So to transfer one item from one
QListWidget
to another, @AnneRanch needs to take it from the first one or create a new one with same properties -> Lambda :-)Edit:
This
Don't you have to either remove it first or copy it?
-
@Pl45m4
Indeed, theconnect()
itself would be fine, both at compile & runtime. The question is what theQListWidget::addItem
will do when the item is clicked on and the slot is called.... Which the OP will get to once her compilation goes through and she tries out the behaviour, I'm trying to anticipate.... -
Why do you discuss instead looking at the source?
void QListWidget::insertItem(int row, QListWidgetItem *item) { Q_D(QListWidget); if (item && !item->view) d->listModel()->insert(row, item); }
-
@Christian-Ehrlicher
Because I like reasoning/guessing it through? I still don't know the effect because I don't know what setsitem->view
, so I'd have to follow that, and/or what thatinsert()
does/does not do. It's not germane to the OP's query about how to write the syntax, it's just it may not produce the behaviour she might be expecting to see at runtime, so it was just a potential caveat from me. -
@jsulm said in Please help with lambda sytax:
@AnneRanch What is list_2?
Also, can you show the whole error?The original , wrong ";" , whole error was already posted.
The ";" error was found and corrected.Now the error is
/media/f/QT/Qt/QT/qtconnectivity/examples/bluetooth/CAT_BT_18112020/device.cpp:181: error: no matching function for call to 'DeviceDiscoveryDialog::connect(QListWidget*&, void (/media/f/QT/Qt/QT/qtconnectivity/examples/bluetooth/CAT_BT_18112020/device.cpp:181: error: no matching function for call to 'DeviceDiscoveryDialog::connect(QListWidget*&, void (QListWidget::*)(QListWidgetItem*), DeviceDiscoveryDialog*, DeviceDiscoveryDialog::DeviceDiscoveryDialog(QWidget*)::<lambda(QListWidgetItem*)>)' [this]( QListWidgetItem * pItem ) { this->ui->list_2->addItem ( pItem ); }) ; ^::*)(QListWidgetItem*), DeviceDiscoveryDialog*, DeviceDiscoveryDialog::DeviceDiscoveryDialog(QWidget*)::<lambda(QListWidgetItem*)>)' [this]( QListWidgetItem * pItem ) { this->ui->list_2->addItem ( pItem ); }) ; ^
Both list's are QListWidget
This whole exercise is my desire to learn how to code "connect". I am trying to duplicate QtDesigner WORKING "connect". See attached screen shot. I went too far and started with copying "item" from one dialog to "main dialog". That when things got convoluted with QOverload ( handling "item" as a string ) and lambda.
So far I have learn that Intelisense and lambda do not mix - I cab "addItem" using Intelisense ( legal) but it there but compiler complains there is not "addItem ".
"click" and "itemchanged" are not the same - no surprise here.I am still looking into lambda doc and my head is spinning.
( I am not sure why lambda "mixes " QListWidget and QListWidgetItem)This is still a learning exercise and I like to go back and copy the QtDesigner WORKING XML to plain C++ code and make it work in ONE dialog.
Then tackle same and make it work between dialog and main dialog - using "new " connect style. ( It would be nice if QtDesigner did "new connect style " too. )
Using lambda is last on my TODO list, but I am open to suggestions.Thanks
-
@AnneRanch
Can you please clarify what your final goal is? It seems that some of your recent topics (incl. this one) are going in the wrong direction...
You started here with an error in your connect statement, but we obviously can not know whether your connection makes sense in your case or not.
If you want to transfer (i.e. "copy") items, you've clicked in one listWidget to the second listWidget, do what @JonB suggested here.
addItem
only works, if you have a "free"QListWidgetItem
. So even if we correct your mistake, it wont help you or work at all.
The item, that the clicked function returns, belongs already to oneQListWidget
, so you cant just add it to a second one.Changing your code inside lambda to this might work (not tested)
// creates a copy of the clicked item, instead of trying to move it QListWidgetItem * newItem = new QListWidgetItem(pItem); ui->list_2->addItem( newItem );
The connection as seen in your picture equals somewhat like this (lambda style):
connect(ui->list, &QListWidget::currentTextChanged, [=](QString s){ ui->plainTextEdit2->appendPlainText(s); });
-
@Pl45m4 said in Please help with lambda sytax:
@AnneRanch
Can you please clarify what your final goal is? It seems that some of your recent topics (incl. this one) are going in the wrong direction...
You started here with an error in your connect statement, but we obviously can not know whether your connection makes sense in your case or not.
If you want to transfer (i.e. "copy") items, you've clicked in one listWidget to the second listWidget, do what @JonB suggested here.
addItem
only works, if you have a "free"QListWidgetItem
. So even if we correct your mistake, it wont help you or work at all.
The item, that the clicked function returns, belongs already to oneQListWidget
, so you cant just add it to a second one.Changing your code inside lambda to this might work (not tested)
// creates a copy of the clicked item, instead of trying to move it QListWidgetItem * newItem = new QListWidgetItem(pItem); ui->list_2->addItem( newItem );
The connection as seen in your picture equals somewhat like this (lambda style):
connect(ui->list, &QListWidget::currentTextChanged, [=](QString s){ ui->plainTextEdit2->appendPlainText(s); });
In general terms - The objective is to copy an item from one widget to another.
It is actually QString, not a generic "item" I want to copy.The QtDesigner does that with the screen shot of SIGNAL/SLOT I have posted. No problem.
Yes, I do not know how to convert QtDesigner XML GUI to plain C code, but if QtDesigner apparently works without creating new "item" why is it necessary to create new item in code? But that is not main issue.
To avoid further r misunderstanding - help me to duplicate XML in C code first . Then do the lambda and then copy between dialogs. Baby steps.
I can just temporary delete the QtDesigner XML to test the plain C code.
Perhaps screen shot what I have now?
Eventually "automatically" copy each line of text from Bluetooth scanner dialog "nearby BT devices" to main window Tab2 "nearby BT devices".
The unnamed text under "Connect" button , done by QtDesigner, is what I want to duplicate in code.
-
Please note - I am posting this to illustrate the problem, please please please - NO comments on my programming style!
My primary goal is to duplicate XML "connect" using code.
The attached code and its variations generally compiles - that is one goal done.HOWEVER - it crashes during run time and I SUSPECT the problem is
after
clicking button 11 my code builds new instance of scanner dialog and it has build-in timers . The "list" is , in theory, filed AFTER each item individual timer expire.
BUT
my test connect is executed immediately after the first timer expires and the "item" is changed .I am asking - is it possible I have a timing problem?
Here is my current - under construction connect to copy the "list" lines.
All it does - just compiles and cannot be tested , in existing code , due to this issue.#ifdef BYPASS // interacts with pushing buitto 11 // keeps crashing connect( this->ui->list, // SIGNAL(ui->list->currentTextChanged()), SIGNAL(ui->list->itemDoubleClicked(*pItem)), // SIGNAL(DDD->ui->list->itemChanged(TEST_LABEL)), // SIGNAL(itemClicked(QListWidgetItem *)), // SIGNAL(itemChanged(TEST_LABEL)), this->ui->plainTextEdit, // SLOT(DDD->ui->plainTextEdit->appendPlainText(TEST_LABEL)) // SLOT(appendPlainText(TEST_LABEL)) SLOT(ui->plainTextEdit->appendPlainText(*pItem))); // ); #endif
This is how it tracks when working - without the code above
QDEBUG TRACE QDEBUG TRACE TASK END imoplement Device DiscoiveryDialog QDEBUG TRACE TASK find nearby BT devices file /media/f/QT/QT_PROJECT/TEST_PROJECT_14/mainwindow_cat_tab.cpp function on_pushButton_11_clicked @line 236 TEMPORARY EXIT /home/f/build-TEST_PROJECT-Desktop-Debug/TEST_PROJECT exited with code 0
And this is failing track
QDEBUG TRACE QDEBUG TRACE TASK START imoplement Device DiscoveryDialog QDEBUG TRACE TASK find nearby BT devices file /media/f/QT/QT_PROJECT/TEST_PROJECT_14/mainwindow_cat_tab.cpp function on_pushButton_11_clicked @line 206 TEMPORARY EXIT TRACE SCAN FLOW START TOK TRACE SCAN FLOW CONSTRUCTOR DeviceDiscoveryDialog::DeviceDiscoveryDialog(QWidget *parent) TEMPORARY exit @line 133 The program has unexpectedly finished. /home/f/build-TEST_PROJECT-Desktop-Debug/TEST_PROJECT crashed
Again - all I am asking - is it possible I have a timing problem?
-
@AnneRanch said in Please help with lambda sytax:
connect(
this->ui->list,
// SIGNAL(ui->list->currentTextChanged()),
SIGNAL(ui->list->itemDoubleClicked(*pItem)),
// SIGNAL(DDD->ui->list->itemChanged(TEST_LABEL)),
// SIGNAL(itemClicked(QListWidgetItem *)),
// SIGNAL(itemChanged(TEST_LABEL)),
this->ui->plainTextEdit,
// SLOT(DDD->ui->plainTextEdit->appendPlainText(TEST_LABEL))
// SLOT(appendPlainText(TEST_LABEL))
SLOT(ui->plainTextEdit->appendPlainText(*pItem)));
// );This is invalid connect() call. Please check https://doc.qt.io/qt-5/signalsandslots.html And it is better to use Qt5 connect() syntax to detect such issues during compile time instead of run time.
It should beconnect( this->ui->list, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this->ui->plainTextEdit, SLOT(appendPlainText(QListWidgetItem*)));
But this will also not work as QPlainTextEdit does not have a slot appendPlainText which takes a QListWidgetItem* as parameter (use new Qt5 connect syntax and a lambda)...
-
@AnneRanch
As @jsulm has said. As long as you use the old-styleSIGNAL
&SLOT()
macros, you are liable to have code which compiles OK but does not behave correctly at runtime. With the new style syntax, if the signal/slot code is wrong, you get told at compile-time. It might seem harder to get it right, but at least you know that when it does compile it will do what you expect when you run it; if it does not compile, you have to sort it out to be correct at that stage. -
@jsulm said in Please help with lambda sytax:
But this will also not work as QPlainTextEdit does not have a slot appendPlainText which takes a QListWidgetItem* as parameter (use new Qt5 connect syntax and a lambda)...
I do appreciate the post.
It may seems strange, but at this point I am NOT after "it" working.
I just need to figure out WHY adding this "connect" , in any form or format , crashes the program.
After I figure out the crasher I will work on form / format/ style.
Of course I could verify the "connect" using separate test program. -
@AnneRanch said in Please help with lambda sytax:
function on_pushButton_11_clicked
@line 206Can you show your on_pushButton_11_clicked? The crash is there at line 206.
-
@AnneRanch
Back to lambdas:
You said, you are struggling to understand lambda connections correctly.
It's not as complicated as it might look.-
You have your sender (first argument)
connect(ui->list,.....)
-
You have your sender's class + signal
connect(ui->list, &QListWidget::itemDoubleClicked,.....)
-
Then you can define a scope for your lambda
connect(ui->list, &QListWidget::itemDoubleClicked, this,......)
-
the last part consists of the capture, the function or slot arguments and the actual code itself, using the passed and captured values
-
Capture
- "
[ ]
": None of the variables from current class / scope are captured and can be used inside lambda "code" - "
[=]
": Captures everything (by value!) - "
[this]
": (current instance) or any combination of variables (e.g.[x, a]
), to pick variables you need explicitely. - "
[&]
" or "[ &someVar ]
": Captures by reference. Changes made inside lambda will affect and change the captured variable outside the lambda as well ( Thx, @JonB )
- "
-
Signal / Slot arguments after capture inside
( .... )
, e.g. if signal sends aQListWidgetItem
, you need a(QListWidgetItem *item)
here. -
lambda code inside
{ .... }
- do whatever you like and what you would put in your slot here.
-
One big advantage using lambda connections is, that you can connect signals to slots (or "code"), that would be incompatible using a "direct" connection because of any reason (e.g. parameter mismatch).
Simple example:
// signal void signal(QString s); // slot void onSignalFired(int i);
A direct connection of these two won't work neither using the
SIGNAL(...) / SLOT( ... )
syntax
(-> crash / error at runtime),
nor using the function based connection&Class::signal... &Class::onSignalFired
( -> wont compile).With lambda, you can make it work:
connect(this, &Class::signal, [] (QString s) { onSignalFired( s.toInt() ); } );
Instead of calling the slot, you could also skip the slot and do whatever you want to do with this string inside the lambda directly, e.g. send your number to a
QLineEdit
("A" would lead to a 65, simple ASCII).@AnneRanch said in Please help with lambda sytax:
Here is my current - under construction connect to copy the "list" lines.
All it does - just compiles and cannot be tested , in existing code , due to this issue.... and this is exactly where you can make use of lambdas ( as @jsulm already said ).
Pass yourQListWidgetItem
from signal to your lambda, get the text from your item usingtext()
(Qt Doc), then pass the text toQPlainTextEdit
'sappendPlainText(QString)
. -