PDA

View Full Version : Custom Widget doesn t show.



Frej
10th March 2010, 14:18
I have created a custom widget and a plugin for that widget in Designer. I have tested the custom widget localy and it works fine. The widget appears in the widget box in designer/form editor and I can drag i it to my window hand handle the signals & and slots. But when I hit preview or compile the widget doesn´t show. I do not get any error messages and when i look into the generated ui_XXXXX.h and it looks fine. What am I missing? Could Upload All code......

customDial.proj

CONFIG += designer \
plugin \
debug_and_release
TARGET = $$qtLibraryTarget(speeddialplugin)
TEMPLATE = lib
HEADERS = speeddialplugin.h \
qtsvgdialgauge.h \
qtsvgpixmapcache.h
SOURCES = speeddialplugin.cpp \
qtsvgdialgauge.cpp \
qtsvgpixmapcache.cpp
RESOURCES = icons.qrc \
skins.qrc
LIBS += -L.
target.path = $$[QT_INSTALL_PLUGINS]/designer
INSTALLS += target
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD

# include(speeddial.pri)
QT += svg


speedDialPlugin.h

#ifndef SPEEDDIALPLUGIN_H
#define SPEEDDIALPLUGIN_H

#include <QtDesigner/QDesignerCustomWidgetInterface>
#include <QObject>
#include <Qt>

class speedDialPlugin : public QObject, public QDesignerCustomWidgetInterface
{
Q_OBJECT
Q_INTERFACES(QDesignerCustomWidgetInterface)

public:
speedDialPlugin(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

speedDialPlugin.cpp


#include "qtsvgdialgauge.h"
#include "speeddialplugin.h"

#include <QtCore/QtPlugin>

speedDialPlugin::speedDialPlugin(QObject *parent)
: QObject(parent)
{
m_initialized = false;
}

void speedDialPlugin::initialize(QDesignerFormEditorInt erface * /* core */)
{
if (m_initialized)
return;

// Add extension registrations, etc. here

m_initialized = true;
}

bool speedDialPlugin::isInitialized() const
{
return m_initialized;
}

QWidget *speedDialPlugin::createWidget(QWidget *parent)
{
//return new speedDial(parent);

QtSvgDialGauge * gauge = new QtSvgDialGauge(parent);
gauge->setSkin("Tachometer");
gauge->setMinimum(0);
gauge->setMaximum(120);
gauge->setValue(0);
return gauge;
}

QString speedDialPlugin::name() const
{
return QLatin1String("speedDial");
}

QString speedDialPlugin::group() const
{
return QLatin1String("");
}

QIcon speedDialPlugin::icon() const
{
return QIcon();
}

QString speedDialPlugin::toolTip() const
{
return QLatin1String("");
}

QString speedDialPlugin::whatsThis() const
{
return QLatin1String("");
}

bool speedDialPlugin::isContainer() const
{
return false;
}

QString speedDialPlugin::domXml() const
{
return QLatin1String("<widget class=\"speedDial\" name=\"speedDial\">\n</widget>\n");

}

QString speedDialPlugin::includeFile() const
{
return QLatin1String("hh.h");
}

Q_EXPORT_PLUGIN2(speeddialplugin, speedDialPlugin)

qtSvgDialGauge.h

/*

*/

#ifndef QT_SVG_DIAL_GAUGE
#define QT_SVG_DIAL_GAUGE
#include <QtGui/QWidget>
#include <Qt>
#include <QtCore/QPair>
#include <QtDesigner/QDesignerExportWidget>

class QSvgRenderer;
class QtSvgPixmapCache;

class QDESIGNER_WIDGET_EXPORT QtSvgDialGauge : public QWidget
{
Q_OBJECT
Q_PROPERTY(QString skin READ skin WRITE setSkin)
Q_PROPERTY(int minimum READ minimum WRITE setMinimum)
Q_PROPERTY(int maximum READ maximum WRITE setMaximum)
Q_PROPERTY(qreal startAngle READ startAngle WRITE setStartAngle)
Q_PROPERTY(qreal endAngle READ endAngle WRITE setEndAngle)
public:
explicit QtSvgDialGauge(QWidget * parent = 0);
~QtSvgDialGauge();

void setSkin(const QString& skin);
QString skin() const;


void setMinimum(int minimum);
void setMaximum(int maximum);
void setNeedleOrigin(qreal x, qreal y);
void setStartAngle(qreal angle);
void setEndAngle(qreal angle);

int value() const;
int minimum() const;
int maximum() const;
qreal needleOriginX() const;
qreal needleOriginY() const;
qreal startAngle() const;
qreal endAngle() const;

virtual QSize minimumSizeHint() const;
virtual QSize sizeHint() const;
void setShowOverlay(bool);

public slots:
void setValue(int value);

private:
void init();
QRectF availableRect(QtSvgPixmapCache * renderObject) const;

QtSvgPixmapCache* m_backgroundRenderer;
QtSvgPixmapCache* m_needleShadowRenderer;
QSvgRenderer* m_needleRenderer;
QRectF availableRect(QSvgRenderer * renderObject) const;
QtSvgPixmapCache* m_overlayRenderer;
/** minimum possible value **/
int m_minimum;
/** maximum possible value **/
int m_maximum;
/** actual value **/
int m_value;
/** smallest start angle **/
qreal m_startAngle;
/** highest end angle **/
qreal m_endAngle;
/** position x of needle **/
qreal m_originX;
/** position y of needle **/
qreal m_originY;
bool m_showOverlay;

/** name of actual skin **/
QString m_skin;
protected:
void paintEvent(QPaintEvent * event);
};

#endif // QT_SVG_DIAL_GAUGE

qtSvgDialGauge.cpp

/*

*/
#include <QtGui/QPainter>
#include <QtSvg/QSvgRenderer>

#include "qtsvgdialgauge.h"

#include "qtsvgpixmapcache.h"

/*!

\class QtSvgDialGauge qtsvgdialgauge.h


\code

// Create a QtSvgDialGauge
QWidget * widget = new QWidget(this)
QtSvgDialGauge * gauge = new QtSvgDialGauge(widget);
gauge->setSkin("Beryl");
widget->addWidget(gauge);
widget->show();
\endcode

/*!
Constructor of the widget with \p parent as
Parent.
*/
QtSvgDialGauge::QtSvgDialGauge(QWidget * parent)
: QWidget(parent),
m_minimum(0),
m_maximum(100),
m_value(0),
m_startAngle(0),
m_endAngle(100),
m_originX(0.5),
m_originY(0.5),
m_showOverlay(true)
{
init();
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
}

/*!
Destructor
*/
QtSvgDialGauge::~QtSvgDialGauge()
{
}



/*.....
......
.....
.....
.....
.....*/
}

qtSvgPixmapCache.h

/*

*/


#ifndef QT_SVG_PIXMAP_CACHE
#define QT_SVG_PIXMAP_CACHE

#include <QtCore/QSizeF>
#include <Qt>
#include <QObject>
#include <QtDesigner/QDesignerExportWidget>


class QPainter;
class QString;
class QRectF;

class QtSvgPixmapCachePrivate;

class QDESIGNER_WIDGET_EXPORT QtSvgPixmapCache : public QObject
{
Q_OBJECT

public:
QtSvgPixmapCache(QObject* parent = NULL);

#endif // QT_SVG_PIXMAP_CACHE

qtSvgPixmapCache.cpp

/*
....
....
...*/

wysota
10th March 2010, 17:09
How did you implement sizeHint()?

Frej
11th March 2010, 08:22
/*!
\internal
\overload
Set default size hint. Can be changed at runtime.
*/
QSize QtSvgDialGauge::sizeHint() const
{
return QSize(400, 400);
}

wysota
11th March 2010, 08:37
And the paintEvent()?

Frej
11th March 2010, 08:41
/*!
\internal
\overload
Overloaded paint event to draw the QtSvgDialGauge components
*/
void QtSvgDialGauge::paintEvent(QPaintEvent * event)
{
Q_UNUSED(event);
QPainter painter(this);

QRectF targetRect;

qreal angleSpan = m_endAngle - m_startAngle;
qreal valueSpan = m_maximum - m_minimum;
qreal rotate = (m_value - m_minimum) / valueSpan * angleSpan + m_startAngle;

// draw background
targetRect = availableRect(m_backgroundRenderer);
painter.translate((width() - targetRect.width()) / 2.0, (height() - targetRect.height()) / 2.0);
painter.save();

m_backgroundRenderer->render(&painter, targetRect);

targetRect = availableRect(m_needleRenderer);
targetRect.moveTopLeft(QPoint(-targetRect.width() * m_originX,
-targetRect.height() * m_originY));

// move origin to center of widget and rotate for the needle
painter.translate(targetRect.width() * m_originX,
targetRect.height() * m_originY);

// draw needle shadow with offset x=2, y=4
painter.save();
painter.translate(2, 4);
painter.rotate(rotate);
m_needleShadowRenderer->render(&painter, targetRect);

// draw needle
painter.restore();
painter.rotate(rotate);
m_needleRenderer->render(&painter, targetRect);

painter.restore();
if (m_showOverlay) {
// draw overlay
targetRect = availableRect(m_overlayRenderer);
m_overlayRenderer->render(&painter, targetRect);
}
}

I have been testing the widget localy i.e. not as a plugin and then it works fine. So it should be any problem with widget code as I see. It has to be the plugin or how i setup the .pro file or something.

wysota
11th March 2010, 09:09
I have been testing the widget localy i.e. not as a plugin and then it works fine. So it should be any problem with widget code as I see. It has to be the plugin or how i setup the .pro file or something.
Hmm... earlier you said it worked fine when previewing the widget in Designer but not after compiling the code. Or at least so I understood... Can you say again when it works and when it doesn't work? And also how the widget works in general (mainly where does it get data from for the renderer).

Frej
11th March 2010, 09:43
The widgetplugin appears in the widgetbox in designer/form editor and i can drag it to my canvas and it is displayed as it should. I can connect signals and slot to it. Butwhen I hit preview in designer or when I compile the application the widget doesn´t show anymore. If I don´t use it as a plugin but just includes the widget code I can manually (in code) create an instance of my widget and it works fine. So it seems to be the plugin that is the problem. My widget uses vector graphics (svg) images that are painted on top of each other with specified relations. So svg files are loaded and ordered in a structured way and then a special renderer takes care of rendering for different platforms and so....

pixmapcache.h


#include "qtsvgpixmapcache.h"

#include <QtGui/QPainter>
#include <QtSvg/QSvgRenderer>

#if defined(Q_WS_HILDON) && (QT_VERSION < 0x040500)
# define QT_MAEMO_XRENDER_ALPHA_BUG
# warning Using workaround for 'XRender and QPixmap with alpha' drawing bug
#endif

class QtSvgPixmapCachePrivate
{
public:
void updatePixmapCache(const QSizeF& size);

public:
QSvgRenderer svgRenderer;
#ifdef QT_MAEMO_XRENDER_ALPHA_BUG
QImage pixmapCache;
#else
QPixmap pixmapCache;
#endif
};

QtSvgPixmapCache::QtSvgPixmapCache(QObject* parent) : QObject(parent)
, d(new QtSvgPixmapCachePrivate())
{
}

QtSvgPixmapCache::QtSvgPixmapCache(const QString& url)
: d(new QtSvgPixmapCachePrivate())
{
load(url);
}

QtSvgPixmapCache::~QtSvgPixmapCache()
{
delete d;
}

bool QtSvgPixmapCache::load(const QString& url)
{
d->svgRenderer.load(url);
#ifdef QT_MAEMO_XRENDER_ALPHA_BUG
d->pixmapCache = QImage();
#else
d->pixmapCache = QPixmap();
#endif
return d->pixmapCache.isNull();
}

bool QtSvgPixmapCache::isValid() const
{
return d->svgRenderer.isValid();
}

void QtSvgPixmapCache::render(QPainter* painter, const QRectF& bounds)
{
if (!d->svgRenderer.isValid()) {
return;
}

if (d->pixmapCache.isNull() || bounds.size().toSize() != d->pixmapCache.size()) {
d->updatePixmapCache(bounds.size());
}

#ifdef QT_MAEMO_XRENDER_ALPHA_BUG
painter->drawImage(bounds.topLeft(), d->pixmapCache);
#else
painter->drawPixmap(bounds.topLeft(), d->pixmapCache);
#endif
}

QSize QtSvgPixmapCache::defaultSize() const
{
return d->svgRenderer.defaultSize();
}

void QtSvgPixmapCachePrivate::updatePixmapCache(const QSizeF& size)
{
#ifdef QT_MAEMO_XRENDER_ALPHA_BUG
pixmapCache = QImage(size.toSize(), QImage::Format_ARGB32_Premultiplied);
#else
pixmapCache = QPixmap(size.toSize());
#endif
pixmapCache.fill(Qt::transparent);

QPainter painter(&pixmapCache);
svgRenderer.render(&painter);
painter.end();
}

wysota
11th March 2010, 09:47
What happens if you compile a standalone program using that widget of yours but not by including the widget files directly into the project but instead by linking with the plugin library? Because the plugin has nothing to do with your application - it is only used by Designer. If you build an application that uses it, you have to link with the code of the widget regardless of the existance of the plugin.

Frej
11th March 2010, 09:55
Yeah I think the linking to my libspeeddial.so is what is going wrong. If I just include LIBS += "/home/frej/qtsdk-2010.01/bin/designer/libspeeddialplugin.so" in my pro file i should be able to use my widget something like this:

#include "speeddialplugin.h"

speedDialPlugin *p = new speedDialPlugin();
QWidget *gauge = p->createWidget(parent);
setCentralWidget(gauge);
But this does´t work, I aslo have to add include paths to my speeddialplugin for this to work. I assumed i vould just link to the lib file and it would contain alll logic is that wrong, if not it seem like it is the linking that is not working.

wysota
11th March 2010, 10:04
Please explain what "doesn't work" means in this case. You always need the header file, the library itself is not enough (you need Qt header files to use Qt too, right?).

Frej
11th March 2010, 10:20
If i create a new project and add LIBS += "/home/frej/qtsdk-2010.01/bin/designer/libspeeddialplugin.so" to link to my speeddialplugin. It i then try to write something like this:
#include "speeddialplugin.h"

speedDialPlugin *p = new speedDialPlugin();
QWidget *gauge = p->createWidget(parent);
setCentralWidget(gauge);
But this doesn´t work, error: speeddialplugin.h: No such file or directory.

So I have to add includepaths to my speeddialplugin.h, INCLUDEPATH += "/home/frej/Documents/Qt Dev/customDial". Then it works fine to create an instance of my widget like
speedDialPlugin *p = new speedDialPlugin();
QWidget *gauge = p->createWidget(parent);
setCentralWidget(gauge);



But if instead by adding the widget by code, but drag n drop from the widget box instead, then I get the problem with the widget not showing when I compile or hit preview.
(Thanx for beeing patient)

wysota
11th March 2010, 10:26
But why include the plugin header? You only need the widget header. If you can't see the widget in the compiled code then inspect the code created by uic (ui_speeddial.h) to see if it creates your widget properly. If it does then the problem is in your widget code. Make sure the paint event is called and that the size of the widget is valid (during that paint event). Once you verify that we can continue looking for problems.

Frej
11th March 2010, 10:48
Found the problem now. Since i didn´t set a skin in my constructor (to leave it to the user) no background image where set, so the widget was there but it didn´t contain any graphic. Sorry for bothering you with this silly problem. On the upside i think I learnt alot on how plugins work.