I am sure my problem is very simple but I just can't debug it!!
I am trying to connect a spinBox widget to a custom function that sets the com port of my QSerialPort instance on Qt.
My Main Window contructor, I try connecting my com_spinBox to my custom function called setComPort() :
QSerialPort *serial;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this); // Here by default. Takes a pointer to mainwindow as argument
serial = new QSerialPort(this); // this (mainwindow) is parent
connect(ui->com_spinBox, SIGNAL(valueChanged(QString)),
this, SLOT(MainWindow::setComPort()));
serial->setBaudRate(QSerialPort::Baud9600);
serial->setDataBits(QSerialPort::Data8);
serial->setParity(QSerialPort::NoParity);
serial->setStopBits(QSerialPort::OneStop);
serial->setFlowControl(QSerialPort::NoFlowControl);
qDebug() << "is " << serial->open(QSerialPort::ReadOnly);
qDebug() << "err " << serial->error();
}
I define my function in my MainWindow.cpp (and declare it in .h) too:
void MainWindow::setComPort()
{
qDebug() << "fu";
}
I do not see anything appear on debug console when changing value of my spinBox.. is it a synthax problem? I know qDebug works as I can print other stuff in my constructor no problem.
Thanks!
You are mixing the old and new syntax of QObject::connect and in a wrong way by using function pointer .. this is wrong: SLOT(MainWindow::setComPort().
If you want to purposely use the old syntax .. do not use function pointers along with SLOT, just use that slot signature; your connect should be like this:
connect(ui->spinBox, SIGNAL(valueChanged(const QString&)),
this, SLOT(setComPort()));
On the other hand, using new syntax with function pointers is possible .. you just need to use overloaded signal signature of QSpinBox , as documented here https://doc.qt.io/qt-5/qspinbox.html#valueChanged:
connect(ui->spinBox, QOverload<const QString&>::of(&QSpinBox::valueChanged) ,
this , &MainWindow::setComPort);
Note also that, while Qt connect() allows the slot to have no arguments, and based on guessing your intention .. you might want to change the slot signature to receive the serial port number .. MainWindow::setComPort(const QString&).
Related
I have eight list widgets in a tab widget. They have similar names, and Designer's "Go to slot" mechanism has made links to slots it names (in the "private slots" section of "mainwindow.h") like:
void on_SR0listWidget_itemClicked(QListWidgetItem *item);
I saw warnings that "Slots named on_foo_bar are error-prone," and now I need to change their names in order to discover if that's the cause of the weird behaviour I'm getting.
I tried simply refactoring the names, but that stopped the slot code from working. I used Designer's graphical "Edit Signal/Slot" mechanism and was able to connect a newly added list widget's "itemClicked(QListWidgetItem *item)" signal to a newly added slot, and it looks OK in the graphical representation, but there's no debug message (that I set up in the Slot function) when an item is clicked.
I also use those widgets' "entered" signals, so there will be at least 16 to fix. I would write a script if it could be done by parsing the relevant files.
One example of exactly how to rename one of my replacement slots and connect an "item clicked" or "entered" signal to it (and where it should go) would be a great help.
Signals/slots setup through the designer rely on the names of the widgets involved. This can lead to problems if the widget names are changed. There are times when using the designer method will lead to code that compiles but doesn't actually make the connections you expect. This is why you are getting that warning.
You can get more reliable behavior by connecting the signals and slots programmatically. For example, let's say you have a class header such as:
#include <QMainWindow>
namespace Ui {
class MyWindow;
};
class QListWidgetItem;
class MyWindow : public QMainWindow {
Q_OBJECT
public:
explicit MyWindow(QWidget* parent = nullptr);
~MyWindow() override;
private:
void handleItemClicked(QListWidgetItem* item); // this is your slot
Ui::MyWindow* ui;
};
You can connect the signal/slot together in the cpp file like this:
#include "MyWindow.h"
#include "ui_MyWindow.h"
#include <QDebug>
MyWindow::MyWindow(QWidget* parent)
: QWidget(parent),
ui(new Ui::MyWindow()) {
ui->setupUi(this);
// connect() has many overloads, but in this case we are passing:
// 1. the object emitting the signal
// 2. the signal being emitted
// 3. the object whose slot we want to call
// 4. the slot to connect to
connect(
ui->listWidget, &QListWidget::itemClicked,
this, &MyWindow::handleItemClicked);
}
MyWindow::~MyWindow() {
delete ui;
}
void MyWindow::handleItemClicked(QListWidgetItem* item) {
qDebug() << "item clicked";
}
You can still use the designer to layout your UI - but prefer to manage connections directly in code rather than through the designer.
I don't under stand how to use the ProcessState enums. According to documentation, the ProcessState enum can have the following values:
QProcess::NotRunning- 0 - The process is not running.
QProcess::Starting- -1-The process is starting, but the program has not yet been invoked.
QProcess::Running -2 -The process is running and is ready for reading and writing.
How would I use them?
What you refer to are not functions, simply values. You could assign them to an integer and output its value:
int val = QProcess::Starting;
qDebug() << "the value of QProcess::Starting is" << val;
To check the state of a process, you could do:
QProcess *process;
....
if (process->state() == QProcess::Running) // do something with a running process
Of course, when it comes to a QProcess, you really need to be handling signals that the process emits as it changes state. You do not want to do any sort of busy-waiting, and I should discourage the use of any Qt function called waitFor.... Those functions cause the event loop to be re-entered, and potentially to re-enter your code that you never realized could be re-entered. It's a Pandora's box you do not want to open. About the only valid use of wait-style functions is to wait for QThreads that have been quit() to finish before you return from the main() function.
You can have states for the processes to be run. You can then connect your slot to the state changed signal, even in QML if needed, and act accordingly. Also, not that there is no such a thing as "enum function". It is just a simple enumeration that basically the state "property" holds. You can query and set it the usual way. You can see the documentation for those methods below.
http://qt-project.org/doc/qt-5.0/qtcore/qprocess.html#state
http://qt-project.org/doc/qt-5.0/qtcore/qprocess.html#setProcessState
This looks like a generic Qt examples as your question is, but here you go:
myclass.h
class MyClass : QObject
{
Q_OBJECT
public:
explicit MyClass(QObject *parent);
public Q_SLOTS:
void handleProcessStateChanged(QProcess::ProcessState newProcessState);
....
}
myclass.cpp
...
MyClass::MyClass(QObject *parent)
: QObject(parent)
{
}
MyClass::myProcessInvokeMethod()
{
connect(myprocess, SIGNAL(stateChanged(QProcess::ProcessState), this, SLOT(handleStateChange(QProcess::ProcessState)));
myprocess.start(myprogram, myarguments);
....
}
void MyClass::handleProcessStateChange(QProcess::ProcessState newProcessState)
{
switch (newProcessState) {
case QProcess::NotRunning:
qDebug() << "Here goes the handler code when the process is not yet running";
break;
case QProcess::Starting:
qDebug() << "Here goes the handler code when the process is starting";
break;
case QProcess::Running:
qDebug() << "Here goes the handler code when the process is running";
break;
}
}
...
I have a basic doubt about how signals and slots actually work. Here's my code segment.
finddialog.cpp :
#include "finddialog.h"
#include <QtGui>
#include <QHBoxLayout>
#include <QVBoxLayout>
FindDialog::FindDialog(QWidget *parent) : QDialog(parent) {
//VAR INITIALIZATIONS
label = new QLabel(tr("Find &what:"));
lineEdit = new QLineEdit;
label->setBuddy(lineEdit);
caseCheckBox = new QCheckBox(tr("Match &case"));
backwardCheckBox = new QCheckBox(tr("Search &backward"));
findButton = new QPushButton("&Find");
findButton->setDefault(true);
findButton->setEnabled(false);
closeButton = new QPushButton(tr("&Quit"));
//SIGNALS & SLOTS
connect (lineEdit, SIGNAL(textChanged(const QString&)),this, SLOT(enableFindButton(const QString&)));
connect (findButton, SIGNAL(clicked()), this, SLOT(findClicked()));
connect (closeButton,SIGNAL(clicked()), this, SLOT(close()));
//Layout
QHBoxLayout *topLeftLayout = new QHBoxLayout;
topLeftLayout->addWidget(label);
topLeftLayout->addWidget(lineEdit);
QVBoxLayout *leftLayout = new QVBoxLayout;
leftLayout->addLayout(topLeftLayout);
leftLayout->addWidget(caseCheckBox);
leftLayout->addWidget(backwardCheckBox);
QVBoxLayout *rightLayout = new QVBoxLayout;
rightLayout->addWidget(findButton);
rightLayout->addWidget(closeButton);
rightLayout->addStretch();
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addLayout(leftLayout);
mainLayout->addLayout(rightLayout);
//Complete window settings
setLayout(mainLayout);
setWindowTitle(tr("Find"));
setFixedHeight(sizeHint().height());
}
//Function Definition
void FindDialog::findClicked() {
QString text = lineEdit->text();
Qt::CaseSensitivity cs = caseCheckBox->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive;
if(backwardCheckBox->isChecked())
emit findPrevious(text, cs);
else
emit findNext(text,cs);
}
void FindDialog::enableFindButton(const QString &text1) {
findButton->setEnabled(!text1.isEmpty());
}
With this code, how does the compiler know what is passed to enableFindButton(QString &) function. There are no function calls to enableFindButton(). In the connect statement there is a reference to enableFindButton() but isn't that more like a prototype because we are not providing the name of the variables to work with in its arguments?
connect (lineEdit, SIGNAL(textChanged(const QString&)),this, SLOT(enableFindButton(const QString&)));
Here only (const QString &) is the argument and a variable is not given. How does the application know what its argument is without passing it explicitly?
void FindDialog::enableFindButton(const QString &text1) {
findButton->setEnabled(!text1.isEmpty());
}
Here also &text1 is a reference argument. But to what ? I don't understand anything now after typing this all!
:-|
Qt is generating the code that makes it work when you build the project.
SIGNAL, SLOT, etc are preprocessor macros defined in qobjectdefs.h
These are then picked up by moc in QT when you build your project, and all the code required is generated, then compiled.
A decent page that explains this in more detail can be found here
C++ source code is processed by Qt meta object compiler (moc). It generates 'signatures' strings for QObject slots. Signatures contain method name and arguments (types, arguments' names do not matter in signatures). Whenever signal is emitted a signature match is performed directly (in case of direct connections) or in the event loop (for queued connections), and corresponding method is called. Moc compiler generates all necessary code that will match signatures and call the methods. If interested, look inside of one of those *.cxx files generated.
I have problem with one class in my project, after click appears new window with QTableWidget and QPushButton, after clicking the button I should have "test" on stdout, but nothing shows, here are parts of this code:
Header:
class ClientsSelector : public QWidget {
Q_OBJECT
public:
ClientsSelector(InvoiceTab* parent);
QWidget *window;
private:
QPushButton *accept;
public slots:
void loadData();
Constructor:
window = new QWidget();
layout = new QGridLayout();
layout->addWidget(table, 0, 0);
/*code*/
accept = new QPushButton(QString::fromUtf8("Load data"));
connect(accept, SIGNAL(clicked()), this, SLOT(loadData()));
layout->addWidget(accept, 0, 1);
/*code*/
window->setLayout(layout);
window->show();
Method:
void ClientsSelector::loadData() {
QTextStream std(stdout);
std << "test" << endl;
}
I have not even one warning nor error. I have nothing on stdout, it looks like button was connected to wrong object(?)
How do you instantiate ClientsSelector? Isn't it a singleton or global variable by chance? Try moving the connect call to a separate init function which is called after the ClientsSelector constructor. It helped me in similar WTF situations. It has something to do with the fact that each QObject inheritor has a static metadata member and you can't be sure about when it is fully initialized until the constructor finishes. connect won't work without that metadata.
See for example here: http://www.qtcentre.org/threads/9479-connect-in-constructor
If still lost, go through this checklist. Qt signals are so easy to use, everybody sometimes forgets it also has some requirements.
Seems like you forgot a closing " on the test printout.
Try using
qDebug() << "test";
instead of QTextstream
You can do following to make sure that the connection was made and slot is called.
connect function returns status of connection. Check if the connection was made properly.
put a breakpoint and see if the loadData() is called when button is pressed.
This might help to find the cause.
i'm reading a book about Qt, in one of the examples of a signal-slot function, there is the emit method located inside the slot method... So this becomes an infinite loop... i don't really understand how to stop it :
connect(webView, SIGNAL(urlChanged(const QUrl&)),
this, SLOT(urlChange(const QUrl&));
and we then have the function :
void BrowserWindow::urlChange(const QUrl &url)
{
emit urlChanged(url);
progressLabel->setText(tr("Loading"));
}
Thanks
What is webView? (is it the same type?)
The connect is connecting one instance with this slot - its probably not connecting its own instance.
If it was
connect(this, SIGNAL(urlChanged(const QUrl&)),
this, SLOT(urlChange(const QUrl&));
then that would be an infinite loop