QSettings & unicode - qt

I have some buttons in a qml file and I want to make them editable from a settings file.
Therefore I read my settings.ini with QSettings and pass the data to qml.
All works just fine until I try to read icons in unicode format.
I found this question but the answer doesn't work for me.
The settings.ini has UTF-8 format and since "QString icon2 = QString::fromUtf8("\uf00c");" works, the problem has to be QSettings.
Any ideas?
main.cpp
----------
int main(int argc, char *argv[])
{
// locale code doesnt help
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
QGuiApplication app(argc, argv);
QList<QObject*> dataList;
QSettings *settings = new QSettings("settings.ini", QSettings::IniFormat);
// settings code doesnt change anything
settings->setIniCodec(QTextCodec::codecForName("UTF-8"));
settings->beginGroup("icons");
// read settings
QString icon1 = settings->value("icon1").toString();
// test
QString icon2 = QString::fromUtf8("\uf00c");
settings->endGroup();
qDebug() << "icon1:" << icon1;
qDebug() << "icon2:" << icon2;
// to qml
MyData *data1 = new MyData();
data1->setIcon(icon1);
MyData *data2 = new MyData();
data2->setIcon(icon2);
dataList.append(data1);
dataList.append(data2);
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("mydata", QVariant::fromValue(dataList));
engine.load(QUrl("qrc:/main.qml"));
return app.exec();
}
qml
----------
FontLoader { id: fontAwesome; source: "qrc:/fontawesome-webfont.ttf" }
Repeater {
model: mydata
Grid {
rows: 1
spacing: 5
Text {
text: index
color: "black"
}
Text {
font: fontAwesome.name
text: model.icon
color: "black"
}
}
}
settings.ini
[icons]
icon1=\uF00C
Output:
icon1: "F00C"
icon2: "\uF00C"
qml output

Looks like I was just on the totally wrong track..
INI file escaping works just fine.
\x....

Related

qml Camera save same image with different resolutions

I'm using QML's Camera component and Camera.imageCapture to save images.
I want to save multiple resolutions of the same image when user click "Capture" button.
The code I'm trying to run is simply like this:
// 160x120
camera.imageCapture.resolution = Qt.size(160,120)
camera.imageCapture.captureToLocation("/location/")
// 320x340
camera.imageCapture.resolution = Qt.size(320,240)
camera.imageCapture.captureToLocation("/anotherLocation/")
camera.imageCapture.resolution = Qt.size(-1,-1) // set to default again
Thanks.
If you'd save your camera input to a QImage you can save and resize and save again using QImage's image.save() and image.scaled() functions.
I've used these functions before for resizing images and it works perfect.
However I don't know how you can save the camera input to a QImage, but I'll look into that and report back.
I know it's not a full answer to your question, but it's a start. I hope that this was helpful.
Here is how I have solved:
Save the image with highest resolution available in Camera:
Component.onCompleted: {
camera.imageCapture.resolution = camera.imageCapture.supportedResolutions[camera.imageCapture.supportedResolutions.length-1]
}
Give the path of that file to the QImage's constructor.
Then scale & save:
Full Code:
imageresizer.cpp:
#include "imageresizer.h"
#include <QImage>
ImageResizer::ImageResizer(QObject *parent) : QObject(parent)
{}
void ImageResizer::resizeImage(int width, int height, QString file, QString savefile)
{
QImage img(file);
img = img.scaled(width, height);
img.save(savefile);
}
imageresizer.h:
#ifndef IMAGERESIZER_H
#define IMAGERESIZER_H
#include <QObject>
class ImageResizer : public QObject
{
Q_OBJECT
public:
explicit ImageResizer(QObject *parent = nullptr);
signals:
public slots:
void resizeImage(int width, int height, QString file, QString savefile);
};
#endif // IMAGERESIZER_H
Don't forget to make it available from QML:
int main(int argc, char *argv[])
{
qmlRegisterType<ImageResizer>("project.imageresizer", 1, 0, "ImageResizer"); // Here
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
main.qml:
import project.imageresizer 1.0
Window {
id: mainWindow
visible: true
width: 1024
height: 600
title: ""
ImageResizer {
id: imageResizer
}
// Use it like:
// imageResizer.resizeImage(100,100,imgPath,scaleImgPath)
}

Add property to QML object after QQmlComponent::beginCreate()

I am looking for a way to add properties in the scope of a certain objects in a QML object tree.
file.qml:
import QtQml 2.0
QtObject {
property var test1: QtObject {
objectName: "child1"
property string color: environment.color
}
property var test2: QtObject {
objectName: "child2"
property string color: environment.color
}
}
main.cpp:
#include <QtCore>
#include <QtQml>
int main(int argc, char* argv[]) {
QCoreApplication app(argc, argv);
QQmlEngine engine;
QQmlComponent component(&engine,QUrl::fromLocalFile("file.qml"));
QObject* object = component.beginCreate(engine.rootContext());
QObject* child1 = object->findChild<QObject*>("child1", Qt::FindChildrenRecursively);
QObject* child2 = object->findChild<QObject*>("child2", Qt::FindChildrenRecursively);
QQmlPropertyMap env1;
QQmlPropertyMap env2;
env1["color"] = "green";
env2["color"] = "blue";
// Now I want to make object1 available for child1
// and object2 available for child2.
// But I can't do this:
// qmlContext(test1)->setContextProperty("environment", env1);
// qmlContext(test2)->setContextProperty("environment", env2);
component.completeCreate();
if (!component.errors().isEmpty()) {
qDebug() << component.errorString();
}
Q_ASSERT(child1->property("color") == QString("green"));
Q_ASSERT(child2->property("color") == QString("blue"));
qDebug() << "It works";
}
I admit that the example above looks a bit odd. It's a simplified variant of the example I posted in the Qt forum.

Load image in QML WebEngineView using QQuickImageProvider

I'm injecting HTML content into a QML WebEngineView using the loadHtml method, and I'm trying to get it to load the images through a QQuickImageProvider.
Up to now, we've been successfully loading images from a Qt resource container (qrc), but this is not flexible enough.
contentimageprovider.cpp
#include "contentimageprovider.h"
#include <QDebug>
ContentImageProvider::ContentImageProvider() : QQuickImageProvider(QQuickAsyncImageProvider::Image)
{
}
QImage ContentImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
qDebug() << __FUNCTION__ << id;
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QtWebEngine/QtWebEngine>
#include "contentimageprovider.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
QtWebEngine::initialize();
engine.addImageProvider(QLatin1String("content-images"), new ContentImageProvider);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
main.qml
import QtQuick 2.7
import QtQuick.Window 2.2
import QtWebEngine 1.4
Image {
source: "image://content-images/this-image-is-requested";
}
WebEngineView {
Component.onCompleted: {
loadHtml("<img src='qrc://images/this-image-is-displayed.png' /><img src='image://content-images/this-image-should-also-be-requested' />", "/");
}
}
Expected output
requestImage "this-image-is-requested"
requestImage "this-image-should-also-be-requested"
Actual output
requestImage "this-image-is-requested"
And the image loaded via qrc in the WebEngineView is displayed, and a broken image is shown for the other one.
Has anyone been able to get this to work?
Thanks to #Xplatforms who pointed out the initial error in assuming that the Chromium engine under the QML WebEngineView would interact with the QML Quick engine and trigger the image provider.
The solution was to implement a QWebEngineUrlSchemeHandler:
void ImageRequestHandler::requestStarted(QWebEngineUrlRequestJob *request)
{
// request->requestUrl() is a QUrl
QFile *image = new QFile(QDir::currentPath() + "/storage/content/" + request->requestUrl().path() + ".png");
// makes sure the image deletes itself when closing the file
connect(image, &QIODevice::aboutToClose, image, &QObject::deleteLater);
// close the file when the request job is done
connect(request, &QObject::destroyed, image, &QIODevice::close);
QMimeDatabase mimeDB;
QMimeType mimeType = mimeDB.mimeTypeForFile(image->fileName());
request->reply(mimeType.name().toUtf8(), image);
}
main.cpp
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
// web engine to provide content display
QtWebEngine::initialize();
// intercept requests from the web engine to provide locally loaded content and images
ImageRequestHandler *imageRequestHandler = new ImageRequestHandler();
QQuickWebEngineProfile::defaultProfile()->installUrlSchemeHandler("image", imageRequestHandler);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}

Setting context property for multiple qml files

I have a main.qml and inside that i have two banners(titlebanner and bottombanner) as shown in below.
Window {
id: main
visible: true
Image {
source: "qrc:/banner.png"
anchors.fill: parent
}
TitleBanner {
x:0
y:10
}
BottomBanner {
x:0
y:420
}
}
In TitleBanner.qml, i have below code
Item {
Rectangle {
id : id_title_banner
property real value : titlebanner.title
Image {
source: "qrc:/banner_title.png";
}
//todo:: some animation stuffs on 'value' later
}
}
In BottomBanner.qml, i have below code
Item {
Rectangle {
id : id_bottom_banner
property real value : bottombanner.title
Image {
source: "qrc:/banner_bottom.png";
}
//todo:: some animation stuffs on 'value' later
}
}
In C++ side, I am keeping two separate objects(for later flexibility) for both title banner and bottom banner. I set the root context property to expose the title banner objects from C++ to qml as below
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
//create title banner object
CTitleBanner *objTitleBanner = new CTitleBanner();
//create bottom banner object
CBottomBanner *objBottomBanner = new CBottomBanner();
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("titlebanner", objTitleBanner);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
My question is, how can we set context property for both titlebanner and bottombanner qml files separately instead of setting it to root context ? My concern is at later point if more banner comes, I set it to rootContext. Is it a proper way of doing ? How can we create seperate context for each banner ?
Your assumption:
it replaces above context property.
is wrong:
// in main.cpp
QObject* obj1 = new QObject();
QObject* obj2 = new QObject();
engine.rootContext()->setContextProperty("obj1", obj1);
engine.rootContext()->setContextProperty("obj2", obj2);
qDebug() << "obj1" << obj1 << engine.rootContext()->contextProperty("obj1").value<QObject*>();
qDebug() << "obj2" << obj2 << engine.rootContext()->contextProperty("obj2").value<QObject*>();
// in main.qml
Component.onCompleted: console.log(obj1, obj2)
// output:
obj1 QObject(0x22d8c768) QObject(0x22d8c768)
obj2 QObject(0x22d8c778) QObject(0x22d8c778)
qml: QObject(0x22d8c768) QObject(0x22d8c778)
Both objects are there, with the right identifier.
Personally I don't like contextProperties since they are easily to be shadowed e.t.c. - I rather register my CPP models as singletons so I can import them at the places where I really want to have access to them. Though there are downsides of those singletons. (e.g. qmlscene will fail to import them)

QML - How to use QStringList as a model of ListView?

I try to make TelnetClient.I use FileIO for read Telnet.There is no problem read or write and also create a string list but I need to show QStringList to ListView but I m getting error: "m_model is not defined".
I create QStringList:
QStringList FileIO::read() {
if (m_source.isEmpty()) {
emit error("source is empty");
return QStringList();
}
QFile file(m_source);
QString fileContent;
QString line;
QStringList list;
if ( file.open(QIODevice::ReadWrite) ) {
QTextStream t( &file );
line = t.readAll();
fileContent += line;
list.append(line.split("\r\n"));
foreach (QString item, list) {
if (item[0].isNumber()) {
list2.append(item);
}
}
QQmlContext *ctxt;
ctxt->setContextProperty("m_model", QVariant::fromValue(list2));
qDebug() << "\r\n\r\nlist2 =" << list2;
line = t.readAll();
qDebug() << "SOURCE" << m_source;
file.close();
}
else {
emit error("Unable to open the file");
return QStringList();
}
return list2;
This can make a new QStringList successfully and also I assign my string list as a model; m_model.
ListView {
id: listView1
x: 0
y: 0
model: m_model
delegate: Rectangle{
Text {text: modelData }
}
}
and here is my ListView. When I try like this, I m getting error. How can I solve this problem. If I can use "list2" in main.cpp I can solve the problem but I don't know how can I use it in main.cpp because it exist in another class.
Thank you!
You can try to set the context property with an instance of the class. That way, you can instantiate the class in main, and then pass it's address to set the context property. If the data of the model is subject to change while the program is running, I would suggest implementing the QStringList as a Q_Property.
//main.cpp
FileIO fileIO;
QQmlApplicationEngine engine;
QQmlContext* ctx = engine.rootContext();
ctx->setContextProperty("fileio", &fileIO);
engine.load(/* Path to your qml */);
//qml
ListView {
id: listView1
x: 0
y: 0
model: fileio.m_model
delegate: Rectangle{
Text {text: modelData }
}
}
To elaborate on Francisco's answer: if the data of the model is subject to change while the program is running, it is indeed the cleanest solution to implement the QStringList as a Q_PROPERTY, because that will send signals to QML objects when the model data changes. A good example is here.
According to the Qt Manual there is also another option:
Note: There is no way for the view to know that the contents of a QStringList have changed. If the QStringList changes, it will be necessary to reset the model by calling QQmlContext::setContextProperty() again.
An (untested) example of this technique is demonstrated below:
main.cpp:
QStringList updateStringList() {
// Your code from "I create QStringList" goes here.
}
QStringList myStringList = updateStringList();
QQmlApplicationEngine engine;
QQmlContext* ctx = engine.rootContext();
ctx->setContextProperty("m_model", &myStringList);
engine.load("ListView.qml");
// ... more code ...
myStringList = updateStringList();
ctx->setContextProperty("m_model", &myStringList);
ListView.qml:
ListView {
id: listView1
x: 0
y: 0
model: fileio.m_model
delegate: Rectangle{
Text {text: modelData }
}
}

Resources