QML element positioning works unexpectedly - qt

This is my custom control. It draws background. I want it to occupy the whole header. But none of methods works, expect setting width and height explicitly, using some numbers. Even parent.width and parent.height does not work.
Control - TabViewHeaderBg.
Code:
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
import MyControls 1.0
Item
{
property int preInfoColumnWidth
property int nameColumnWidth
property int progressColumnWidth
property int sizeColumnWidth
property int columnSpacing
height: 40
TabViewHeaderBg
{
anchors.fill: parent
}
Row
{
spacing: columnSpacing
Row
{
width: preInfoColumnWidth
CheckBox
{
}
}
Text
{
text: "Name"
width: nameColumnWidth
anchors.verticalCenter: parent.verticalCenter
}
Text
{
text: "Status"
width: progressColumnWidth
anchors.verticalCenter: parent.verticalCenter
}
Text
{
text: "Size"
width: sizeColumnWidth
anchors.verticalCenter: parent.verticalCenter
}
}
}
This whole control is used as the header control in ListView.
Addition #1.
TabViewHeaderBgQc code:
class TabViewHeaderBgQc :
public QQuickPaintedItem
{
Q_OBJECT
public:
TabViewHeaderBgQc(
QQuickItem *parent = 0);
void paint(QPainter *painter) override;
signals:
public slots:
};
TabViewHeaderBgQc::TabViewHeaderBgQc(
QQuickItem *parent) :
QQuickPaintedItem(parent)
{
}
void TabViewHeaderBgQc::paint(QPainter *painter)
{
QPen pen(QColor(229,229,229), 1);
painter->setPen(pen);
painter->drawRect(boundingRect());
}
Imports with the following code:
qmlRegisterType<TabViewHeaderBgQc>("MyControls", 1, 0, "TabViewHeaderBg");
Addition #2.
Qt 5.8, Windows 10, Visual Studio 2015.

Related

Modify a QTextDocument of a QML TextArea element

I'm trying to create a minimal version of the following example: https://doc.qt.io/qt-5/qtquickcontrols-texteditor-example.html
I have created a DocumentHandler class with the following method:
class DocumentHandler : public QObject {
Q_OBJECT
QML_ELEMENT
public:
Q_INVOKABLE void changeFormat(QQuickTextDocument *doc) {
QTextCursor cursor(doc->textDocument());
cursor.select(QTextCursor::Document);
QTextCharFormat format;
format.setFontItalic(true);
cursor.mergeBlockCharFormat(format);
}
}
Unfortunately, when I call this method from the following QML code
import DocumentTest 1.0
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15
Window {
width: 640
height: 480
visible: true
title: qsTr("Document Test")
TextArea {
id: textArea
focus: true
anchors.fill: parent
wrapMode: Text.Wrap
selectByMouse: true
text: "Another day in paradise"
onReleased: {
document.changeChar(textDocument);
}
textFormat: Text.RichText
}
DocumentHandler {
id: document
}
}
I have a crash at the following line: https://github.com/qt/qtbase/blob/5.15.2/src/gui/text/qtextoption.h#L118
I read in the documentation that the QQuickTextDocument::textDocument() is read-only and that I can not modify its internal state so I wonder if using the QTextCursor is the right way to go. This is what is done in the example but I struggle finding out what is the difference with my code.
Looking at https://doc.qt.io/qt-5/qml-qtquick-textedit.html#textFormat-prop, i would replace textFormat: Text.RichText with textFormat: TextEdit.RichText
Sometime ago, I wrote a wrapper for the QSyntaxHighter classes. This achieves more than you require, but, it has the following elements:
control text color and formatting in your TextEdit
link to the TextEdit's textDocument property
Note that the example works with TextEdit not TextArea.
#include <QObject>
#include <QTextDocument>
#include <QSyntaxHighlighter>
#include <QQuickTextDocument>
class SyntaxHighlighter : public QSyntaxHighlighter
{
Q_OBJECT
Q_PROPERTY(QQuickTextDocument* textDocument READ textDocument WRITE setTextDocument NOTIFY textDocumentChanged)
public:
SyntaxHighlighter(QObject* parent = nullptr);
Q_INVOKABLE void setFormat(int start, int count, const QVariant& format);
// ...
};
You can use it like this:
TextEdit {
id: textEdit
}
SyntaxHighlighter {
textDocument: textEdit.textDocument
onHighlightBlock: {
let rx = /[A-Za-z]/g;
let m;
while ( ( m = rx.exec(text) ) !== null ) {
let keywords = [
'import', 'function', 'bool', 'var',
'int', 'string', 'let', 'const', 'property',
'if', 'continue', 'for', 'break', 'while',
];
if (keywords.includes(m[0])) {
setFormat(m.index, m[0].length, keywordFormat);
continue;
}
}
}
}
TextCharFormat {
id: keywordFormat
foreground: "#808000"
font.pointSize: 12
font.bold: true; font.italic: true
}
For full source code, refer to:
https://github.com/stephenquan/QtSyntaxHighlighterApp

error C2280: 'QQmlPrivate::QQmlElement<T>::QQmlElement(void)': attempting to reference a deleted function

I tried to operate a part of a qt project in Qt\Examples\Qt-5.9\quick\views, I am new to qml and I am trying to open each time a different QDialog window depending on qml pathview component that has been clicked. First of all, I started with creating a class (interfacageQML) which will serve to interface the qml Mainform and the QDialog (qtinterface), the necessary files are included among which interfacageqml.h.
here is the main.cpp :
#include "interfacageqml.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
qmlRegisterType<interfacageQML>("Interfacage", 1, 0,"Component:MouseArea");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
And here's interfacageqml.h :
#ifndef INTERFACAGEQML_H
#define INTERFACAGEQML_H
#include <QObject>
#include "qtinterface.h"
class interfacageQML : public QObject
{
Q_OBJECT
public:
interfacageQML(QObject *parent);
~interfacageQML();
Q_INVOKABLE void mouseClick();
signals:
void clicked();
};
#endif // INTERFACAGEQML_H
interfacageqml.cpp :
#include "interfacageqml.h"
#include <QDebug>
#include <QApplication>
interfacageQML::interfacageQML(QObject *parent)
: QObject(parent)
{
}
interfacageQML::~interfacageQML()
{
}
void interfacageQML::mouseClick()
{
qDebug() << "qmlinterface::mouseClick()";
emit clicked();
}
My project is organised this way :
the qmlinterface.qrc file contains these paths:
main.qml :
import QtQuick 2.6
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
MainForm{
anchors.fill: parent
}
}
MainForm.qml :
import QtQuick 2.6
import QtQuick.Controls 2.0 as QQC2
import Interfacage 1.0
Rectangle {
width: 800
height: 800
color: "white"
ListModel {
id: appModel
ListElement {
name: "Contacts"
icon: "pics/Resources/AddressBook_48.png"
}
ListElement {
name: "Music"
icon: "pics/Resources/AudioPlayer_48.png"
}
ListElement {
name: "Movies"
icon: "pics/Resources/VideoPlayer_48.png"
}
ListElement {
name: "Camera"
icon: "pics/Resources/Camera_48.png"
}
ListElement {
name: "Calendar"
icon: "pics/Resources/DateBook_48.png"
}
ListElement {
name: "Todo List"
icon: "pics/Resources/TodoList_48.png"
}
}
Component {
id: appDelegate
Item {
width: 100
height: 100
scale: PathView.iconScale
Image {
id: myIcon
y: 20
anchors.horizontalCenter: parent.horizontalCenter
source: icon
}
Text {
anchors {
top: myIcon.bottom
horizontalCenter: parent.horizontalCenter
}
text: name
}
MouseArea {
anchors.fill: parent
onClicked: {
view.currentIndex = index
Interfacage.mouseClick
}
}
}
}
Component {
id: appHighlight
Rectangle {
width: 100
height: 80
color: "lightsteelblue"
}
}
PathView {
id: view
anchors.fill: parent
highlight: appHighlight
preferredHighlightBegin: 0.5
preferredHighlightEnd: 0.5
focus: true
model: appModel
delegate: appDelegate
path: Path {
startX: 50
startY: 80
PathAttribute {
name: "iconScale"
value: 2.0
}
PathQuad {
x: 250
y: 200
controlX: 50
controlY: 200
}
PathAttribute {
name: "iconScale"
value: 2.0
}
PathQuad {
x: 600
y: 50
controlX: 400
controlY: 200
}
PathAttribute {
name: "iconScale"
value: 2.0
}
}
}
}
When I run this project, i got an error :
error:C2280
However, when I comment this line : qmlRegisterType<interfacageQML>("Interfacage", 1, 0, "Component:MouseArea"); the project runs and I can navigate between the pathview components in the MainForm.
When you use qmlRegisterType you are registering a new data type in QML, it is not an object, in that case the name "Component: MouseArea" is not suitable.
qmlRegisterType<interfacageQML>("Interfacage", 1, 0, "InterfacageQML");
Another error is that you must pass a parent by default, in this case 0 or nullptr since the items may not have parents.
class interfacageQML : public QObject
{
Q_OBJECT
public:
explicit interfacageQML(QObject *parent = nullptr);
[...]
As I said in the first lines, this is a new type, it is not an object so you must create it.
import QtQuick 2.6
import QtQuick.Controls 2.0 as QQC2
import Interfacage 1.0
Rectangle {
width: 800
height: 800
color: "white"
InterfacageQML{
id: myitem
}
[...]
And in the end if you want to use it you must call the function through the item.
MouseArea {
anchors.fill: parent
onClicked: {
view.currentIndex = index
myitem.mouseClick()
}
}
Since you want to connect your QDialog with the QML through that class, you can not do it since they will be different objects, one solution for this is to use a singleton, for this you must do the following:
interfacageqml.h
#ifndef INTERFACAGEQML_H
#define INTERFACAGEQML_H
#include <QObject>
#include <QQmlEngine>
class interfacageQML : public QObject
{
Q_OBJECT
static interfacageQML* instance;
explicit interfacageQML(QObject *parent = nullptr);
public:
static interfacageQML *getInstance();
~interfacageQML();
Q_INVOKABLE void mouseClick();
signals:
void clicked();
};
#endif // INTERFACAGEQML_H
interfacageqml.cpp
#include "interfacageqml.h"
#include <QDebug>
interfacageQML* interfacageQML::instance = 0;
interfacageQML *interfacageQML::getInstance()
{
if (instance == 0)
instance = new interfacageQML;
return instance;
}
interfacageQML::interfacageQML(QObject *parent) : QObject(parent)
{
}
interfacageQML::~interfacageQML()
{
}
void interfacageQML::mouseClick()
{
qDebug() << "qmlinterface::mouseClick()";
emit clicked();
}
main.cpp
#include "interfacageqml.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
static QObject *singletonTypeProvider(QQmlEngine *, QJSEngine *)
{
return interfacageQML::getInstance();
}
int main(int argc, char *argv[])
{
qmlRegisterSingletonType<interfacageQML>("Interfacage", 1, 0, "InterfacageQML", singletonTypeProvider);
// test
interfacageQML *obj = qobject_cast<interfacageQML*>(interfacageQML::getInstance());
QObject::connect(obj, &interfacageQML::clicked,[]{
qDebug()<<"clicked";
});
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
As it is a singleton it is not necessary to create an item, you can do it directly:
import Interfacage 1.0
[...]
MouseArea {
anchors.fill: parent
onClicked: {
view.currentIndex = index
InterfacageQML.mouseClick()
}
}
This last example can be found in the following link.

How to take a screen shot of the window and display it on an image using QML?

I want to take a screen shot using the code
QImage img = currentView_->grabWindow();
and i want to display this screen shot on my GUI using QML.
How to do this ?
If you want to transfer an image from C++ to QML the best way I guess is QQuickImageProvider. The small example bellow is maybe a bit different from what you want but anyway:
QQuickImageProvider class:
#ifndef IMAGEPROVIDER_H
#define IMAGEPROVIDER_H
#include <QQuickImageProvider>
#include <QQuickView>
#include <QImage>
class ImageProvider : public QObject, public QQuickImageProvider
{
Q_OBJECT
public:
ImageProvider(QObject *parent = 0, Flags flags = Flags());
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize);
protected:
QMap<int, QImage> m_images;
public slots:
void makeScreenshot();
};
#endif // IMAGEPROVIDER_H
#include "imageprovider.h"
ImageProvider::ImageProvider(QObject *parent, Flags flags) :
QQuickImageProvider(QQmlImageProviderBase::Image, flags),
QObject(parent)
{
}
QImage ImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
bool ok = false;
QImage img = m_images[id.toInt(&ok)];
return img;
}
void ImageProvider::makeScreenshot()
{
QQuickWindow *view = static_cast<QQuickWindow *>(sender());
static int pos = 0;
QImage img = view->grabWindow();
m_images.insert(pos,img);
QVariant returnedValue;
QMetaObject::invokeMethod(view, "setImage",
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, pos++));
}
Registering it in main.cpp:
QQmlApplicationEngine engine;
ImageProvider *imageProvider = new ImageProvider();
engine.addImageProvider(QLatin1String("screenshots"), imageProvider);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QQuickWindow *view = dynamic_cast<QQuickWindow *>(engine.rootObjects().at(0));
QObject::connect(view, SIGNAL(getScreenshot()),
imageProvider, SLOT(makeScreenshot()));
Usage:
import QtQuick 2.7
import QtQuick.Window 2.0
Window {
id:container
width: 600
height: 600
visible: true
signal getScreenshot()
Repeater {
model: 20
delegate: Rectangle {
x: Math.random() * 500
y: Math.random() * 500
width: Math.random() * 50 + 50
height: width
radius: width / 2
color: Qt.rgba(Math.random(),Math.random(),Math.random(),1)
}
}
Text {
id: txt
anchors.centerIn: parent
text: "Click me"
}
Rectangle {
id: rect
anchors.centerIn: parent
width: 0
height: 0
border.width: 5
border.color: "black"
Image {
id: img
anchors.fill: parent
anchors.margins: 5
source: ""
fillMode: Image.PreserveAspectFit
}
ParallelAnimation {
id: anim
PropertyAnimation {
property: "width"
target: rect
from: 0
to: 200
duration: 500
}
PropertyAnimation {
property: "height"
target: rect
from: 0
to: 200
duration: 500
}
}
}
MouseArea {
anchors.fill: parent
onClicked: {
txt.visible = false;
container.getScreenshot();
}
}
function setImage(id)
{
img.source = "image://screenshots/" + id;
anim.running = true;
}
}

C++ class exposed to QML error in fashion TypeError: Property '...' of object is not a function

I've successfully exposed a C++ class to QML. It is registered and found in Qt Creator. It's purpose is to connect to a database, as shown in following code:
#ifndef UESQLDATABASE_H
#define UESQLDATABASE_H
#include <QObject>
#include <QtSql/QSqlDatabase>
class UeSqlDatabase : public QObject
{
Q_OBJECT
Q_PROPERTY(bool m_ueConnected READ isConnected WRITE setConnected NOTIFY ueConnectedChanged)
private:
bool m_ueConneted;
inline void setConnected(const bool& ueConnected)
{ this->m_ueConneted=ueConnected; }
public:
explicit UeSqlDatabase(QObject *parent = 0);
Q_INVOKABLE inline const bool& isConnected() const
{ return this->m_ueConneted; }
~UeSqlDatabase();
signals:
void ueConnectedChanged();
public slots:
void ueConnectToDatabase (const QString& ueStrHost, const QString& ueStrDatabase,
const QString& ueStrUsername, const QString& ueStrPassword);
};
#endif // UESQLDATABASE_H
However, when I try to call method isConnected() from the following QML code
import QtQuick 2.0
Rectangle
{
id: ueMenuButton
property string ueText;
width: 192
height: 64
radius: 8
states: [
State
{
name: "ueStateSelected"
PropertyChanges
{
target: gradientStop1
color: "#000000"
}
PropertyChanges
{
target: gradientStop2
color: "#3fe400"
}
}
]
gradient: Gradient
{
GradientStop
{
id: gradientStop1
position: 0
color: "#000000"
}
GradientStop
{
position: 0.741
color: "#363636"
}
GradientStop
{
id: gradientStop2
position: 1
color: "#868686"
}
}
border.color: "#ffffff"
border.width: 2
antialiasing: true
Text
{
id: ueButtonText
color: "#ffffff"
text: qsTr(ueText)
clip: false
z: 0
scale: 1
rotation: 0
font.strikeout: false
anchors.fill: parent
font.bold: true
style: Text.Outline
textFormat: Text.RichText
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 16
}
MouseArea
{
id: ueClickArea
antialiasing: true
anchors.fill: parent
onClicked:
{
uePosDatabase.ueConnectToDatabase("127.0.0.1",
"testDb",
"testUser",
"testPassword");
if(uePosDatabase.isConnected()==true)
{
ueMenuButton.state="ueStateSelected";
}
else
{
ueMenuButton.state="base state"
}
}
}
}
I get the following error:
qrc:/UeMenuButton.qml:92: TypeError: Property 'isConnected' of object UeSqlDatabase(0x1772060) is not a function
What am I doing wrong?
You have this error because you have declared the property isConnected in C++ but you're calling it from QML in the wrong way: uePosDatabase.isConnected is the correct way, not uePosDatabase.isConnected().
If you want to call the function isConnected() you should change its name to differate it from the property, like getIsConnected(). Given your property declaration, you neither need to call this function directly nor you need to make it callable from QML with the Q_INVOKABLE macro.
You must first create the object you want in QML code and then use the function:
your QML Code:
import QtQuick 2.0
import QSqlDatabase 1.0
Rectangle {
id: ueMenuButton
QSqlDatabase {
id: uePosDatabase
}
.
.
.
MouseArea
{
id: ueClickArea
antialiasing: true
anchors.fill: parent
onClicked: {
console.log(uePosDatabase.isConnected())
}
}
}
Be aware in case of an error some lines earlier in the same .js file can lead to this problem. The following code will not be executed.

Mouse events not handled within QQuickItem inheritor

I want to write simple Qt Quick app with draggable QQuickItems. The items are well draggeble because of embedded MouseArea in the items. But a problem is that mouse events are not fired into C++ code in virtual overloaded functions. How to solve this problem or maybe there are some examples that I didn't find?
The QML file:
import QtQuick 2.0
import SimpleMaterial 1.0
Rectangle {
width: 320
height: 480
color: "black"
SimpleMaterialItem {
width: parent.width;
height: parent.height / 3;
color: "steelblue"
MouseArea {
anchors.fill: parent
width: 64
height: 64
drag.target: parent
drag.axis: Drag.XandYAxis
}
}
}
The C++ class:
class Item : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
public:
Item()
{
setFlag(ItemHasContents, true);
setFlag(ItemAcceptsDrops, true);
setFlag(ItemAcceptsInputMethod, true);
setAcceptedMouseButtons(Qt::AllButtons);
}
void mousePressEvent(QMouseEvent * event)
{
qDebug("Press"); // NOT CALLED!
}
public:
QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
{
...
}
};
If MouseArea handles mouse event it doesn't pass event to its parent.
You need:
onPressed: {
mouse.accepted = false;
}
in mouse area to let the SimpleMaterialItem handle onPressed event.

Resources