Qt 5.11, QWidget and creating a window and connecting to signals - c++

I am dynamically creating new windows using:
QWidget* pobjWin = new QWidget();
pobjNode->setWidget(pobjWin);
pobjWin->resize(intWidth, intHeight);
pobjWin->move(intX, intY);
This works and in my application I have 3 windows, I want to connect to the various signals that according to the online documentation are:
activeChanged
contentOrientationChanged
focusObjectChanged
...
In my application as an example I connect to these signals with:
QObject::connect(pobjWin, SIGNAL(activeChanged(void))
,pobjSubNode
,SLOT(windowSlotActiveChanged(void)));
The pointer 'pobjSubNode' points to a class which has defined slots for each of the signals I am connecting to.
When I run this and the connects are executed I get:
2018-10-25 16:26:39.550030+0100 XMLMPAM[2048:219099] QObject::connect: No such signal QWidget::activeChanged(void) in ../XMLMPAM/clsMainWnd.cpp:733
I think the issue is because the pobjWin points to a QWidget and not a QWindow, but I couldn't find an example that doesn't create a window this way.
[Edit] Using the new connection method:
QObject::connect(pobjWin, &QWindow::activeChanged
,pobjSubNode, &clsXMLnode::windowSlotActiveChanged);
The prototypes for activeChanged and windowSlotActiveChanged are identical. But when I build with this implementation I get:
/Users/simonplatten/XMLMPAM/clsMainWnd.cpp:733: error: no matching function for call to 'connect'
QObject::connect(pobjWin, &QWindow::activeChanged
^~~~~~~~~~~~~~~~
[Edit2] I've changed the connect to:
QObject::connect(pobjWin->windowHandle(), &QWindow::activeChanged
,pobjSubNode, &clsXMLnode::windowSlotActiveChanged);
Now I get:
2018-10-25 17:37:22.299066+0100 XMLMPAM[2930:423194] QObject::connect: invalid null parameter
Having just assigned:
QWindow* pobjW2 = pobjWin->windowHandle();
I can see in the debugger that pobjW2 is NULL, which explains the error.
Changing the line:
QWidget* pobjWin = new QWidget();
To:
QWindow* pobjWin = new QWindow();
Has fixed the connection problems, once I fixed all the methods to use the QWindow versions instead of the QWidget versions, but now I don't get any visible windows...investigating. Its odd that the methods in QWindow have different names to those that do the exact same job in QWidget.
[Edit 3] After fixing the problems with help on correcting the connection and inserting a call to showNormal before creating the connections. The code is exactly as originally posted with a call to pobjWin->showNormal before any connects.

Fixed, I acknowledge the input from eylanesc, thank you.
I had to add a call to:
pobjWin->showNormal();
Before attempting the signal / slot connections, an example of a signal and slot connection now looks like:
QObject::connect(pobjWin->windowHandle(), &QWindow::activeChanged
,pobjSubNode, &clsXMLnode::windowSlotActiveChanged);

Related

How to connect callback with QPlainTextEdit change?

I am listening to a topic and want to display and update the received value every time it changes.
This function creates the logging part of the GUI
QGroupBox *Window::startLoggingGroup()
{
QGroupBox *groupBox = new QGroupBox(tr("Logging"));
log_value = new QPlainTextEdit;
log_value->setReadOnly(true);
log_value->setPlaceholderText("Value will appear here \n");
QHBoxLayout *hbox = new QHBoxLayout;
hbox->addWidget(log_carrot);
groupBox->setLayout(hbox);
return groupBox;
}
This is the code executed on every value changed.
void EFISWindow::callback_value(const geometry_msgs::PoseStamped& msg){
QString qst = QString::number(msg.pose.position.z);
log_value->setPlainText(qst);
}
It works at first, I can see the GUI and some values, but after several messages like the ones I show now it crashes:
QObject::connect: Cannot queue arguments of type 'QTextBlock' (Make
sure 'QTextBlock' is registered using qRegisterMetaType().) QObject:
Cannot create children for a parent that is in a different thread.
(Parent is QTextDocument(0x227e580), parent's thread is
QThread(0x1f9db50), current thread is QThread(0x7f4ae40011d0)
How can I solve this threading issue? Maybe using a signal-slot design? I don't really understand why this is not working.
You should not access a GUI element from another thread.
Maybe using a signal-slot design?
Yes, Your worker object should have a signal that you emit at some point and you should connect that signal to update the "log_value" value.

Qt signal on buttongroup not connected

I have a buttongroup defined with two radiobuttons
buttonGroupFFTDimension = new QButtonGroup(this);
buttonGroupFFTDimension->addButton(ui->radioButton1D, 1);
buttonGroupFFTDimension->addButton(ui->radioButton2D, 2);
buttonGroupFFTDimension->setExclusive(true);
ui->radioButton1D->setChecked(true);
The connect also compiles
connect(this->buttonGroupFFTDimension, static_cast<void(QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked),
this, &MainWindow::on_buttonGroupFFTDimension_buttonClicked);
but it throws and error at runtime
QMetaObject::connectSlotsByName: No matching signal for on_buttonGroupFFTDimension_buttonClicked(int)
I admit that I am not familiar with the new connect syntax, but also do not see the obvious error. What is wrong?
The message shown is because you are using Qt Designer and it uses the connectSlotsByName method to connect various elements, it recognizes the format on_somesender_somesignal, and in your case matches your slot.
First solution: It iss unnecessary to use the connect function, this will automatically do it. Also I think that the slot does not have as parameter the type int that requires.
In your case the slot should be as follows:
private slots:
void on_buttonGroupFFTDimension_buttonClicked (int val);
Another possible solution is to rename the slot, after that you run make clean and qmake.

How to tell when a QPushButton is clicked in a QButtonGroup

In my project, I have 40 QPushButtons all put into a QButtonGroup like this:
QButtonGroup* group = new QButtonGroup(this);
group->addButton(ui->slot_0);
group->addButton(ui->slot_1);
//...
group->addButton(ui->slot_38);
group->addButton(ui->slot_39);
Each button is a QPushButton that I made checkable. That way only one button can be checked at a time. All works great, but how can I "make a slot" when one of the buttons becomes checked? I don't want to have 40 different slots, one for each button all to end up doing essentially the same thing. Is there any way I can just use the QButtonGroup I put them in?
As Jamin and Nikos stated: you should create your own slot to handle the signal emitted by QButtonGroup. It could be something like this:
In the header file:
public slots:
void buttonWasClicked(int);
In the *.cpp file:
void MainWindow::buttonWasClicked(int buttonID)
{
cout << "You have clicked button: " << buttonID << endl;
}
And in the code responsible for creation of the MainWindow (i.e. in constructor but not necessairly) there should be this line:
connect(group, SIGNAL(buttonClicked(int)), this, SLOT(buttonWasClicked(int)));
Be aware that since Qt5 the connect syntax has changed. The syntax I used here is from Qt4. It still works but is deprecated now (for more information please refer to New Signal Slot Syntax in Qt 5). Moreover I would suggest going through QButtonGroup class reference as there are other available signals which could suit your needs better than the one I've chosen.
BR
The documentation for QButtonGroup shows a QButtonGroup::buttonClicked() signal - have you already tried that one?
The signal comes in two variants - one that gives the QPushButton as a parameter (as a QAbstractButton), and one that gives the ID of the button in the group.
You can use connect() to setup signal and slot connections in your C++ code.
Sometime during the initialization of your window's class (perhaps in the constructor), call this:
connect(myButtonGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(theSlotThatYouWrite(QAbstractButton*));
Where myButtonGroup is probably this->ui->nameOfTheButtonGroup, and theSlotThatYouWrite is a function that you write in your own code, that belongs to your window's class, that returns void and takes a signal QAbstractButton* as a parameter (since that's what this specific signal gives as an argument).
Make sure theSlotThatYouWrite is under the label "private slots:" or "public slots:" in your class's interface.
Here's a screenshot of actual usage of some signals and slots in my own code.
Signals and Slots is something very important to learn, but can be bit of a hill to climb when first trying to understand it!

Qt doesn't find QStackedWidgets' slot setCurrentWidget

I am writing a wizard-style application in Qt that uses a QStackedWidget to organize the individual pages of the wizard. Now I want to switch between the pages, which should be possible using the function setCurrentWidget(...):
I have a simple main class that instantiates a QWidget audioconfig. Then, it adds this QWidget to a QStackedWidget pageStack using pageStack.addWidget(&audioconfig);.
Later, I want to connect a certain signal from a different QWidget hub to setCurrentWidget(...) of the QStackedWidget in order to switch the page. However, my compiler remarks that
0Object::connect: No such slot QStackedWidget::setCurrentWidget(audioconfig) in /Users/paperflyer/Development/App/main.cpp:41`
There are two things I don't get here:
there clearly is such a function. You can look it up in the class definition of QStackedWidget. What is going on here?
Why is the first character of the compiler output a '0', while my source code clearly and correctly shows it as 'Q'?
Here is the whole code:
int main(int argc, char *argv[])
{
QApplication app(argc,argv);
QStackedWidget pageStack;
CHub hub; // inherits from CWidget
CAudioConfig audioconfig; // ditto
pageStack.addWidget(&hub);
pageStack.addWidget(&audioconfig);
// connect() is a custom signal of hub
QObject::connect(&hub, SIGNAL(configure()), &pageStack, SLOT(setCurrentWidget(&audioconfig)));
pageStack.setGeometry(100,100,700,500);
pageStack.show();
return app.exec();
}
As always, thank you so much for your help!
QObject::connect(&hub, SIGNAL(configure()), &pageStack, SLOT(setCurrentWidget(&audioconfig)));
When you connect a signal to a signal/slot, you connect a signature. The actual parameters are passed when emitting the signal. The above should probably be setCurrentWidget(QWidget*), but even so it won't work, because the signature for the signal must match the one of the slot.
Note: I think that if the signal has more parameters than the slot it will still work, provided that the first parameters are the same.
Your connect line is wrong. It should be:
// connect() is a custom signal of hub
QObject::connect(
&hub, SIGNAL(configure()),
&pageStack, SLOT(setCurrentWidget(QWidget *))); // <- change here
You connect based on the prototype of the slot and/or signal.

Qt: having problems responding on QWebView::linkClicked(QUrl) - slot signal issue

I am pretty new with Qt.
I want to respond to linkClicked in QWebView.
I tried connect like this:
QObject::connect(ui->webView, SIGNAL(linkClicked(QUrl)),
MainWindow,SLOT(linkClicked(QUrl)));
But I was getting error: C:/Documents and Settings/irfan/My Documents/browser1/mainwindow.cpp:9: error: expected primary-expression before ',' token
When I do this using UI Editing Signals Slots:
I have in header file declaration of slot:
void linkClicked(QUrl &url);
in source cpp file :
void MainWindow::linkClicked(QUrl &url)
{
QMessageBox b;
b.setText(url->toString());
b.exec();
}
When I run this it compiles and runs but got a warning :
Object::connect: No such slot MainWindow::linkClicked(QUrl)
in ui_mainwindow.h:100
What is proper way of doing this event handling?
You state that it now works because you changed QObject::connect to connect. Now I'm not 100% on this but I believe the reason for this is that by calling connect, you are calling the method associated with an object which is part of your application. i.e. it's like doing this->connect(...). That way, it is associated with an existing object - as opposed to calling the static method QObject::connect which doesn't know anything about your application.
Sorry if that's not clear, hopefully I got the point across!
Using QObject::connect() and connect() is same in this context. I believe
QObject::connect(ui->webView,SIGNAL(linkClicked(QUrl)),
MainWindow,SLOT(linkClicked(QUrl)));
was called from a function inside MainWindow class. That is why when you tried
connect(ui->webView,SIGNAL(linkClicked(const QUrl)),
this,SLOT(linkClicked(const QUrl)),Qt::DirectConnection);
it works. Notice the difference that make it work - the third parameter. You used this in the second snippet, where as you used MainWindow in the first snippet.
Read this to know how signals and slots mechanism works and how to properly implement it.
I changed QObject::connect to only connect and it works.
So this code works:
connect(ui->webView,SIGNAL(linkClicked(const QUrl)),this,SLOT(linkClicked(const QUrl)),Qt::DirectConnection);
But I don't know why?