PDA

View Full Version : Properly adding custom widget into Qt Designer



Baltharos
19th January 2015, 05:48
Hello,

I'm new to Qt, and I've been experimenting with a few things. I'm stuck with adding custom widgets to Qt Designer. I used the example given in Qt 5.3 (D:\Qt\Qt5.3.0\Examples\Qt-5.3\designer\customwidgetplugin), and ran it with release mode. Qt showed the 'find custom executable' dialogbox, which I think is fine (it's plugin anyway). Now, there are a few lines of command like:


TARGET = $$qtLibraryTarget($$TARGET)

target.path = $$[QT_INSTALL_PLUGINS]/designer
INSTALLS += target

I can't find the DLL installed in any 'designer' folder on my installation directory. The custom widget doesn't show up on the left side on Designer either, or pops up when I try to promote a blank widget. When I tried to put the resulting DLL into D:\Qt\Qt5.3.0\Tools\QtCreator\bin\plugins\designer , the designer plugins dialogbox shows that the plugin failed because it used an incompatible library ([5.3.0] release).

Is there anything that I missed?

wysota
19th January 2015, 07:35
You need to build the plugin with the same compiler, Qt version and same mode (release) Creator was built with. This might not be the same version you are using for building your programs.

Baltharos
19th January 2015, 07:47
You need to build the plugin with the same compiler, Qt version and same mode (release) Creator was built with. This might not be the same version you are using for building your programs.

Yes, I have tried to check with this answer. The problem is, I have never installed another version of Qt before on my machine. Another computer (also installed with Qt 5.3.0 and definitely compiled with mingw) also has the same problem. I used the same source code without any alteration, ran qmake, ran it with release mode, and when I put the resulting .a and .dll files into the plugins/designer folder the same error popped out. The custom widget won't appear on QtCreator-integrated Designer or non-integrated Designer.
On the past documentations, I found a command - Q_EXPORT_PLUGIN2(), which is not in the customwidgetplugin source code example in 5.3. Is this actually required in this version?

wysota
19th January 2015, 08:21
As I said you need to build the plugin so that it is binary compatible with your Qt Creator which has its own Qt binaries. You can check the version from Creator's help menu.

Alternatively you can build Creator yourself from sources with the version of Qt you are using for your programs and then you will be able to use the plugin built with the same toolchain.

Baltharos
19th January 2015, 11:41
As I said you need to build the plugin so that it is binary compatible with your Qt Creator which has its own Qt binaries. You can check the version from Creator's help menu.

Alternatively you can build Creator yourself from sources with the version of Qt you are using for your programs and then you will be able to use the plugin built with the same toolchain.

The about window says "Qt Creator 3.1.1, based on Qt 5.2.1 (MSVC 2010) 32 bit". So I have to either compile the plugin again to Qt 5.2.1 & MSVC 2010, or compile my own Creator with that version?

wysota
19th January 2015, 12:42
Basically yes. It doesn't have to be Qt 5.2.1, it can be any of Qt 5.2.x, but it does have to be 32bit MSVC2010. If you decide to build Qt Creator yourself, you are free to choose any compiler and any supported Qt version.

Baltharos
20th January 2015, 07:00
Basically yes. It doesn't have to be Qt 5.2.1, it can be any of Qt 5.2.x, but it does have to be 32bit MSVC2010. If you decide to build Qt Creator yourself, you are free to choose any compiler and any supported Qt version.

Okay, thanks a lot! Also a question again (I'm sorry): I assume that to embed my own widgets/plugins to QtCreator/Designer I have to refer to the Creator build version, but if I want to add custom libraries/plugins to my applications using Qt 5.3 compiled with mingw, I have to build them with version 5.3 + mingw right?

wysota
20th January 2015, 08:03
but if I want to add custom libraries/plugins to my applications using Qt 5.3 compiled with mingw, I have to build them with version 5.3 + mingw right?

Yes, that's correct. Just bear in mind that if you split your plugin into two parts -- a library implementing the widget and a plugin itself that uses this library (be it statically or dynamically linked), you can link your application againt that library only.

Baltharos
21st January 2015, 04:14
Yes, that's correct. Just bear in mind that if you split your plugin into two parts -- a library implementing the widget and a plugin itself that uses this library (be it statically or dynamically linked), you can link your application againt that library only.

Okay, thanks a lot! It works now, although I have to use version 5.2.1 and version 5.3.0 together. Is it possible to use 5.3.2-compiled library/plugins in 5.3.0-compiled applications? I'm gonna try to shift to online installer (so I can use a single Creator), and the one offered is 5.3.2..

wysota
21st January 2015, 07:49
Is it possible to use 5.3.2-compiled library/plugins in 5.3.0-compiled applications?
It should be ok.

Baltharos
28th January 2015, 02:32
It should be ok.

Thanks a lot!

Baltharos
3rd March 2015, 10:34
Sorry for bumping this thread, but I got another problem.. I managed to compile the dll, put it on the Designer, and it shows on the window form. But I can't access any of the custom methods, creating error "cannot locate ntablew.h". The custom widget subclass QTableWidget, and I use the template from Widget Collection.

for ntablew.h

#ifndef NTABLEW_H
#define NTABLEW_H

#include <QTableWidget>
#include <QStandardItemModel>

class NTableW : public QTableWidget
{
Q_OBJECT

public:
NTableW(QWidget *parent = 0);
void freezeRow(bool froze, int row);
void unfreezeRow(int row);

public slots:
void showFrozenRow();
void hideFrozenRow();

protected:
virtual void resizeEvent(QResizeEvent *event);

private:
QTableView * m_frozentableview;
QStandardItemModel * m_frozenmodel;
bool m_frozen;
int m_frozenrow;
void init();
void updateFrozenTableGeometry();

private slots:
void updateSectionWidth(int logicalIndex, int oldSize, int newSize);
void updateSectionHeight(int logicalIndex, int oldSize, int newSize);
};

#endif


For ntablew.cpp

#include "ntablew.h"
#include <QHeaderView>
#include "colordelegate.h"

NTableW::NTableW(QWidget *parent) :
QTableWidget(parent)
{
m_frozen = false;

m_frozentableview = new QTableView();
m_frozenmodel = new QStandardItemModel();

connect(horizontalHeader(),SIGNAL(sectionResized(i nt,int,int)), this,
SLOT(updateSectionWidth(int,int,int)));
connect(verticalHeader(),SIGNAL(sectionResized(int ,int,int)), this,
SLOT(updateSectionHeight(int,int,int)));

connect(m_frozentableview->horizontalScrollBar(), SIGNAL(valueChanged(int)),
horizontalScrollBar(), SLOT(setValue(int)));
connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
m_frozentableview->horizontalScrollBar(), SLOT(setValue(int)));

}

void NTableW::freezeRow(bool froze, int row = 0)
{
m_frozen = froze;
m_frozenrow = row;
setItemDelegateForRow(m_frozenrow, new ColorDelegate(this));
if(froze){
init();
}else{
m_frozentableview->lower();
}
}

void NTableW::unfreezeRow(int row){
m_frozentableview->lower();
m_frozenmodel->clear();
}

void NTableW::resizeEvent(QResizeEvent * event)
{
//QTableView::resizeEvent(event);
updateFrozenTableGeometry();
}

void NTableW::init()
{
QStandardItem * newItem = 0;
for(int i = 0; i < columnCount(); i++){
newItem = new QStandardItem(item(m_frozenrow, i)->text());
m_frozenmodel->setItem(0, i, newItem);
}

m_frozentableview->setModel(m_frozenmodel);

m_frozentableview->setFocusPolicy(Qt::NoFocus);
m_frozentableview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

viewport()->stackUnder(m_frozentableview);

m_frozentableview->setSelectionModel(selectionModel());
QHeaderView * horizontalHeaders = m_frozentableview->horizontalHeader();
horizontalHeaders->setVisible(false);
QHeaderView * verticalHeaders = m_frozentableview->verticalHeader();
verticalHeaders->sectionResizeMode(QHeaderView::Fixed);
if(!m_siderow) verticalHeaders->setVisible(false);
m_frozentableview->setItemDelegateForRow(m_frozenrow, new ColorDelegate(m_frozentableview));

m_frozentableview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOf f);
m_frozentableview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff) ;
m_frozentableview->show();

updateFrozenTableGeometry();

setHorizontalScrollMode(ScrollPerPixel);
setVerticalScrollMode(ScrollPerPixel);
m_frozentableview->setVerticalScrollMode(ScrollPerPixel);
}

void NTableW::showFrozenRow()
{
m_frozentableview->raise();
}

void NTableW::hideFrozenRow()
{
m_frozentableview->lower();
}

void NTableW::updateSectionWidth(int logicalIndex, int /* oldSize */, int newSize)
{
m_frozentableview->setColumnWidth(logicalIndex, newSize);
}

void NTableW::updateSectionHeight(int logicalIndex, int /* oldSize */, int newSize)
{
if (logicalIndex == m_frozenrow){
m_frozentableview->setRowHeight(m_frozenrow, newSize);
}
}

void NTableW::updateFrozenTableGeometry(){
if(rowViewportPosition(m_frozenrow) <= horizontalHeader()->height()){
m_frozentableview->setGeometry(verticalHeader()->width()+frameWidth(),
horizontalHeader()->height(), viewport()->width(), rowHeight(m_frozenrow));
}else if(rowViewportPosition(m_frozenrow) >= viewport()->height() - rowHeight(m_frozenrow) - horizontalHeader()->height()){
m_frozentableview->setGeometry(verticalHeader()->width()+frameWidth(),
viewport()->height()-rowHeight(m_frozenrow)-horizontalHeader()->height(), viewport()->width(), rowHeight(m_frozenrow));
}else{
m_frozentableview->setGeometry(verticalHeader()->width() + frameWidth(),
rowViewportPosition(m_frozenrow), viewport()->width(), rowHeight(m_frozenrow));
}
}


For ntablewidgetplugin.h

#ifndef NTABLEWPLUGIN_H
#define NTABLEWPLUGIN_H

#include <QDesignerCustomWidgetInterface>

class NTableWPlugin : public QObject, public QDesignerCustomWidgetInterface
{
Q_OBJECT
Q_INTERFACES(QDesignerCustomWidgetInterface)
#if QT_VERSION >= 0x050000
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface")
#endif // QT_VERSION >= 0x050000

public:
NTableWPlugin(QObject *parent = 0);

bool isContainer() const;
bool isInitialized() const;
QIcon icon() const;
QString domXml() const;
QString group() const;
QString includeFile() const;
QString name() const;
QString toolTip() const;
QString whatsThis() const;
QWidget *createWidget(QWidget *parent);
void initialize(QDesignerFormEditorInterface *core);

private:
bool m_initialized;
};

#endif

wysota
3rd March 2015, 11:56
Where did you put ntablew.h?

Baltharos
3rd March 2015, 13:40
The template put it in its own folder with ntablew.pri and ntablew.cpp. I just copied the resulting dll into plugins/designer folder, and the custom widget won't show methods in new projects. I didn't copy anything from the dll project onto the new project. When I tried to manually call the methods, that's when the error happens.

wysota
3rd March 2015, 15:27
If the project does not include ntablew.h then how do you expect to call methods defined in a class your compiler knows nothing about? If you call methods from QWidget then you include QWidget. The same is with your custom widget.

Baltharos
4th March 2015, 03:57
I've read some threads about this, but I didn't pay any heed back then.. :eek:

So even though I put the dll, the cpp and h file (or the pri file) have to be included in the project so the widget's methods can be called?

wysota
4th March 2015, 06:28
Your widget is no different than any other library you link with -- you need the library and a header file which describes classes contained within it. Just like you need qwidget.h and QtWidgets to use QWidget class (you don't need qwidget.cpp, right?).

Baltharos
4th March 2015, 06:52
I'm so sorry, but I still don't get it. The header file alone with the custom widget can call the methods (at least show them), but when I tries to run it the custom methods fail to compile (undefined reference). It only works when the cpp file is also included.

wysota
4th March 2015, 06:53
Because you are not linking with your plugin.

Baltharos
4th March 2015, 13:28
So I need to.. Link the resulting library and header file into new projects? Changes the .pro file to include the folder of the dll project?

anda_skoa
4th March 2015, 13:57
You can build the custom widget into a library and link both the applicaton and the designer plugin to it.

Cheers,
_

wysota
4th March 2015, 15:39
So I need to.. Link the resulting library and header file into new projects?
Same like with any other lib you use.


Changes the .pro file to include the folder of the dll project?
I don't understand what you mean.

Baltharos
8th March 2015, 19:45
Well, I tried to link in the .pro file. I made folder "includes" in which goes the header files, put the resulting .lib file into the new project folder (and the dll into the plugins/designer folder), and put some lines in the .pro file like this:

INCLUDEPATH += "C:\Qt\CTablegunakan\includes"
LIBS += "C:\Qt\CTablegunakan\ntablewplugin.lib"

and the custom functions went error again..

wysota
9th March 2015, 07:32
You are using incorrect syntax for the LIBS variable. It should be -L directoryname -l libraryname

Baltharos
9th March 2015, 08:11
LIBS += -L$$_PRO_FILE_PWD_ -lntablewplugin
LIBS += -LD:\CTablegunakan -lntablewplugin

don't work. I'm confused. If I'm not wrong, $$_PRO_FILE_PWD_ means the full directory path of the .pro file right? -L command can also be used for windows?

wysota
9th March 2015, 08:59
Check the compiler output to see the actual linker line being ivoked. See if the linker gets proper arguments for your library.

Baltharos
11th March 2015, 04:36
The result for the debug is this :


11:26:11: Running steps for project CTablegunakan...
11:26:11: Configuration unchanged, skipping qmake step.
11:26:11: Starting: "E:\Qt\Qt5.3.0\Tools\mingw482_32\bin\mingw32-make.exe"
E:/Qt/Qt5.3.0/Tools/mingw482_32/bin/mingw32-make -f Makefile.Debug
mingw32-make[1]: Entering directory 'D:/build-CTablegunakan-Desktop_Qt_5_3_0_MinGW_32bit-Debug'
g++ -Wl,-subsystem,windows -mthreads -o debug\CTablegunakan.exe debug/main.o debug/mainwindow.o debug/moc_mainwindow.o -lglu32 -lopengl32 -lgdi32 -luser32 -lmingw32 -lqtmaind -LD:/CTablegunakan -lntablewplugin -LE:/Qt/Qt5.3.0/5.3/mingw482_32/lib -lQt5Widgetsd -lQt5Guid -lQt5Cored
debug/mainwindow.o: In function `ZN10MainWindow21on_pushButton_clickedEv':
D:\build-CTablegunakan-Desktop_Qt_5_3_0_MinGW_32bit-Debug/../CTablegunakan/mainwindow.cpp:60: undefined reference to `NTableW::setHeaderTrue(bool, QStringList)'
D:\build-CTablegunakan-Desktop_Qt_5_3_0_MinGW_32bit-Debug/../CTablegunakan/mainwindow.cpp:61: undefined reference to `NTableW::setSiderowTrue(bool)'
debug/mainwindow.o: In function `ZN10MainWindow21on_checkBox_4_clickedEb':
D:\build-CTablegunakan-Desktop_Qt_5_3_0_MinGW_32bit-Debug/../CTablegunakan/mainwindow.cpp:87: undefined reference to `NTableW::freezeRow(int)'
D:\build-CTablegunakan-Desktop_Qt_5_3_0_MinGW_32bit-Debug/../CTablegunakan/mainwindow.cpp:89: undefined reference to `NTableW::isFrozen()'
D:\build-CTablegunakan-Desktop_Qt_5_3_0_MinGW_32bit-Debug/../CTablegunakan/mainwindow.cpp:90: undefined reference to `NTableW::unfreezeRow()'
debug/mainwindow.o: In function `ZN10MainWindow21on_checkBox_5_clickedEb':
D:\build-CTablegunakan-Desktop_Qt_5_3_0_MinGW_32bit-Debug/../CTablegunakan/mainwindow.cpp:100: undefined reference to `NTableW::isHeaderHidden()'
debug/mainwindow.o: In function `ZN13Ui_MainWindow7setupUiEP11QMainWindow':
D:\build-CTablegunakan-Desktop_Qt_5_3_0_MinGW_32bit-Debug/./ui_mainwindow.h:118: undefined reference to `NTableW::NTableW(QWidget*)'
collect2.exe: error: ld returned 1 exit status
Makefile.Debug:80: recipe for target 'debug\CTablegunakan.exe' failed
mingw32-make[1]: *** [debug\CTablegunakan.exe] Error 1
mingw32-make: *** [debug] Error 2
mingw32-make[1]: Leaving directory 'D:/build-CTablegunakan-Desktop_Qt_5_3_0_MinGW_32bit-Debug'
Makefile:34: recipe for target 'debug' failed
11:26:13: The process "E:\Qt\Qt5.3.0\Tools\mingw482_32\bin\mingw32-make.exe" exited with code 2.
Error while building/deploying project CTablegunakan (kit: Desktop Qt 5.3.0 MinGW 32bit)
When executing step 'Make'

Is this line wrong?
g++ -Wl,-subsystem,windows -mthreads -o debug\CTablegunakan.exe debug/main.o debug/mainwindow.o debug/moc_mainwindow.o -lglu32 -lopengl32 -lgdi32 -luser32 -lmingw32 -lqtmaind -LD:/CTablegunakan -lntablewplugin -LE:/Qt/Qt5.3.0/5.3/mingw482_32/lib -lQt5Widgetsd -lQt5Guid -lQt5Cored

wysota
11th March 2015, 06:55
Where is your plugin located? Is it built in release or debug mode? Did you remember to export the NTableW class using Q_DECL_EXPORT or similar?

Baltharos
27th March 2015, 17:18
Sorry for taking so long to reply. It's built in release mode (the plugin). Where do I have to put in Q_DECL_EXPORT? I've only seen it in QT library template, not custom Designer widget template.

wysota
27th March 2015, 20:50
You are building a library. You want to link your application with your custom widget code, don't you?

Baltharos
29th March 2015, 10:54
Yeah, I finally got it to work (can access the library now). How do I connect the library to widget?

wysota
29th March 2015, 22:48
I have no idea what "connecting the library to widget" means.