The project im trying to build is a media player with c++ and qt inclusion. However im failing to do this due to error , which i am not sure why or how it occurs. Please excuse me since this is my first ever project with c ++ or QT .
The Error is multiple defintions of frames for the media player which i am not sure because in header file only definitions are written and source (cpp) the code is written . I would really appreciate the help , thank you everyone for taking time of your day to help means a lot.
Code:
playeframe.h
#include <QAbstractVideoSurface>
#include <QImage>
#include <QVideoFrame>
#include <QLabel>
class PlayerFrame : public QAbstractVideoSurface
{
Q_OBJECT
public:
PlayerFrame(QObject *parent = nullptr);
void stopVideo();
Q_SIGNALS:
void fnSurfaceStopped(QPixmap pix);
private slots:
void fnClearPixmap();
private:
QPixmap CapImage;
QImage::Format imgFormat;
QVideoFrame curFrame;
bool Videostart(const QVideoSurfaceFormat &format);
QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const;
bool isFormatSupported(const QVideoSurfaceFormat &format) const;
bool present(const QVideoFrame &frame);
};
#endif
playerframe.cpp
#include "playerframe.h"
#include <QtWidgets>
#include <qvideosurfaceformat.h>
#include "playerwindow.h"
PlayerFrame::PlayerFrame(QObject *parent)
: QAbstractVideoSurface(parent)
, imgFormat(QImage::Format_Invalid)
{
}
bool PlayerFrame::Videostart(const QVideoSurfaceFormat &format)
{
QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat());
QSize size = format.frameSize();
if (imageFormat != QImage::Format_Invalid && !size.isEmpty())
{
this->imgFormat = imageFormat;
QAbstractVideoSurface::start(format);
return true;
}
else return false;
}
void PlayerFrame::fnClearPixmap()
{
CapImage = QPixmap();
}
void PlayerFrame::stopVideo()
{
QAbstractVideoSurface::stop();
}
QList<QVideoFrame::PixelFormat> PlayerFrame::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const
{
if (handleType == QAbstractVideoBuffer::NoHandle) {
return QList<QVideoFrame::PixelFormat>()
<< QVideoFrame::Format_RGB32
<< QVideoFrame::Format_ARGB32
<< QVideoFrame::Format_ARGB32_Premultiplied
<< QVideoFrame::Format_RGB565
<< QVideoFrame::Format_RGB555;
}
else
{
return QList<QVideoFrame::PixelFormat>();
}
}
bool PlayerFrame::isFormatSupported(const QVideoSurfaceFormat &format) const
{
QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat());
QSize size = format.frameSize();
return imageFormat != QImage::Format_Invalid && !size.isEmpty() && format.handleType() == QAbstractVideoBuffer::NoHandle;
}
bool PlayerFrame::present(const QVideoFrame &frame)
{
if (surfaceFormat().pixelFormat() != frame.pixelFormat() || surfaceFormat().frameSize() != frame.size())
{
setError(IncorrectFormatError);
stop();
return false;
}
else
{
if (!CapImage.isNull())
{
fnSurfaceStopped(CapImage);
}
curFrame = frame;
if (curFrame.map(QAbstractVideoBuffer::ReadOnly))
{
QImage image(
curFrame.bits(),
curFrame.width(),
curFrame.height(),
curFrame.bytesPerLine(),
imgFormat);
if (CapImage.isNull())
{
CapImage = QPixmap::fromImage(image.copy(image.rect()));
}
curFrame.unmap();
}
return true;
}
}
Related
The problem I'm having has been discussed multiple times, but I still don't understand how to fix the issue I'm having. I used to program in C++ a lot but switched over to Java for a while due to work. I'm getting back into C++ and I'm now having a lot of issues with memory management/pointers/references etc. This problem stems from that.
For context, these are files for a Qt 5.14 project that I'm working on.
The problem is that I have a private class variable named loggerLevel and the method that creates the segmentation fault error is getLevel which just returns the value of the loggerLevel. The that is supposed to be stored in the variable is an enum named Level that is defined in the header of the class.
I don't know if the problem stems from my lack of knowledge or if I am misunderstanding something about how classes work in C++, or if its something completely different. In any case, if anyone can help me out that would be great :)
--- Source code below ---
logger.cpp
#include "logger.h"
QString debugHTML = "<font color=\"gray\">";
QString infoHTML = "<font color=\"black\">";
QString warningHTML = "<font color=\"yellow\">";
QString errorHTML = "<font color=\"orange\">";
QString criticalHTML = "<font color=\"red\">";
QString endHTML = "</font><br>";
Logger::Logger(QObject *parent,
QString fileName,
QTextEdit *editor) : QObject(parent)
{
m_editor = editor;
m_showDate = true;
loggerLevel = Level::INFO;
if (!fileName.isEmpty()) {
file = new QFile;
file->setFileName(fileName);
file->open(QIODevice::Append | QIODevice::Text);
}
}
void Logger::write(const QString &value) {
QString text = value;
if (m_showDate) {
text = QDateTime::currentDateTime()
/*.toString("dd.MM.yyyy hh:mm:ss ") + text;*/
.toString("hh:mm:ss: ") + text;
}
QTextStream out(file);
out.setCodec("UTF-8");
if (file != 0) {
out << text;
} else {
//TODO: add QMessageBox here with error
}
//Adds HTML color/formatting
switch(loggerLevel)
{
case DEBUG: text = debugHTML + text; break;
case INFO: text = infoHTML + text; break;
case WARNING: text = warningHTML + text; break;
case ERROR: text = errorHTML + text; break;
case CRITICAL: text = criticalHTML + text; break;
default: text = infoHTML + text; break;
}
text = text + endHTML;
if (m_editor != 0) {
m_editor->insertHtml(text);
} else {
//TODO: add QMessageBox here with error
}
}
void Logger::write(const Level &level, const QString &value) {
Level prevLoggerLevel = Logger::getLevel();
Logger::setLevel(level);
write(value);
Logger::setLevel(prevLoggerLevel);
}
//--------Setters--------
void Logger::setLevel(const Level &level) {
loggerLevel = level;
}
void Logger::setShowDateTime(bool value) {
m_showDate = value;
}
//--------Getters--------
Logger::Level Logger::getLevel() {
return loggerLevel;
}
Logger::~Logger() {
if (file != 0) {
file->close();
}
}
logger.h
#ifndef LOGGER_H
#define LOGGER_H
#include <QObject>
#include <QPlainTextEdit>
#include <QFile>
#include <QTextStream>
#include <QDateTime>
class Logger : public QObject
{
Q_OBJECT
public:
explicit Logger(QObject *parent,
QString fileName = 0,
QTextEdit *editor = 0);
~Logger();
void setShowDateTime(bool value);
enum Level
{
DEBUG,
INFO,
WARNING,
ERROR,
CRITICAL
};
private:
QFile *file;
QTextEdit *m_editor;
bool m_showDate;
Level loggerLevel;
signals:
public slots:
void write(const QString &value);
void write(const Level &level, const QString &value);
void setLevel(const Level &level);
Level getLevel();
};
#endif // LOGGER_H
MainWindow.cpp
#include <string>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "settingsdialog.h"
#include "logger.h"
Logger *logger;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QString logFileName = "log.txt";
Logger *logger = new Logger(this, logFileName, ui->loggerOutput);
logger->write(Logger::Level::INFO, "Logger Initilized!");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_toolButton_clicked()
{
SettingsDialog settingsDialog;
settingsDialog.setModal(true);
settingsDialog.exec();
}
//Left Side of controller
void MainWindow::on_s_leftJoystickX_Throttle_sliderMoved(int position)
{ ui->l_leftJoystickX->setText(QStringLiteral("X-Axis: %1%").arg(position)); }
void MainWindow::on_s_leftJoystickY_Throttle_sliderMoved(int position)
{ ui->l_leftJoystickY->setText(QStringLiteral("Y-Axis: %1%").arg(position)); }
void MainWindow::on_s_leftTrigger_Throttle_sliderMoved(int position)
{ ui->l_leftTrigger->setText(QStringLiteral("Trigger: %1%").arg(position)); }
void MainWindow::on_s_joystickThrottle_sliderMoved(int position)
{ ui->l_joystickThrottle->setText(QStringLiteral("Throttle: %1%").arg(position)); }
//Right Side of controller
void MainWindow::on_s_rightJoystickX_Throttle_sliderMoved(int position)
{ ui->l_rightJoystickX->setText(QStringLiteral("X-Axis: %1%").arg(position)); }
void MainWindow::on_s_rightJoystickY_Throttle_sliderMoved(int position)
{ ui->l_rightJoystickY->setText(QStringLiteral("Y-Axis: %1%").arg(position)); }
void MainWindow::on_s_rightTrigger_Throttle_sliderMoved(int position)
{ ui->l_rightTrigger->setText(QStringLiteral("Trigger: %1%").arg(position)); }
void MainWindow::on_s_keyboardThrottle_sliderMoved(int position)
{ ui->l_keyboardThrottle->setText(QStringLiteral("Throttle: %1%").arg(position)); }
void MainWindow::on_b_keyboardAction_1_clicked()
{
logger->write(Logger::Level::CRITICAL, "test");
}
There are more files, but I believe they are not relevant to the problem, if needed I can post the other files aswell.
-----Solution!-----
#churill Solution explains what needs to be done to fix this problem but I also will detail it below to complete this question.
Since I had already made a forward declaration of logger
Logger *logger
at the top of MainWindow.cpp, creating a new Logger object
Logger *logger = new Logger(this, logFileName, ui->loggerOutput);
is unnecessary so calling the forward declarations variable name instead of creating a new Logger object
logger = new Logger(this, logFileName, ui->loggerOutput);
fixes the problem!
From first glance:
Logger *logger = new Logger(this, logFileName, ui->loggerOutput);
creates an object that has nothing to do with the global variable logger which is never initialized. Maybe you meant to write only
logger = new Logger(this, logFileName, ui->loggerOutput);
to initialize this global variable.
To somewhat address the title of your question: Yes you actually can call functions on invalid pointers, but then the this-pointer is not valid, thus accessing a member variable causes the seg-fault.
Hello i have a strange problem to save pixmap.
My Widget Header
public:
QPixmap *base; //Base Poses
QPixmap *Hair; //Hair
QPixmap *Composited; //Final Composition
bool compisition = false;
void Composite();
My Widget Cpp
At paintEvent
base = &pic;
Hair = &hairs;
if(compisition)
{
QPixmap pix(128,192);
QPainter *p = new QPainter(&pix);
p->drawPixmap(0,0,128,192,*base);
p->drawPixmap(0,0,128,192,*Hair);
Composited = &pix;
compisition = false;
}
void AnimPreview::Composite()
{
compisition = true;
this->update();
}
At main form source
void MainWindow::on_commandLinkButton_clicked()
{
QString file = QFileDialog::getSaveFileName(this,
tr("Save Sprite file"),
"",tr("File PNG (*.png)"));
const QPixmap *pix = ui->SpriteFront->pixmap();
if(!file.isEmpty())
{
QFile files(file);
files.open(QIODevice::WriteOnly);
ui->SpriteFront->Composite();
ui->SpriteFront->Composited->save(&files,"PNG");
}
}
When i try to save a file, the process work but whit on error
An unhandled win32 exception
For more information
complete code here
https://pastebin.com/GtaVCXGf
I have avoided reviewing where the error can be generated since there are many possible sources of the problem, among them the following:
It is not necessary that you create QPixmap pointers since in the end you will have the job of eliminating it from memory.
The same happens with QPainter since it only needs to be a local variable, in addition to that the painting is not done immediately, to be sure that it is painted you must call its end() method.
paintEvent is a protected method, so by design we prefer it to remain so.
It is not necessary to use a QFile to save an image, you can directly pass the filename to it.
Considering all the above, we obtain the following:
*.h
#ifndef ANIMPREVIEW_H
#define ANIMPREVIEW_H
#include <QLabel>
#include <QPixmap>
class AnimPreview : public QLabel
{
public:
AnimPreview(QWidget *parent = 0);
void Rotate(int value);
void Composite();
void Create(int _sex, int _hair);
QPixmap Composited;
private:
int sex = 0;
int hair = 0;
bool draw = true;
int rotation = 0;
const int offsetX = 16;
const int offsetY = 32;
QPixmap base;
QPixmap Hair;
bool compisition = false;
protected:
void paintEvent(QPaintEvent *);
};
#endif // ANIMPREVIEW_H
*.cpp
#include "animpreview.h"
#include <QPainter>
AnimPreview::AnimPreview(QWidget *parent):QLabel(parent)
{
}
void AnimPreview::paintEvent(QPaintEvent *){
QPainter p(this);
QPixmap pic;
QPixmap hairs;
if(draw)
{
//Sesso
switch(sex)
{
case 0:
pic.load(":/Male/Base/Res/man_f.png");
break;
case 1:
pic.load(":/Male/Base/Res/woman_f.png");
break;
}
//capelli
if(sex == 1)
{
switch(hair)
{
case 1:
hairs.load(":/Female/Hair/Res/7_aqua.png");
break;
case 2:
hairs.load(":/Female/Hair/Res/5_gold.png");
break;
}
}
if(sex == 0)
{
switch (hair)
{
case 0:
break;
case 1:
hairs.load(":/Male/Hair/Res/1_aqua.png");
break;
case 2:
hairs.load(":/Male/Hair/Res/14_black.png");
break;
}
}
}
p.drawPixmap(width()/2 - offsetX,height()/2 - offsetY,pic,0,rotation,32,48);
p.drawPixmap(width()/2 - offsetX,height()/2 - offsetY,hairs,0,rotation,32,48);
p.drawRect(0,0, width()-1, height()-1);
base = pic;
Hair = hairs;
if(compisition)
{
QPixmap pix(128,192);
QPainter p(&pix);
p.drawPixmap(0,0,128,192, base);
p.drawPixmap(0,0,128,192, Hair);
p.end();
Composited = pix;
compisition = false;
}
}
void AnimPreview::Rotate(int value)
{
rotation = value;
update();
}
void AnimPreview::Create(int _sex, int _hair)
{
sex = _sex;
hair = _hair;
draw = true;
}
void AnimPreview::Composite()
{
compisition = true;
update();
}
void MainWindow::on_commandLinkButton_clicked()
{
QString file = QFileDialog::getSaveFileName(this,
tr("Save Sprite file"),
"",tr("File PNG (*.png)"));
if(!file.isEmpty())
{
ui->SpriteFront->Composite();
ui->SpriteFront->Composited.save(file,"PNG");
}
}
For my game, I want to use PhysFs to extract music files that are in a zip file
I created a custom class MusicStream that inherits from sf::InputStream that I use as an sf::Music's stream.
This is my basic program:
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include "musicstream.h"
#include "physfs.h"
int main() {
PHYSFS_init(0);
PHYSFS_addToSearchPath("data.zip", 0);
std::string musicFile = "music.ogg";
if (PHYSFS_exists(musicFile.c_str()) == 0) {
PHYSFS_deinit();
return EXIT_FAILURE;
}
sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");
sf::Music myMusic;
MusicStream myStream(musicFile.c_str());
if (!myStream.getError()) {
myMusic.openFromStream(myStream);
myMusic.play();
}
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) window.close();
}
}
myMusic.stop();
PHYSFS_deinit();
return 0;
}
This works flawlessly, except for one thing:
When I close the window and the program exits, I'm getting a runtime error R6025 pure virtual function call and the program crashes.
So apparently a pure virtual function is called (sf::InputStream's dtor??), but I implemented all of sf::InputStream's functions and it doesn't make sense to me.
Also, I'm not really sure if the code is relevant but in case it is, this is the custom class:
musicstream.h
#ifndef MUSIC_STREAM_H_INCLUDED
#define MUSIC_STREAM_H_INCLUDED
#include <SFML/System.hpp>
#include "physfs.h"
class MusicStream : public sf::InputStream {
public:
MusicStream();
MusicStream(const char *fileName);
virtual ~MusicStream() override;
sf::Int64 read(void *data, sf::Int64) override;
sf::Int64 seek(sf::Int64 position) override;
sf::Int64 tell() override;
sf::Int64 getSize() override;
bool getError() const;
private:
PHYSFS_File *file_;
bool error_;
};
#endif
musicstream.cpp
#include "musicstream.h"
MusicStream::MusicStream() :
error_(true)
{
}
MusicStream::MusicStream(const char *filename) :
error_(false)
{
file_ = PHYSFS_openRead(filename);
if (file_ == nullptr) {
error_ = true;
}
}
MusicStream::~MusicStream() {
if (error_) { return; }
PHYSFS_close(file_);
}
sf::Int64 MusicStream::read(void *data, sf::Int64 size) {
if (error_) { return 0; }
sf::Int64 fileRead = PHYSFS_read(file_, data, 1, size);
if (fileRead == -1) {
return 0;
}
return fileRead;
}
sf::Int64 MusicStream::seek(sf::Int64 position) {
if (error_) { return -1; }
if (PHYSFS_seek(file_, position) == 0) {
return -1;
}
return position;
}
sf::Int64 MusicStream::tell() {
if (error_) { return -1; }
sf::Int64 position = PHYSFS_tell(file_);
return position;
}
sf::Int64 MusicStream::getSize() {
if (error_) { return -1; }
sf::Int64 size = PHYSFS_fileLength(file_);
return size;
}
bool MusicStream::getError() const {
return error_;
}
The problem were these two lines:
sf::Music myMusic;
MusicStream myStream(musicFile.c_str());
I swapped them and got rid of the error. It's because music is played in its own thread. It tried reading from the stream after it was destroyed. Now the music is destroyed before the stream is.
I'm trying to move the layout up when the keyboard is presented cause it hides my input textfield
but my app crash from line HASH_FIND_PTR(_targets, &tmp, element); from this class
void ActionManager::addAction(Action *action, Node *target, bool paused)
{
CCASSERT(action != nullptr, "");
CCASSERT(target != nullptr, "");
tHashElement *element = nullptr;
// we should convert it to Ref*, because we save it as Ref*
Ref *tmp = target;
HASH_FIND_PTR(_targets, &tmp, element); //error
if (! element)
{
element = (tHashElement*)calloc(sizeof(*element), 1);
element->paused = paused;
target->retain();
element->target = target;
HASH_ADD_PTR(_targets, target, element);
}
actionAllocWithHashElement(element);
CCASSERT(! ccArrayContainsObject(element->actions, action), "");
ccArrayAppendObject(element->actions, action);
action->startWithTarget(target);
}
I'm using cocos2d-x 3.2
i have debug and it's crashing after this line m_pLayout->runAction(moveBy);
anyone please give me some advice how can i solve it thanks
My LoginScene.h
#include "cocos2d.h"
#include "cocos-ext.h"
#include "CocosGUI.h"
USING_NS_CC;
USING_NS_CC_EXT;
using namespace ui;
class LoginScene : public Scene
{
public:
LoginScene(bool pPortrait=false);
~LoginScene();
virtual void onEnter();
virtual void onExit();
void onLogin(Ref* pSender, Widget::TouchEventType type);
void onRegister(Ref* pSender, Widget::TouchEventType type);
void TextFieldEvent(Ref* pSender,TextField::EventType type);
protected:
Layout* m_pLayout;
Layer* m_pUILayer;
};
and LoginScene.cpp
#include "LoginScene.h"
#include "cocostudio/CCSSceneReader.h"
#include "cocostudio/CCSGUIReader.h"
#include "cocostudio/CCActionManagerEx.h"
#include <sqlite3.h>
LoginScene::LoginScene(bool pPortrait):m_pLayout(NULL),m_pUILayer(NULL)
{
Scene::init();
}
LoginScene::~LoginScene()
{
}
void LoginScene::onEnter()
{
Scene::onEnter();
m_pUILayer=Layer::create();
m_pUILayer->scheduleUpdate();
addChild(m_pUILayer);
//register root from json
m_pLayout=dynamic_cast<Layout*>(cocostudio::GUIReader::getInstance()->widgetFromJsonFile("LoginScene/LoginScene.json"));
m_pUILayer->addChild(m_pLayout);
//button initialize
Button *btnLogin=static_cast<Button*>(Helper::seekWidgetByName(m_pLayout, "btnLogin"));
btnLogin->addTouchEventListener(CC_CALLBACK_2(LoginScene::onLogin, this));
Button *btnRegister=static_cast<Button*>(Helper::seekWidgetByName(m_pLayout, "btnRegister"));
btnRegister->addTouchEventListener(CC_CALLBACK_2(LoginScene::onRegister, this));
//textfield initialize
TextField *txtUsername=static_cast<TextField*>(Helper::seekWidgetByName(m_pLayout, "txtUsername"));
txtUsername->addEventListenerTextField(m_pLayout, textfieldeventselector(LoginScene::TextFieldEvent));
TextField *txtPassword=static_cast<TextField*>(Helper::seekWidgetByName(m_pLayout, "txtPassword"));
txtPassword->addEventListenerTextField(m_pLayout, textfieldeventselector(LoginScene::TextFieldEvent));
}
void LoginScene::onExit()
{
m_pUILayer->removeFromParent();
cocostudio::GUIReader::destroyInstance();
cocostudio::ActionManagerEx::destroyInstance();
cocostudio::SceneReader::destroyInstance();
Scene::onExit();
}
void LoginScene::onLogin(Ref* pSender, Widget::TouchEventType type)
{
if(type==Widget::TouchEventType::ENDED)
{
CCLOG("abc");
}
}
void LoginScene::onRegister(Ref* pSender, Widget::TouchEventType type)
{
if (type==Widget::TouchEventType::ENDED)
{
CCLOG("abc");
}
}
void LoginScene::TextFieldEvent(Ref* pSender,TextField::EventType type)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
switch (type)
{
case TextField::EventType::ATTACH_WITH_IME:
{
TextField* txtUsername=dynamic_cast<TextField*>(pSender);
MoveBy* moveBy=MoveBy::create(0.5f, Vec2(0,txtUsername->getContentSize().height*2.5));
m_pLayout->runAction(moveBy);
}
break;
case TextField::EventType::DETACH_WITH_IME:
{
TextField* txtUsername=dynamic_cast<TextField*>(pSender);
MoveBy* moveBy=MoveBy::create(0.1f, Vec2(0,-txtUsername->getContentSize().height*2.5));
m_pLayout->runAction(moveBy);
}
break;
default:
break;
}
#endif
}
I am attempting to create a single DLL "CustomPlugins" that contains two QtDesigner plugins. By replicating the WorldClockPlugin example I am able to get each of the plugins to work individually. However when I attempt to include both of them in a single DLL, I get the following build error:
LNK2005: _qt_plugin_instance already defined in moc_qledplugin.obj
It appears to me that by causing my plugin wrapper widgets to both inherit QDesignerCustomWidgetInterface it is resulting a multiple definition of the _qt_plugin_instance function. I've looked through the moc files and the customwidget header file (included by QDesignerCustomWidgetInterface) but cannot find any reference to this function.
QDesignerExportWidget is included in both of the plugin headers and QDESIGNER_WIDGET_EXPORT is included in both widget declarations.
Is it simply not possible to wrap two plugins in the same DLL? Or am I missing something?
Thank you.
Following is the code. qdragabletoolboxplugin.* files (not shown) are nearly identical to the qledplugin* files. Furthermore, qdragabletoolbox (also not shown) is declared in the same way as qled but obviously does something very different. For the sake of saving space I've left off those files and replaced some of the function definitions with ellipses.
.pro file:
QT += widgets designer
QMAKE_LFLAGS += /INCREMENTAL:NO
TARGET = $$qtLibraryTarget($$TARGET)
CONFIG += plugin
TEMPLATE = lib
target.path = $$[QT_INSTALL_PLUGINS]/designer
INSTALLS += target
HEADERS = qled.h \
qledplugin.h \
qdragabletoolbox.h \
qdragabletoolboxplugin.h
SOURCES = qled.cpp \
qledplugin.cpp \
qdragabletoolbox.cpp \
qdragabletoolboxplugin.cpp
RESOURCES += CustomDesignerPlugins.qrc
qled.h:
#ifndef QLED_H
#define QLED_H
#include <QWidget>
#include <QPaintEvent>
#include <QPainter>
#include <QList>
#include <QColor>
#include <QGradient>
#include <QtDesigner/QDesignerExportWidget>
class QDESIGNER_WIDGET_EXPORT QLED : public QWidget
{
Q_OBJECT
Q_ENUMS(ledColor)
Q_ENUMS(ledShape)
Q_PROPERTY(ledColor offColor READ offColor WRITE setOffColor)
Q_PROPERTY(ledColor onColor READ onColor WRITE setOnColor)
Q_PROPERTY(bool shadow READ shadow WRITE setShadow)
Q_PROPERTY(ledShape shape READ shape WRITE setShape)
Q_PROPERTY(bool value READ value WRITE setValue)
public:
enum ledColor { Red = 0, Orange, Yellow, Green, Blue, Indigo, Violet, Black, Gray, DarkGray };
enum ledShape { Ellipse = 0, Rectangle, Circle, Square };
explicit QLED(QWidget *parent = NULL);
virtual ~QLED() { /*empty*/ }
bool value() const { return mValue; }
ledColor onColor() const { return mOnColor; }
ledColor offColor() const { return mOffColor; }
ledShape shape() const { return mShape; }
bool shadow() const { return mShadow; }
signals:
public slots:
void setValue(bool value) { mValue = value; update(); }
void setShape(ledShape shape) { mShape = shape; update(); }
void setOnColor(ledColor color) { mOnColor = color; update(); }
void setOffColor(ledColor color) { mOffColor = color; update(); }
void setShadow(bool b) { mShadow = b; update(); }
void toggle() { mValue = !mValue; update(); }
protected:
void paintEvent(QPaintEvent *event);
private:
void drawBezel(QPainter *painter);
void drawFace(QPainter *painter);
void drawShadow(QPainter *painter);
private:
bool mValue;
ledColor mOnColor;
ledColor mOffColor;
bool mBezel;
float mBezelWidth;
ledColor mBezelColor;
bool mShadow;
ledShape mShape;
QList<QColor> colors;
};
#endif
qled.cpp
#include "qled.h"
QLED::QLED(QWidget *parent)
: QWidget(parent)
{
...
}
void QLED::paintEvent(QPaintEvent *event)
{
...
}
void QLED::drawBezel(QPainter *painter)
{
...
}
void QLED::drawFace(QPainter *painter)
{
...
}
void QLED::drawShadow(QPainter *painter)
{
...
}
qledplugin.h
#ifndef QLEDPLUGIN_H
#define QLEDPLUGIN_H
#include <QDesignerCustomWidgetInterface>
class QLEDPlugin : public QObject, public QDesignerCustomWidgetInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface" FILE "qled.json")
Q_INTERFACES(QDesignerCustomWidgetInterface)
public:
QLEDPlugin(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 initialized;
};
#endif
qledplugin.cpp
#include "qled.h"
#include "qledplugin.h"
#include <QtPlugin>
QLEDPlugin::QLEDPlugin(QObject *parent)
: QObject(parent)
{
initialized = false;
}
void QLEDPlugin::initialize(QDesignerFormEditorInterface *core)
{
Q_UNUSED(core);
if (initialized)
return;
else
initialized = true;
}
bool QLEDPlugin::isInitialized() const
{
return initialized;
}
QWidget *QLEDPlugin::createWidget(QWidget *parent)
{
return new QLED(parent);
}
QString QLEDPlugin::name() const
{
return QLatin1String("QLED");
}
QString QLEDPlugin::group() const
{
return QLatin1String("Display Widgets");
}
QIcon QLEDPlugin::icon() const
{
return QIcon(QLatin1String(":/QLED/LEDIcon.png"));
}
QString QLEDPlugin::toolTip() const
{
return "Binary status indicator";
}
QString QLEDPlugin::whatsThis() const
{
return "";
}
bool QLEDPlugin::isContainer() const
{
return false;
}
QString QLEDPlugin::domXml() const
{
return "<ui language=\"c++\">\n"
" <widget class=\"QLED\" name=\"qLed\">\n"
" <property name=\"geometry\">\n"
" <rect>\n"
" <x>0</x>\n"
" <y>0</y>\n"
" <width>25</width>\n"
" <height>25</height>\n"
" </rect>\n"
" </property>\n"
" </widget>\n"
"</ui>";;
}
QString QLEDPlugin::includeFile() const
{
return QLatin1String("QtWidgets/QLED.h");
}
The compiler error message gives you all the information you need: you have two widgets, but you need just one plugin.
Instead of implementing QDesignerCustomWidgetInterface, implement QDesignerCustomWidgetCollectionInterface.