Application crashes when adding QWidget obtained from shared library to QTabWidget - qt

//the subclass of widget in shared library
class MYWIDGETSHARED_EXPORT MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget *parent = 0);
void do_something();
};
extern "C"{
MYWIDGETSHARED_EXPORT MyWidget *getMyWidget(){ return new MyWidget;}
}
//the application which will use the shared library
void MainWindow::creatCentralWidget()
{
QTabWidget *tabWidget = new QTabWidget(this);
QLibrary myLib("xxx/MyWidget.dll");
if(myLib.load()){
MyWidget *widget = (MyWidget*)myLib.resolve("getMyWidget");
tabWidget->addTab(widget,"MyWidget");//Here cause crash!
}
//.......do_something()......
}
When I add MyWidget to tabWidget, the application crashed with code 255.
I have set the LIBS, INCLUDEPATH, DEPENDPATH, it seems no problem with them.
So I want to know, how can I correctly embed the widget from a shared library into QTabWidget? Thank you!

You have undefined behaviour due to your use of the following cast...
MyWidget *widget = (MyWidget*)myLib.resolve("getMyWidget");
The correct type for getMyWidget is...
MyWidget *(*)()
You need to resolve the symbol and then invoke it...
typedef MyWidget *(*get_my_widget_type)();
if (get_my_widget_type get_my_widget = get_my_widget_type(myLib.resolve("getMyWidget"))) {
MyWidget *widget = get_my_widget();
tabWidget->addTab(widget, "MyWidget");
}

Related

How can I connect a signal to QWidget::update slot?

I am using Qt5 with new signal/slot syntax.
I don't know why the following code doesn't work:
QWidget *widget = new QWidget();
connect(pipeline, &Pipeline::NewFrame, widget, &QWidget::update);
I get the error:
no matching member function for call to 'connect' why?
Pipeline class inherits from QObject and NewFrame signal has the same signature as QWidget::update
class Pipeline
: public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Pipeline)
public:
Pipeline(QObject *parent);
signals:
void NewFrame();
};
I am using QtCreator on Arch Linux with g++.
TL;DR: The pipeline should be signaling an image, and the widget should have a SetImage method:
class Pipeline : public QObject {
Q_OBJECT // important
public:
Q_SIGNAL void NewFrame(const QImage &);
...
};
class Viewer : public QWidget {
Q_OBJECT // important
QImage m_image;
public:
Q_SLOT void SetImage(const QImage &image) {
m_image = image;
update();
}
...
};
This is how you'd be using it - note that Viewer knows nothing about Pipeline, because it shouldn't: it just shows new frames, wherever they come from.
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Pipeline pipeline;
Viewer viewer;
QObject::connect(&pipeline, &Pipeline::NewFrame, &viewer, &Viewer::SetImage);
return app.exec();
}
Connecting anything to QWidget::update directly, especially from external sources, is usually a sign of bad design.
To satisfy your curiosity, you can use a lambda or qOverload to specify what you're connecting to, to fix the very error you're seeing - caused by ambiguity of the the type of the method pointer. Any of the following will work:
connect(…, widget, qOverload<>(&QWidget::update));
or
auto constexpr update = qOverload<>(&QWidget::update));
connect(…, widget, update);
or
connect(…, widget, [widget]{ widget->update(); });

How to read widgets from the .ui file in qt5?

I am trying to get the list of widgets from a .ui files.
So here is a bit of code:
QUiLoader loader;
QFile file(fname);
file.open(QFile::ReadOnly);
QWidget *myWidget = loader.load(&file, this);
file.close();
QStringList avlb_wd = loader.availableWidgets();
QMessageBox msg;
foreach (const QString &str, avlb_wd)
{
msg.setText(str);
msg.exec();
}
But as I can see, availableWidgets() gives me all the widgets, not the ones that are in .ui file.
How can I achieve it?
Thanks forward.
Make a subclass of QUiLoader, and reimplement createWidget, createLayout and createAction (there's also createActionGroup, but it's not really supported any more, unless you manually edit the ui file).
These functions are called every time a new widget, layout or action is created by the ui loader. So just call the base-class implementation to get the created object, and then you can gather whatever information you like, before returning it.
UPDATE:
So the basic QUiLoader subclass would look like this (add other overloads as required):
class UiLoader : public QUiLoader
{
Q_OBJECT
public:
UiLoader(QObject *parent = 0) : QUiLoader(parent) { }
virtual QWidget* createWidget(const QString &className,
QWidget *parent = 0, const QString &name = QString())
{
QWidget* widget = QUiLoader::createWidget(className, parent, name);
// do stuff with className, name, widget, etc
return widget;
}
};

SIGSEGV with QMainWindow singleton

The application I am writting as unique instantiation of some classes which have to be accessible easily. For that i use singletons.
For exemple my Core is defined as :
class Core : public QObject
{
Q_OBJECT
public:
Core();
~Core();
static Core& getCore()
{
static Core mycore;
return mycore;
}
(...)
};
and it works just great. However I tried to do the same with my MainWindow class, which interits from QMainWindow. I need that in order to access methods such as geometry() from other objects
However Core works great, MainWindow makes error when clossing the programe. The main window destructor is called and executed apparently once ( debug using qDebug() ) but i still have a SIGSEGV signal. What's happening? How to solve it?
Here is the code of MainWindow
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
static MainWindow& getUi()
{
static MainWindow myUi;
return myUi;
}
public slots:
void refreshImage();
private:
Ui::MainWindow *ui;
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(&appCore(), SIGNAL(refreshed()), this, SLOT(refreshImage()));
}
MainWindow::~MainWindow()
{
delete ui;
}
And the main code
QApplication app(argc, argv);
try
{
appCore().setDevice(MDMA::Kinect);
appUi().show();
return app.exec();
} catch(MDMA::exn e) {
(...)
}
where appCore and appUi are macros for Core::getCore and MainWindow::getUi()
This crash probably results from your QApplication being destroyed before the MainWindow.
If you cannot pass your MainWindow via other ways to the code where it is needed (e.g. as argument or via QObjecg::parent()), you could employ a technique similar to what QApplication does with it's instance method (a non-owning global reference):
Construct your MainWindow as an ordinary local variable on the stack, after the QApplication. Then set a global pointer (maybe better a QPointer; e.g. a static member of MainWindow), which you initially initialize to 0, to this in the constructor of MainWindow. You can also check if it was already initialized here to enforce the uniqueness. Via a public accessor method (instance?) for the global pointer, you can access the class from everywhere while ensuring destruction before QApplication.
If you want to make singletone, try to use general technics, for example, as described here:
http://www.qtcentre.org/wiki/index.php?title=Singleton_pattern
Hope, lot of questions will dissappear after reading all of that article.
As for me, there is nice and simple realization of singletone.
Good luck!

QDialog with label that I'm trying to paint

from my main window I am launching a dialog which has a label, in which I am trying to paint.
So, the dialog's header file (.h) has two classes, one for the dialog itself and one for my label. So, my label's class is this:
class MyImage : public QLabel
{
Q_OBJECT
public:
explicit MyImage(QWidget *parent = 0);
protected:
void paintEvent(QPaintEvent *e);
};
and in the .cpp, along with the constructor of my QDialog I have the constructor of my MyImage class and the paintEvent function:
MyImage::MyImage(QWidget *parent)
: QLabel(parent)
{
/*...*/
}
void MyImage::paintEvent(QPaintEvent *e)
{
QLabel::paintEvent(e);
QPainter painter(image_label);
painter.setPen(QPen(QBrush(QColor(0,0,0,180)),1,Qt::DashLine));
painter.setBrush(QBrush(QColor(255,255,255,120)));
painter.drawRect(selectionRect);
}
The image_label is a MyImage object. On the constructor of my QDialog I do the following so as to add it to my QDialog's layout:
mainLayout->addWidget(image_label);
But it is null. I get an error message on output (cannot add null widget) and when I try to add a pixmap to the image_label the program crashes.
Thanks in advance for any answers!
void MyImage::paintEvent(QPaintEvent *e)
{
// QPainter painter(image_label); <- Only paint onto yourself.
QPainter painter(this);
painter.setPen(QPen(QBrush(QColor(0,0,0,180)),1,Qt::DashLine));
painter.setBrush(QBrush(QColor(255,255,255,120)));
painter.drawRect(selectionRect);
}
Do not call the base class as any output will be overwritten by the new QPainter. It is crashing because image_label is null.

Qt subclassing from QWidget

I write my own class which subclass from QWidget
And this is my header file
#ifndef GRAPHMATRIX_H
#define GRAPHMATRIX_H
#include "treemodel.h"
#include <QWidget>
#include <Qt/qtableview.h>
class GraphMatrix : public QWidget
{
Q_OBJECT
public:
TreeModel& getModel();
GraphMatrix(QWidget* parent = 0);
void addTop(QString name);
void cutComponent(GraphMatrix* component, QVector<int> columns);
private:
TreeModel model;
QTableView* view;
public slots:
void changeValue(const QModelIndex& index);
};
#endif // GRAPHMATRIX_H
And I am getting this error
error C2248: 'QWidget::QWidget' : cannot access private member declared in class 'QWidget'
Can anyone help me?
Updated to add: I find answer, problem is in QList I must write QList. because QList is using copy constructor. Thank you for giving time for my problem
It looks like you are trying to call the default constructor of QWidget which is private. Instead, your constructor needs to call the public constructor of QWidget as follows:
GraphMatrix::GraphMatrix(QWidget* parent) : QWidget(parent) {}
I find answer, problem is in QList I must write QList. because QList is using copy constructor. Thank you for giving time for my problem

Resources