Qt/Qml: Custom widget -- cannot set "width" property as it is readonly - c++

I have created a custom widget called OpenGLWidget which I have registered with the qmlRegisterType function.
Nested inside the Qml file, I have this:
OpenGLWidget {
id: glwidget
width: parent.width
}
My app dies saying that width is a readonly property.
I have also tried adding this line to the OpenGLWidget header file:
Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged)
(However, even if these methods are not there, the code still compiles -- why?)
Anyway, it seems to me like Q_PROPERTY is used if you want to add your own custom properties, but properties like x, y, width, height, etc (which are all readonly) ought to be built-in, no?
EDIT: OpenGLWidget header file upon request.
#ifndef OPENGLWIDGET_H
#define OPENGLWIDGET_H
#include <QObject>
#include <QGLWidget>
class OpenGLWidget : public QGLWidget
{
Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged)
public:
OpenGLWidget();
void setWidth(int width) { resizeGL(width, this->geometry().height()); }
void widthChanged(int width) { }
protected:
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
};
#endif // OPENGLWIDGET_H

Your class is missing the Q_OBJECT macro. This causes the Qt meta object system to think of it as the closest superclass where the macro was defined, missing your method overrides.
Add Q_OBJECT line before the Q_PROPERTY line (it is needed so that the build system knows to run moc for this class). Then run qmake manually (eg. from Qt Creator build menu), because this change isn't picked up automatically so Makefiles aren't updated automatically.
It is a good idea to use Qt Creator new class wizard to add classes to a project, to avoid easy mistakes like this.

Related

Qt Custom Widget Plugin Q_Property With Enum

In my custom designer widget plugin I have a custom widget that derives QProgressBar. I have a field to chose either a determinate or indeterminate state. For this I have simply made an enum with the two states. I would like to use these values in the QtDesigner widget property area via implementing a Q_PROPERTY macro as follows:
class QDESIGNER_WIDGET_EXPORT QtMaterialProgress : public QProgressBar
{
Q_OBJECT
Q_PROPERTY(QColor progressColor WRITE setProgressColor READ progressColor)
Q_PROPERTY(QColor backgroundColor WRITE setProgressColor READ backgroundColor)
Q_PROPERTY(Material::ProgressType progressType WRITE setProgressType READ progressType)
.....
And also here is the enum declaration:
enum ProgressType
{
DeterminateProgress,
IndeterminateProgress
};
I would expect this piece of code to produce a QComboBox in the property editor of QtDesigner with the two states, however I get non of the such. I have also tried adding Q_ENUMS(PropertyType) to the header with no luck.
You have to use Q_ENUM (Not Q_ENUMS since it is deprecated from Qt 5.5: https://doc.qt.io/qt-5/whatsnew55.html) as the following example shows:
#ifndef TESTWIDGET_H
#define TESTWIDGET_H
#include <QWidget>
class TestWidget : public QWidget
{
Q_OBJECT
Q_PROPERTY(EnumTest test READ test WRITE setTest)
public:
TestWidget(QWidget *parent = 0);
enum EnumTest { ENUM0, ENUM1, ENUM2, ENUM3 };
Q_ENUM(EnumTest)
EnumTest test() const;
void setTest(const EnumTest &test);
private:
EnumTest mTest;
};
#endif
In the following link you can find a complete example

Make Qlabel clickable or double clickable in Qt

I am beginner in Qt, now I want to make my label clickable, I have searched so much online, but no one gives my a real example of how they made it. So can someone teach me step by step? Now my basic thinking is creating a new .c file and new .h file respectively and then include them into my mainwindow.c and then connect it with the existing label in ui form. These are what I was trying to do, but can not make it. Hope someone can teach and better put the step picture in the command, thanks.
Here is the clicklabel.h code:
#ifndef CLICKEDLABEL_H
#define CLICKEDLABEL_H
#include <QWidget>
#include <QLabel>
class ClickedLabel : public QLabel
{
Q_OBJECT
public:
ClickedLabel(QWidget *parent=0): QLabel(parent){}
~ClickedLabel() {}
signals:
void clicked(ClickedLabel* click);
protected:
void mouseReleaseEvent(QMouseEvent*);
};
#endif // CLICKEDLABEL_H
This the clicklabel.c code:
#include "clicklabel.h"
void ClickedLabel::mouseReleaseEvent(QMouseEvent *)
{
emit clicked(this);
}
These are what I added into my mainwindow.c( the name of the label is click_test):
void data_labeling::on_label_clicked()
{
QString path="/home/j/Pictures/images.jpeg";
QPixmap cat(path);
connect(ui->click_test, SIGNAL(clicked()), this,
SLOT(on_label_clicked()));
ui->click_test->setPixmap(cat);
ui->click_test->resize(cat.width(),cat.height());
}
Of course I have promoted it to clicklabel.h and also I have added void on_label_click() to my mainwindow.h under private slots, but nothing happened.
Create a new class derived from QLabel, reimplement mousePressEvent to emit custom pressed() signal (or any other functionality you need)
If you need to use your clickable label in ui files, follow these steps:
Add QLabel to the form
Right-click on added label and select Promote to...
Enter your clickable label class name and its header file name
Press add, than select your label in the tree and select promote
Now you can use your subclassed label (this tutorial actually works for any subclassed widget) as any QWidget using ui->
You can use QPushButton instead, but if you desperately need QLabel, you can do this:
clickable.h
class Clickable :public QLabel
{
Q_OBJECT
signals:
void clicked();
public:
void mousePressEvent(QMouseEvent* event);
using QLabel::QLabel;
};
clickable.cpp
void Clickable::mousePressEvent(QMouseEvent* event)
{
emit clicked();
}
UPDATE:
This implementation I used in my source code. I can't paste complete code, but here is the part where I used it.
source.h
...
private:
QLabel* label1;
QLabel* label2;
...
source.cpp
...
label1 = new Clickable("label1 text", this);
label2 = new Clickable("label2 text", this);
...
connect(label1 , SIGNAL(clicked()), this, SLOT(label1clicked()));
connect(label2 , SIGNAL(clicked()), this, SLOT(label1clicked()));
...

Subclassing widgets in QT designer

I am having a hard time subclassing Widgets in the QDesigner. I am using QDesigner to create my UI, but using cmake to compile rather than .pro files. So I am basically using QT Creator for nothing other than generating ui files.
Now I want to subclass QLabel in order to override the mouse click event, so as far as I understand all I have to do is right click the QLabel and select "promote to". It then asks me what i want to promote to, so I say "clickable_qlabel.h". However, when I call "make", I get "ui_mainWindow.h:95:5: error: ‘Clickable_QLabel’ does not name a type". Unfortunately I have no idea where I need to put clickable_qlabel.h, or whether it already exists and I just need to fill it with my code.
Any help would be greatly appreciated!
Many thanks.
[UPDATE]
OK, so now I have created the following class:
QLabelClickable.h
#ifndef _QLABELCLICKABLE_H_
#define _QLABELCLICKABLE_H_
#include <QLabel>
#include <QMouseEvent>
class QLabelClickable : public QLabel
{
Q_OBJECT
public:
explicit QLabelClickable( const QString& text="", QWidget* parent=0 );
~QLabelClickable();
signals:
void clicked(int, int);
protected:
void mousePressEvent(QMouseEvent* event);
};
#endif
QLabelClickable.cpp
#include "QLabelClickable.h"
QLabelClickable::QLabelClickable(const QString& text, QWidget* parent)
: QLabel(parent)
{
setText(text);
}
QLabelClickable::~QLabelClickable()
{
}
void QLabelClickable::mousePressEvent(QMouseEvent* event)
{
emit clicked(event->x(),event->y());
}
So this code compiles beautifully. So now I am in QtDesigner and I create a QLabel, called label4, and I right click and select "Promote to". Then under "Promoted class name:" I type "QLabelClickable" and under "Header file:" I type "QLabelClickable.h". Then I click "Promote". Wonderful. But I am still getting the error:
Vigil/build/ui_mainWindow.h:328:42: error: no matching function for call to ‘QLabelClickable::QLabelClickable(QWidget*&)’ label_4 = new QLabelClickable(tab);
So clearly QtDesigner needs to be instructed (somehow) where my implementation of QLabelClickable is. Quite frustrating.
Eh. My error, I should have read the error message properly. I hadn't included a constructor for the passing of only a QWidget. Adding
QLabelClickable::QLabelClickable( QWidget* parent ) : QLabel(parent) {
}
to my CPP has solved the problem! Hooray.

Qt create prototype tool for mobile device

Hi I need to create prototype tool for smartphone screen using Qt, I have png image of the smartphone right now and need to do place some text and image as shown in below image.
So my question is, is there anything similar already exist to create such a tool in C++ Qt.
Or do I need to use QPainter for achieving it.
Or any better method to accomplish it.
I can give you small code example how you can create such app. For main window you can set brush, created from this image, then set mask for window to ensure it painting right way. Also you need set Qt::FramelessWindowHint flag. Then you can add all needed widgets to this widget. Small example (assuming :/img/i.png is your picture, saved to resources):
At .h file:
#include <QFrame>
#include <QPixmap>
class TestFrame : public QFrame
{
Q_OBJECT
public:
TestFrame(QWidget* p = 0);
protected:
void resizeEvent(QResizeEvent* e) override;
private:
QPixmap _pix;
};
At .cpp file:
#include <QBitmap>
TestFrame::TestFrame(QWidget *p) :
QFrame(p, Qt::FramelessWindowHint | Qt::WindowSystemMenuHint),
_pix(":/img/i.png")
{
QPalette pal = palette();
pal.setBrush(QPalette::Background, QBrush(_pix));
setPalette(pal);
resize(_pix.width(), _pix.height());
}
void TestFrame::resizeEvent(QResizeEvent *e)
{
QFrame::resizeEvent(e);
setMask(_pix.scaled(size()).mask());
}
Also make sure your image has alpha-channel for invisible parts (I mean corners). For now it hasn't.

Adding signals to class that inherit from QGraphicsScene

I want to add a signal to a class that inherits from QGraphicsScene.
signals:
void update(std::vector< std::vector<int> > board);
When I do this, Qt Creator warns me that I forgot the Q_OBJECT macro. But somewhere I read that since QGraphicsScene doesn't inherit from QObject, I shouldn't put it in my class definition. But signals need this macro.
How do I add a signal to a class that doesn't inherit from QObject?
boardgui.h
#ifndef BOARDGUI_H
#define BOARDGUI_H
#include <QGraphicsView>
#include <QGraphicsScene>
class BoardGUI : public QGraphicsScene
{
Q_OBJECT
public:
BoardGUI(QGraphicsView*& view, int dimension);
~BoardGUI();
void buildBoard();
signals:
void update(std::vector< std::vector<int> > board);
private:
int dimension;
QGraphicsView* view;
};
#endif // BOARDGUI_H
Reposting as answer, as requested:
Is update() your signal? did you try to implement the signal yourself? If yes, don't do that, signals are defined by moc.
QGraphicsScene does inherit from QObject. You can consult the documentation.
http://doc.qt.io/qt-5/qgraphicsscene.html
Vtables have something to do with virtual functions. When you have an error like Undefined reference to vtable then it cannot find an implementation for a virtual function (I think). Have you implemented all of your functions? Maybe you used the virtual keyword when you weren't supposed to? Or vice versa?
Also, you say that you want to add a signal, but your code chunk shows a slot? Could you show a little more of your class?
If you have not implemented any class with Q_Object before to the project and you add the Q_OBJECT line yourself, you get the vtable error. If you add another c++ class to the project that inherits from QObject, then you get rid of this problem. You can remove this class you created if you dont need it. I am not sure why this happens, but this is easy way to get rid of the problem. Maybe the creator adds some line to the . pro file when you add a class that inherits from qobject.
Have you implemented your destructor? If not, try changing ~BoardGUI(); to ~BoardGUI(){};
Have you added boardgui.h to the MOC preprocessor's file list? Any class that uses QObject and Signals/Slots needs to be passed through the Meta-Object Compiler so it can generate the actual code behind the signals.
I am unsure if Qt Creator handles this automatically.
You simply have to inherit from QObject yourself.
boardgui.h
#ifndef BOARDGUI_H
#define BOARDGUI_H
#include <QGraphicsView>
#include <QGraphicsScene>
class BoardGUI : public QObject, public QGraphicsScene
{
Q_OBJECT
public:
BoardGUI(QGraphicsView*& view, int dimension);
~BoardGUI();
void buildBoard();
signals:
void update(std::vector< std::vector<int> > board);
private:
int dimension;
QGraphicsView* view;
};
#endif // BOARDGUI_H
If you are using Qt Creator, you shouldn't have to worry about moc, everything should be handled by Qt Creator.