Passing QWidget* as function parameter doesn't behave as expected [duplicate] - c++

This question already has answers here:
Can I modify the target of a pointer passed as parameter?
(3 answers)
Closed 2 years ago.
I want to pass QWidget pointer to a function to get some widget back as a result of function actions. But the value of this pointer leaves the same as befoere.
Next code
#include <QApplication>
#include <QWidget>
#include <QDebug>
class Test
{
public:
QWidget *_widget;
Test()
{
_widget = new QWidget;
}
void test_pointer(QWidget *w) const
{
w = _widget;
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget *w = nullptr;
Test t;
t.test_pointer(w);
qDebug() << w;
return app.exec();
}
outputs
QWidget(0x0)
What's wrong?

You pass the pointer as copy, which means the outside pointer is not modified by the inside assignment. Instead you have to pass a pointer or a reference to your QWidget*.

Related

Why am I getting weird crashes with Qt5 depending on how I create the application instance?

Here is a reduced version of my code:
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
class MainView : public QMainWindow
{
public:
static MainView *Initialise(int argc, char **argv);
int Run() { return qApp->exec(); }
private:
MainView() { }
virtual ~MainView() { }
};
namespace
{
QApplication *s_app {nullptr};
MainView *s_instance {nullptr};
};
MainView *MainView::Initialise(int argc, char **argv)
{
if (nullptr == s_app) {
s_app = new QApplication(argc, argv);
}
if (nullptr == s_instance) {
s_instance = dynamic_cast<MainView *>(new MainView());
}
return s_instance;
}
class Framework
{
public:
Framework() { }
~Framework() { }
int Initialise(int argc, char **argv)
{
m_main_view = MainView::Initialise(argc, argv);
return 0;
}
int Run()
{
m_main_view->show();
return m_main_view->Run();
}
private:
MainView *m_main_view;
};
int main(int argc, char **argv)
{
Framework framework;
int result = 0;
// Weirdness here!!!!
MainView::Initialise(argc, argv); // Crashes even with this line.
result = framework.Initialise(argc, argv);
if (0 == result) {
result = framework.Run();
}
return result;
}
This code crashes when showing the MainWindow instance. In my full version of this code, where MainView inherits from a virtual interface class (so as to allow me to decouple the view and substitute a command line interface or a test interface) it doesn't crash unless I comment out the code marked as "weirdness here".
In this code, if I replace:
MainView::Initialise(argc, argv); // Crashes even with this line.
with:
if (nullptr == s_app) {
s_app = new QApplication(argc, argv);
}
then it works fine and doesn't crash.
Essentially if the application is instantiated within MainView::Initialise(), whether called from main() or from Framework::Initialise() then the program crashes, but if I initialise the application in main() first then it doesn't crash.
I don't want my main() function to have any knowledge of the UI at all, if possible, even taking my virtual base class interface into account. There should be no need and it makes main() messier than necessary.
So why is this crashing and how do I stop it?
There's a subtle difference between your invocation of the QApplication constructor in main() and the invocation in MainView::Initialise().
The documentation for the QApplication constructor says:
QApplication::QApplication(int &argc, char **argv)
< ... >
Note: argc and argv might be changed as Qt removes command line arguments that it recognizes.
So when invoking the constructor in MainView::Initialise(), you are actually passing a copy of the argc that came from main. Presumably, Qt stores a reference to this internally somewhere, causing it to crash when the QApplication later dereferences it during the construction of the window.
If you change the signature of both Initialise() functions to take a reference to argc, the program works without crashing.

Pass a function pointer to a method of another class

I'm working on my first C++ project. I have 2 classes: 1 for the interaction with the sqlite db, the other one for the qt main window. In the main I create a new window. In the window constructor I would like to load the content of the db and display it in a QtWidget.
So if I understand well sqlite callback function will be called for each row that the sqlite3_exec returns. I made a select_all function in the database class which takes a callback function as an argument so I'll be able to do use the same sql function to display/use the data in different ways.
#include <cstdio>
#include <iostream>
#include <QtCore>
#include <QtGui>
#include <QtWidgets>
#include <qmainwindow.h>
#include <qstandarditemmodel.h>
#include <sqlite3.h>
#include <string>
using namespace std;
class Database {
public:
sqlite3* db;
Database() {db = create_or_open_database();}
sqlite3* create_or_open_database()
{
sqlite3 *db = NULL;
const char *query;
int ret = 0;
char *errorMsg = 0;
ret = sqlite3_open("expense.db", &db);
query = "CREATE TABLE IF NOT EXISTS EXPENSES(NAME TEXT KEY NOT NULL, AMOUNT INT NOT NULL, TAG TEXT, SUBTAG TEXT, DATE CHAR(10) NOT NULL);";
ret = sqlite3_exec(db, query, callback, 0, &errorMsg);
return db;
}
void select_all(int (*f)(void*, int, char**, char**)){
int ret = 0;
char *errorMsg = 0;
const char *query = "SELECT * FROM EXPENSES";
ret = sqlite3_exec(db, query, (*f), 0, &errorMsg);
}
};
class MainWindow
{
public:
QWidget window;
Database expenses;
QTreeView *navigateView = new QTreeView;
QTreeView *expensesList = new QTreeView;
QPushButton *newButton = new QPushButton;
QVBoxLayout *mainVLayout = new QVBoxLayout;
QHBoxLayout *listHLayout = new QHBoxLayout;
QStandardItemModel *expensesModel = new QStandardItemModel;
MainWindow()
{
QSizePolicy navigateSize(QSizePolicy::Preferred, QSizePolicy::Preferred);
QSizePolicy expenseListSize(QSizePolicy::Preferred, QSizePolicy::Preferred);
navigateSize.setHorizontalStretch(1);
navigateView->setSizePolicy(navigateSize);
expenseListSize.setHorizontalStretch(2);
expensesList->setSizePolicy(expenseListSize);
newButton->setText("New");
listHLayout->addWidget(navigateView);
listHLayout->addWidget(expensesList);
mainVLayout->addLayout(listHLayout);
mainVLayout->addWidget(newButton);
window.setLayout(mainVLayout);
// int (MainWindow::*foo)(void*, int, char**, char**) = &MainWindow::display_expenses_in_list;
// expenses.select_all(foo);
expenses.select_all(this->display_expenses_in_list);
}
int display_expenses_in_list(void *NotUsed, int argc, char **argv, char **azColName)
{
QStringList list = {"Name", "Amount (€)", "Tag", "Subtag", "Date"};
this->expensesModel->setVerticalHeaderLabels(list);
// here I'll create items and add them to the QTreeView
return 0;
}
};
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow ui;
ui.window.show();
return app.exec();
}
With this code I get reference to a non-static member function must be called [bound_member_function]
If googled it and tried, I guess, to create a function pointer foo that point to the callback function (the lines that are currently commented). I get this : Cannot initialize a parameter of type 'int (*)(void *, int, char **, char **)' with an lvalue of type 'int (MainWindow::*)(void *, int, char **, char **)' [init_conversion_failed]
If I make display_expenses_in_list static then I can't edit the expensesModel...
The key here is that void* argument to sqlite3_exec. You now pass 0, but you need to pass this instead.
You can now make display_expenses_in_list static. That NotUsed parameter then becomes used. You just need to cast it back to MainWindow* and use it instead of this.
The problem:
The problem is your display_expenses_in_list(...) function is a class member function. Therefore your need to use a pointer to a member function rather than a pointer to a function, because it must always be called on an instance of the class it's a member of - however the sqlite library will only take a void* function pointer.
Check out this article: https://isocpp.org/wiki/faq/pointers-to-members
The fix:
Modern C++ to the rescue here. Wrap up your whole class member function call up in a lambda with the class instance in scope, then pass a pointer to this new, anonymous function as the callback.
Check this stackoverflow answer out showing how to do it (copied below): https://stackoverflow.com/a/31461997/410072
An example (copied from the linked answer):
if (sqlite3_exec(this->db, this->SQL_SELECT_READINGS_QUERY,
+[](void* instance, int x, char** y, char** z) {
return static_cast<dataSend_task*>(instance)->callback(x, y, z);
},
this,
&err))
{
/* whatever */
}

QDataStream is becoming Readonly

I have two classes named IPCBase and DispatchData. Now I want to pass QDataStrean Object drom IPCBase to DispatchData. First I tried to send it directly using Connect Statement. But it is giving error like QDataStream object is not registered in QRegisterMatatype.
edit :: I have refered this link as well
When, where and why use namespace when registering custom types for Qt
So I have done something like
typedef QDataStream* myDataStrem;
Q_DECLARE_METATYPE(myDataStrem)
and then connect statement in another class(DispatchData)
connect(mpThrIPCReceiver, SIGNAL(dispatchReadData(const int&, myDataStrem)),
this, SLOT(onIPCDataReceived(const int&, myDataStrem)));
onIPCDataReceived Slot
void DispatchData::onIPCDataReceived(const int& msgType, myDataStrem dataReceived)
{
// dataReceived >> str1; Here it is giving error
// qDebug()<<"is"<<str1;
MemberFuncPointer f = mIPCCommandMapper.value(msgType);
(this->*f)(*dataReceived);
//This is function pointer which will rout it to respective function depending on the Message type.
and then it will come here
void DispatchData::onStartCountingCycle(QDataStream &dataReceived)
{
int data = 0;
dataReceived >> data; //Here it is crashing
//Giving error like
//pure virtual method called
//terminate called without an active exception
// I have debugged it and here dataReceived is becoming Readonly.
}
It seems like you're passing around a dangling pointer: the data stream seems to not exist anymore by the time the receiving thread gets to it. Even if you extended its lifetime in the source object, it's a bad idea to pass a raw pointer through signal-slot connections. If the source class might vanish while the receiver thread has a pending slot call, you'll still be using a dangling pointer at the receiver. You'd be best served by passing around a QSharedPointer or std::shared_ptr.
The following works, you can of course use any type in the shared pointer.
#include <QtCore>
#include <cstdio>
struct Class : public QObject {
Q_SIGNAL void source(QSharedPointer<QTextStream>);
Q_SLOT void destination(QSharedPointer<QTextStream> stream) {
*stream << "Hello" << endl;
}
Q_OBJECT
};
Q_DECLARE_METATYPE(QSharedPointer<QTextStream>)
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
Class c;
c.connect(&c, &Class::source, &c, &Class::destination, Qt::QueuedConnection);
auto out = QSharedPointer<QTextStream>(new QTextStream(stdout));
emit c.source(out);
QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
*out << "About to exec" << endl;
return app.exec();
}
#include "main.moc"
Output:
About to exec
Hello
On modern Qt (5.6 at least), you don't need to call qRegisterMetatype in this case.
The same using std::shared_ptr:
// https://github.com/KubaO/stackoverflown/tree/master/questions/datastream-pass-37850584
#include <QtCore>
#include <cstdio>
#include <memory>
struct Class : public QObject {
Q_SIGNAL void source(std::shared_ptr<QTextStream>);
Q_SLOT void destination(std::shared_ptr<QTextStream> stream) {
*stream << "Hello" << endl;
}
Q_OBJECT
};
Q_DECLARE_METATYPE(std::shared_ptr<QTextStream>)
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
Class c;
c.connect(&c, &Class::source, &c, &Class::destination, Qt::QueuedConnection);
auto out = std::make_shared<QTextStream>(stdout);
emit c.source(out);
QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
*out << "About to exec" << endl;
return app.exec();
}
#include "main.moc"

Qt C++ connect signal with non-void signature to lambda

I want to connect a signal with non-void signature to a lambda function.
My code looks like the following
QTimeLine *a = new QTimeLine(DURATION, this);
connect(a, &QTimeLine::valueChanged, [a,this](qreal r) mutable { this->setMaximumHeight(r);});
in a way similar to the SIGNAL-SLOT approach:
connect(a, SIGNAL(valueChanged(qreal),this,SLOT(doStuff(qreal)));
My connect-to-lambda compiles, but it won't change this->height().
What did I get wrong? How should I write the lambda so that it takes the qreal from valueChanged?
I read the related documentation, but I couldn't find useful examples.
****EDIT****
In fact it works, I was getting the QTimeLine settings wrong. And yes, I don't need to capture a.
I was trying to animate a custom insertRow() method of a QTableWidget.
I also made the lambda change the height of the table row instead of the contained widget's. For reference, here's the working snippet:
QTimeLine *a = new QTimeLine(DURATION,this);
connect(a,&QTimeLine::valueChanged,[this](qreal r) mutable {
this->list->setRowHeight(0,r * ROW::HEIGHT);
});
a->start();
Thanks a lot for the quick replies anyway.
Should just work. Here is a complete SSCCE that demonstrates it working. Check what you are doing different in principles.
main.cpp
#include <QTimeLine>
#include <QObject>
#include <QDebug>
#include <QCoreApplication>
class Foo
{
void setMaximumHeight(int h) {height = h; qDebug() << "Height:" << height;}
public:
void doStuff() { QObject::connect(&timeLine, &QTimeLine::valueChanged, [this](qreal r) mutable { setMaximumHeight(r);}); timeLine.start(); }
int maximumHeight() const { return height; }
int height{0};
int DURATION{100};
QTimeLine timeLine{DURATION};
};
int main(int argc, char **argv)
{
QCoreApplication application(argc, argv);
Foo foo;
foo.doStuff();
return application.exec();
}
main.pro
TEMPLATE = app
TARGET = main
QT = core
CONFIG += c++11
SOURCES += main.cpp
Build and Run
qmake && make && ./main

user's arguments are empty with QCoreApplication in mysterious cases

I'm trying to create a console application with Qt and been facing really strange behavior when attempting to retrieve the arguments. My class is derived from QCoreApplication which has a function that should normally put all the args in some list of strings. But in some cases that call ends in a segmentation fault.
Here's the code:
main.cpp
#include "Diagramm.h"
int main(int argc, char *argv[])
{
Diagramm application(argc, argv);
application.run();
return EXIT_SUCCESS;
}
Diagramm.h
#include <QCoreApplication>
#include <iostream>
#include <QStringList>
#include <QFile>
#include <QDebug>
class Diagramm : public QCoreApplication
{
Q_OBJECT
public:
Diagramm(int argc, char *argv[]);
void run();
private:
void testArguments();
signals:
public slots:
};
Diagramm.cpp
#include "Diagramm.h"
Diagramm::Diagramm(int argc, char *argv[]) : QCoreApplication(argc, argv)
{
//std::cout << "calling Diagramm constructor" << std::endl;
}
void Diagramm::run()
{
testArguments();
}
void Diagramm::testArguments()
{
//get source and target files from arguments
QStringList arguments = this->arguments();
if(arguments.count() < 2)
{
std::cout << "Missing arguments" << std::endl;
return exit(1);
}
}
When compiling and executing the code above, everything works fine, BUT when I uncomment the line in Diagramm's constructor I've got a segmentation fault on the first line of function testArguments (the call to arguments())
I've been on that for hours, reading Qt's doc, forums... Does anyone know where that can come from? Any idea would be greatly appreciated.
Note : I'm not calling the exec function on purpose because I don't need any event loop.
Q(Core)Application wants argc and argv by reference, so your constructor should read
Diagramm(int& argc, char **argv[])
If you don't to this, it may work in some cases and lead to segfaults or strange behavior in others, as you encountered. Seems to be a common error and isn't easy to spot when reading the documentation.
arguments() is a static function so the line should be:
QStringList arguments = QCoreApplication::arguments();