PDA

View Full Version : Porting problems with connect upgradeing to Qt V5.7



Carlton
26th June 2017, 13:32
I am resurrecting an old (Pre version 5) Qt project. I see that the signal/slot syntax has changed, but that the old format is still supported. I restarted the project from an old functional version. The project compiles without error.
The connect commands connect the various dialog buttons with the functionality code. Hence the connect commands are at the top of the dialog constructor after the ui->setupUI(this) command.

When I run I get a SIGSEGV runtime error when I get to the connect statement both with the original statement and with my new statement.
Checking with the debugger, all the pointers have values.


//My original connect statement was
connect ( comboBox_Aaccount, SIGNAL ( activated ( QString ) ), this, SLOT ( selectAccount( QString ) ) );
//My new one is
connect(comboBox_Aaccount,SIGNAL( &comboBox_Aaccount::activated), this, SLOT(&selectAccount( QString& )));

I have read through the documentation and forum and had no problems with the previous system, I assume I'm missing something obvious I just can't see.

d_stranz
26th June 2017, 16:20
Your syntax is incorrect. It should be:



connect(comboBox_Aaccount, &comboBox_Aaccount::activated, this, &whateverClassThisIs::selectAccount);


The SIGNAL() and SLOT() macros of the old style were passed char * strings, which the Qt metatype system used to look up the actual function. The new style uses the address of the member function (signal or slot). Function addresses don't include the names / types of arguments.

In the connect statement I posted above, unless you have a member variable named "comboBox_Aaccount", this code won't compile either. The first argument to the connect() statement must be the name of the member variable that has the same type (or is derived from) the class used in the second argument. Likewise for the 3rd / 4th argument pair.

Carlton
27th June 2017, 13:36
Thanks for the assistance, I think I understand the approach now;
In my example;
this is the dialog constructor (DialogCF3tab),
comboBox_Aaccount is a member of class DialogCF3tab inherited from the class generated by DialogCF2tab.ui derived from the class QComboBox
The selectAccount function is also a member of DialogCF3tab; hence the following should be correct;


connect(comboBox_Aaccount, &QComboBox::activated, this, &DialogCF3tab::selectAccount);

However, it gives the following compilation error;
C:\Carlton\SoftwareDevelopment\CF_3\dialogCF3tab.c pp:39: error: no matching function for call to 'DialogCF3tab::connect(QComboBox*&, <unresolved overloaded function type>, DialogCF3tab*, void (DialogCF3tab::*)(QString))'
connect(comboBox_Aaccount,&QComboBox::activated, this, &DialogCF3tab::selectAccount); //From Qt Forum

activated is a member of QComboBox, I don't understand why it's an unresolved overloaded function type.

d_stranz
27th June 2017, 18:32
Your signal and slot function signatures have to match for this type of connect() call. The QComboBox::activated() signal has two overloads - one with an int argument and one with a QString argument. The compiler can't tell which one to use in the connect() statement. You will have to use the qOverload() function to tell connect() explicitly which overload to apply:



// C++14 - compliant compiler:

connect( comboBox_Aaccount, qOverload<QString>( &QComboBox::activated ), this, &DialogCF3tab::selectAccount );

// C++11 - compliant compiler:

connect( comboBox_Aaccount, QOverload<QString>::of( &QComboBox::activated ), this, &DialogCF3tab::selectAccount );

Carlton
6th July 2017, 13:07
I have failed to get my QComboBox connect statements working, so thought I'd try simpler case without overloads.


//ORIGINAL connect statements
// connect ( pushButton_accept, SIGNAL ( clicked () ), this, SLOT ( acceptButtonClicked() ) );
// connect ( pushButton_cancel, SIGNAL ( clicked () ), this, SLOT ( cancelButtonClicked() ) );

This was replaced by the following which I believe has the correct syntax;


// New format connect syntax
connect ( pushButton_cancel, &QPushButton::clicked, this, &DialogCF3_A::cancelButtonClicked );
connect ( pushButton_accept, &QPushButton::clicked, this, &DialogCF3_A::acceptButtonClicked );

When stepping through the debugger in Qt Creator, when I get to the connect statements the variables are;
pushButton_cancel=0x28ffca
&QPushButton::clicked = no value available
This=0x28fcf4
&DialogCF3_A::cancelButtonClicked= no value available

Subsequently the run fails with SIG

Is my syntax still incorrect, or do I have bigger problems?

d_stranz
6th July 2017, 16:31
Subsequently the run fails with SIG

The connect() statements look fine. If there was something wrong with the syntax, you wouldn't get to the point where you could execute the code.

Where does the execution fail? Inside the connect() call or somewhere afterwards? Which particular signal is issued? SIGSEGV or something else?

A copy of the stack trace at the failure point would help, as would a copy of the source code for the method in which you are making these connections.

Carlton
13th July 2017, 16:53
The program fails at the first connect statement in the DialogCF3_A constructor
I have included the stack trace back and the local variables.
The problem also occurs on a different machine.
NOTE only comments removed.


int main(int argc, char *argv[])
{
QString qmsg;
QString PROGRAM = "Qt4 Cashflow Predictor"; /* Program title */
QString VERSION = "COMMIT #243+ Version 1.0";/* Program version string */
QApplication app( argc, argv );
DialogCF3_A A_win;



DialogCF3_A::DialogCF3_A(QWidget *parent) : QDialog(parent), ui(new Ui::DialogCF3_A)
{
// Constructor for the account edit dialog.
QString qstr;
ui->setupUi(this);
// New format connect syntax
connect ( pushButton_cancel, &QPushButton::clicked, this, &DialogCF3_A::cancelButtonClicked );
connect ( pushButton_accept, &QPushButton::clicked, this, &DialogCF3_A::acceptButtonClicked );

//ORIGINAL connect statements
// connect ( pushButton_accept, SIGNAL ( clicked () ), this, SLOT ( acceptButtonClicked() ) );
// connect ( pushButton_cancel, SIGNAL ( clicked () ), this, SLOT ( cancelButtonClicked() ) );
pDIALOG->WriteDBMessage("CF3:DialogCF2_A::DialogCF2_A( QWidget * parent, Qt::WFlags f): QDialog(parent, f)");
}

running in debug mode and stepping through until the SIGSEGV error the line that fails is line 238 of qobject.h
Line after const int *types = Q_NULLPTR; (line 23 below)
The relevant section of code is


#else
//Connect a signal to a pointer to qobject member function
template <typename Func1, typename Func2>
static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot,
Qt::ConnectionType type = Qt::AutoConnection)
{
typedef QtPrivate::FunctionPointer<Func1> SignalType;
typedef QtPrivate::FunctionPointer<Func2> SlotType;

Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
"No Q_OBJECT in the class with the signal");

//compilation error if the arguments does not match.
Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
"The slot requires more arguments than the signal provides.");
Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArgum ents<typename SignalType::Arguments, typename SlotType::Arguments>::value),
"Signal and slot arguments are not compatible.");
Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatib le<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
"Return type of the slot is not compatible with the return type of the signal.");

const int *types = Q_NULLPTR;
if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();

return connectImpl(sender, reinterpret_cast<void **>(&signal),
receiver, reinterpret_cast<void **>(&slot),
new QtPrivate::QSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
typename SignalType::ReturnType>(slot),
type, types, &SignalType::Object::staticMetaObject);
}

The trace back window shows
1 QObject::connect<void (QAbstractButton:: *)(bool), void (DialogCF3_A:: *)()> qobject.h 245 0x432192
2 DialogCF3_A::DialogCF3_A dialogCF3_A.cpp 118 0x4116bb
3 qMain main.cpp 47 0x4016e0
4 WinMain *16 qtmain_win.cpp 123 0x41db10
5 main 0x43712d

The values of the locals (from the locals and expressions window) at the tie of the crash are;
Locals
receiver @0x28fcf4 QtPrivate::FunctionPointer<void (DialogCF3_A::*)()>::Object
[QDialog] @0x28fcf4 QDialog
[Ui::DialogCF3_A] @0x28fd0c Ui::DialogCF3_A
[Ui_DialogCF3_A] @0x28fd0c Ui_DialogCF3_A
checkBox @0x28fde8 QCheckBox
dateEdit_enddate 0x3f QDateEdit *
dateEdit_startdate @0xac5e25 QDateEdit
horizontalLayout @0x77505918 QHBoxLayout
horizontalLayout_2 @0xac5e25 QHBoxLayout
horizontalLayout_3 @0x1340000 QHBoxLayout
horizontalSpacer @0x7747e0c6 QSpacerItem
horizontalSpacer_2 0xfffffffe QSpacerItem *
label 0x8 QLabel *
label_accountnumber @0x28fca4 QLabel
label_description 0x0 QLabel *
label_enddate @0x77483431 QLabel
label_limit 0x0 QLabel *
label_sortcode 0x3f QLabel *
label_startbalance @0x77483406 QLabel
label_startdate @0x774c58c5 QLabel
layoutWidget @0x77482fdd QWidget
layoutWidget_2 @0x13556a8 QWidget
layoutWidget_3 0x0 QWidget *
layoutWidget_4 @0x774c58c5 QWidget
lineEdit_accountnumber @0x167f0138 QLineEdit
lineEdit_description @0x1340000 QLineEdit
lineEdit_limit 0x0 QLineEdit *
lineEdit_sortcode 0x3f QLineEdit *
lineEdit_startbalance @0x77483431 QLineEdit
pushButton_accept 0x3f QPushButton *
pushButton_cancel @0x28ffc4 QPushButton
verticalLayout 0x77c36ab5 QVBoxLayout *
verticalLayout_2 @0x28fd9c QVBoxLayout
verticalLayout_3 @0x28fda8 QApplication
verticalLayout_4 0x4 QVBoxLayout *
verticalLayout_5 0x8 QVBoxLayout *
verticalLayout_6 @0x77483406 QVBoxLayout
verticalLayout_7 @0x28ffc4 QVBoxLayout
[children] <7 items> QObjectList
[methods] <3 items>
[parent] 0x0 QObject *
[properties] <at least 0 items>
[signals] <0 items>
dirtyAccounts 205 bool
mp_activeaccount @0x77521e09 CashFlow::Account
paccount 0xfffffffe CashFlow::Account *
pallaccounts <0 items> QList<CashFlow::Account*>
staticMetaObject @0x43b038 QMetaObject
ui @0x183b3a70 Ui::DialogCF3_A
sender @0x28ffc4 QtPrivate::FunctionPointer<void (QAbstractButton::*)(bool)>::Object
[QWidget] @0x28ffc4 QWidget
[children] <not accessible> QList<QObject*>
[methods] <11 items>
[parent] @0xc5d8b53 QObject
[properties] <at least 0 items>
[signals] <5 items>
staticMetaObject @0xdb96940 QMetaObject
signal 0xd7f552a <QAbstractButton::clicked(bool)> void (QAbstractButton::*)(QAbstractButton * const, bool)
slot 0x4115a2 <DialogCF3_A::cancelButtonClicked()> void (DialogCF3_A::*)(DialogCF3_A * const)
type Qt::AutoConnection (0) Qt::ConnectionType
types 0x0 int *
Inspector
Expressions
Return Value
Tooltip
Q_NULLPTR <no such value>
SignalType <no such value>
if <not accessible>
I suspect the problem is with the types=0x0, but I don't know what might case it.

d_stranz
13th July 2017, 17:08
You don't show the code that defines your slots, but from what I can guess from seeing the last few lines of your dump, it looks like your slots are defined as taking no arguments, whereas the clicked() signal has a bool argument. Try adding a bool argument to your slot definition, see if that makes a difference. If it doesn't then it could be that something else your code does prior to this causes memory corruption and this connect problem just hapens to be where it manifests.

I see a few variables with the value 0xfffffffe, which indicates an uninitialized pointer. Especially suspicious is the uninitialized horizontal spacer in your dialog layout.