I'm a little new to QML and C++ in general, but I'm learning quick. I'm a bit stumped on something though. I'm trying to make an application that reads text from a QML TextInput text field, and writes the data to a text area. I'm not sure what is going wrong, but upon reading the text I get the error "Unable to assign QQuickTextInput to QString" - and I'm a bit stumped on how to write back to a text area. If someone could shed some light, that would be appreciated. I've already been through the QML/C++ binding page, and that doesn't seem to help. I'm wondering if that page was written for an older version of Qt... Here's my code thus far:
QML:
import QtQuick 2.0
import QtMultimedia 5.0
import QtQuick.Controls 1.1
import QtQuick.Window 2.1
import QtWinExtras 1.0
import QtQuick.Layouts 1.1
Rectangle {
id: main
width: 640
height: 480
signal onClicked_button
TextInput {
id: textbocks
objectName: textbocks
x: 280
y: 230
width: 80
height: 20
text: "Text Input"
font.pixelSize: 12
Button {
id: button1
x: -10
y: 45
text: "Button"
onClicked:main.onClicked_button()
}
}
TextField {
id: textField1
x: 257
y: 329
placeholderText: qsTr("Text Field")
}
}
header (class - originally designed to write back to text input):
#ifndef TEST_H
#define TEST_H
#include <QObject>
#include <QtCore>
#include <QString>
#include <QQuickView>
#include <QQuickItem>
#include <QQmlComponent> // for accessing QML from C++
#include <QQmlContext> // for accessing C++ from QML
class test : public QObject
{
Q_OBJECT
public:
explicit test(QObject *parent = 0);
signals:
public slots:
void test_button(){
QQuickView *view = new QQuickView(QUrl("test.qml"));
view->show();
QQuickItem *item = view->rootObject();
QObject *item = object->findChild<QObject*>("textbocks");
textbox->setProperty("text", str);
delete textbox;
return;}
private:
bool switched;
bool textOutput;
QString str = "Hello World";
};
#endif // TEST_H
And main .cpp file:
#include "test.h"
#include <QGuiApplication>
#include <QtCore>
#include <QObject>
#include <QQuickItem>
#include <QQmlComponent>
#include <QQmlContext>
#include <QQuickView>
#include <QDeclarativeEngine>
#include <QDeclarativeComponent>
#include <QDeclarativeContext>
test::test(QObject *parent) :
QObject(parent)
{
}
int main (int argc, char*argv[]) {
QGuiApplication app(argc, argv);
QQuickView *view = new QQuickView(QUrl("test.qml"));
view->show();
QQuickItem *item = view->rootObject();
test *funcs = new test();
// connect button signals to their slots:
QObject::connect(item, SIGNAL(buttonClicked_button()), funcs, SLOT(test_button()));
delete funcs;
return 0;
}
Any help would be appreciated. Some of this is still a bit abstract for me... Thanks!!
as I noticed you are creating two QQuickViews from the same QML file "test.qml" :
1.In the main function (main.cpp)
2.and in the TEST_BUTTON function (test.h)
which are different QObject .
Another issues are that :
you are assigning an object of type TextInput to the objectName property (test.qml) which is a String
you are deleting (as Yekmen mentioned earlier) the object (textbox (test.h) = textbocks (test.qml)) which in the mean time you are assigning to it the string str="hello world" via setProperty() function .
Ahh forgot one, the slot name in C++ side which must be identical to the one declared in QML
I think you should look this method :
Connections {
target: area
onClicked: foo(parameters)
}
For example : area is your c++ object.( qmlRegisterType(myclass) )
area send a signal and after you can lauch your function.
I think is more easy.
Related
I would like to ask you a question, how to correctly block some url access. I would like to block access to URLs like "file:///" on QtWebEngine. I was searching something about WebUrlRequestInterceptor and QWebEngineUrlSchemeHandler but, did I find the right answer?
// main.qml
import QtQuick 2.0
import QtQuick.Window 2.0
import QtWebEngine 1.1
Window {
id: window
width: 800
height: 600
WebEngineView {
id: webView
anchors.fill: parent
url: "file:///"
}
}
// request.cpp
#include <QtCore/QRegExp>
#include "request.h"
WebUrlRequestInterceptor::WebUrlRequestInterceptor(QObject *p)
:QWebEngineUrlRequestInterceptor(p)
{
}
void WebUrlRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &info) {
if(!info.requestUrl().toString().contains(QRegExp("(?:https?|ftp)://\\S+")))
info.block(true);
}
// main.cpp
#include <QtGui/QGuiApplication>
#include <QtCore/QCoreApplication>
#include <QtQml/QQmlApplicationEngine>
#include <QtWebEngine/QQuickWebEngineProfile>
#include <QtWebEngine/QtWebEngine>
#include <QtQuick/QQuickWindow>
#include "request.h"
int main(int argc, char **argv) {
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
QGuiApplication app(argc, argv);
WebUrlRequestInterceptor *wuri = new WebUrlRequestInterceptor;
QQuickWebEngineProfile::defaultProfile()->setUrlRequestInterceptor(wuri);
QQmlApplicationEngine engine;
engine.load(QStringLiteral("./main.qml"));
QQuickWindow *window = qobject_cast<QQuickWindow*>(engine.rootObjects().first());
QRect rectangle;
rectangle.setWidth(800);
rectangle.setHeight(600);
window->setGeometry(rectangle);
window->show();
return app.exec();
}
Is it the right way, how I made it? I founded some flags here https://doc.qt.io/qt-5/qwebengineurlscheme.html#Flag-enum like QWebEngineUrlScheme::LocalAccessAllowed, but not sure, if this will help me. Isn't possible to control this list somehow https://admx.help/?Category=Chrome&Policy=Google.Policies.Chrome::URLBlocklist ?
Thank you
I am trying to create a qml object dynamically in c++ using the object of c++ class. Below is the minimal code for my approach. Upon execution of this code and after clicking, the application is crashing(see the comment in main.qml).
I have pasted the code below and It can be downloaded here.
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "scene.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
scene sc(engine);
QQmlContext* context = engine.rootContext();
context->setContextProperty("sc", &sc);
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
scene.h
#ifndef SCENE_H
#define SCENE_H
#include <QObject>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
class scene : public QObject
{
Q_OBJECT
public:
explicit scene(QQmlApplicationEngine& engine, QObject *parent = nullptr);
QQmlApplicationEngine& engine;
public slots:
void create_rect_object();
};
#endif // SCENE_H
scene.cpp
#include "scene.h"
scene::scene(QQmlApplicationEngine &engine, QObject *parent) : engine(this->engine),QObject(parent)
{
}
void scene::create_rect_object()
{
QQmlComponent component(&engine, QUrl::fromLocalFile("myrect.qml"));
QObject *object = component.create();
object->setProperty("width", 200);
object->setProperty("height", 150);
object->setProperty("color", "blue");
}
main.qml
import QtQuick 2.11
import QtQuick.Window 2.11
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle{
anchors.fill: parent
color: "red"
MouseArea{
anchors.fill: parent
onClicked: {
console.log("Before click");
sc.create_rect_object(); // application is crashing here
console.log("after click");
}
}
}
}
myrect.qml
import QtQuick 2.0
Rectangle {
id:id_rec
width: 100
height: 100
color: "green"
x:0
y:0
}
Update
The object to be created is not the child of the root of main window but child of one of the item inside the chain of children items of root of mainwindow. The pseudo structure looks like below.
main.qml
Window {
customitem1{
id:id_ci1
}
customitem2{
id:id_ci1
}
}
customitem1.qml
Item {
customitem3{
id:id_ci3
}
customitem3{
id:id_ci4
}
}
[UPDATED]
You have two errors for crashing and one for not showing rectangles
1.Your scene's Constructor member initializer list is falsy which causes the app crash
(TIP : use different naming for members of the class by prefixing them with m_ e.g: m_engine for READABILITY and not get confused)
//Correct WAY
class Something
{
private:
int m_value1;
double m_value2;
char m_value3;
public:
//################# YOUR CASE ###############################
Something(int number) : m_value1(number), m_value2(2.2), m_value3('c') // directly initialize our member variables
{
// No need for assignment here
}
//#############################################################
Something() : m_value1(1), m_value2(2.2), m_value3('c') // directly initialize our member variables
{
// No need for assignment here
}
void print()
{
std::cout << "Something(" << m_value1 << ", " << m_value2 << ", " << m_value3 << ")\n";
}
}
and it should be like this :
scene::scene(QQmlApplicationEngine &engine, QObject *parent) : engine(engine),QObject(parent)
instead of
scene::scene(QQmlApplicationEngine &engine, QObject *parent) : engine(this->engine),QObject(parent)
2.The url of myrect.qml which you get from local file that isn't found at runtime caused the app crash aslo and the one of remedies is to load it from your qrc file
QQmlComponent component(&engine, QUrl("qrc:/myrect.qml"));
3.And you'll notice after clicking you got no rectangles that's because the rectangles getting created doesn't have a parent and by changing your create_rect_object()(In this example the parent is the invisible root of our window contentItem) you'll get some rectangles :)
//A QQuickWindow always has a single invisible root item containing all of its content.
//To add items to this window, reparent the items to the contentItem or to an existing item in the scene.
//http://doc.qt.io/qt-5/qquickwindow.html#contentItem-prop
void scene::create_rect_object()
{
QQmlComponent component(&engine, QUrl("qrc:/myrect.qml"));
QObject *object = component.create();
QQuickItem *item = qobject_cast<QQuickItem*>(object);
// Set the parent of our created qml rect
item->setParentItem((QQuickItem*)((QQuickWindow *) engine.rootObjects()[0])->contentItem());
//Set some random position and color
item->setProperty("color", QColor::fromRgb(QRandomGenerator::global()->generate()));
item->setX(20+qFloor(QRandomGenerator::global()->generateDouble()*20));
item->setY(20+qFloor(QRandomGenerator::global()->generateDouble()*20));
}
Finding QML Objects from C++
For finding objects and using them as parentItem, you have to set the objectName of your qml object
Rectangle {
...
objectName : "rect_1"
...
}
and in C++
QObject* obj = dynamic_cast<QObject*>(engine.rootObjects()[0]).findChild("rect_1");
I have a bit of a strange error being caused by a seemingly simple problem.
In my source code I am attempting to use QQuickPaintedItem to render just the overall look of a QWidget derived class (QPushButton), and then painting it on to the QQuickPaintedItem
In doing so I ran into this error:
QQmlComponent: Created graphical object was not placed in the graphics
scene.
Followed by:
The program has unexpectedly finished.
Here's the context I am trying to create my special QQuickPaintedItem in along with the source code for it:
main.qml
import QtQuick 2.9
import com.particletool 1.0
import QtQuick.Particles 2.0
import QtQuick.Window 2.3
import QtQuick.Controls 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.4 as QQ1
Item {
id: root
width: Screen.width
height: Screen.height
WidgetInterface {
id: w
}
}
widgetInterface.h
#ifndef WIDGETINTERFACE_H
#define WIDGETINTERFACE_H
#include <QObject>
#include <QQuickItem>
#include <QQuickPaintedItem>
#include <QWidget>
#include <QPushButton>
#include <QtQuick>
class WidgetInterface : public QQuickPaintedItem
{
public:
WidgetInterface(QQuickItem *parent = nullptr, QWidget* renderWidget = nullptr);
QWidget* m_widget;
QPushButton* m_button;
protected:
void paint(QPainter* painter);
public slots:
void morphIntoButton(QString txt);
};
#endif // WIDGETINTERFACE_H
widgetinterface.cpp
#include "widgetinterface.h"
#include <QQuickPaintedItem>
#include <QObject>
#include <QPainter>
#include <QWidget>
#include <QPushButton>
WidgetInterface::WidgetInterface(QQuickItem *parent, QWidget* renderWidget) : QQuickPaintedItem(parent), m_widget(renderWidget)
{
morphIntoButton("test");
QQmlEngine::setObjectOwnership(m_button, QQmlEngine::JavaScriptOwnership);
}
void WidgetInterface::paint(QPainter *painter)
{
if (m_widget != nullptr) {
painter->end();
m_button->render(painter);
} else {
}
}
void WidgetInterface::morphIntoButton(QString txt)
{
m_widget->setGeometry(0,0, this->width(), this->height());
m_button = new QPushButton(m_widget);
m_button->setGeometry(m_widget->geometry());
m_button->setText(txt);
this->update(this->boundingRect().toRect());
}
main.cpp
#include <QtGui/QGuiApplication>
#include <QApplication>
#include <QtQml/QQmlApplicationEngine>
#include "src/interfaces/widgetinterface.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
qmlRegisterType<WidgetInterface>("com.particletool", 1, 0, "WidgetInterface");
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
The expected result is a button being drawn on to the QML scene graph
Does anyone know how I can achieve this using some method? ( I know that its not supported by Qt, but I am trying to implement a way to make it happen so dont both with the "You can't" answers because there is a way I'm sure.
The expected result is a button being drawn on to the QML scene graph
class WidgetInterface : public QQuickPaintedItem
{
public:
WidgetInterface(QQuickItem *parent = Q_NULLPTR) :
QQuickPaintedItem(parent)
{
mButton = new QPushButton("TEST", Q_NULLPTR);
auto resize = [=](){
mButton->setGeometry(QRect(QPoint(), boundingRect().size().toSize()));
QPixmap p(mButton->size());
mButton->render(&p);
if(!p.isNull())
mButtonPix = p;
update();
};
connect(this, &QQuickPaintedItem::widthChanged, this, resize, Qt::QueuedConnection);
connect(this, &QQuickPaintedItem::heightChanged, this, resize, Qt::QueuedConnection);
}
~WidgetInterface() {
mButton->deleteLater();
}
protected:
void paint(QPainter* painter){
painter->drawPixmap(0, 0, mButtonPix);
}
private:
QPushButton* mButton;
QPixmap mButtonPix;
};
I'm starting out with QT5.3, or rather QT in general.
Now I basically want to program C/C++ console applications and add a front-end.
I created a QT Quick Application and have trouble getting my back-end code to interact with the front-end.
What I have so far:
Main.qml :
import QtQuick 2.2
import QtQuick.Window 2.1
import QtQuick.Controls 1.2
Window {
visible: true
width: 360
height: 360
MouseArea {
anchors.fill: parent
onClicked: {
// Qt.quit();
}
}
Text {
text: w1.getRoll
anchors.centerIn: parent
}
Button {
onClicked: w1.roll
}
}
Main.cpp :
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "wuerfel.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
Wuerfel w1;
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
engine.setContextForObject(&w1,engine.rootContext());
return app.exec();
}
Wuerfel.h :
#ifndef WUERFEL_H
#define WUERFEL_H
#include <QObject>
#include <time.h>
#include <cstdlib>
class Wuerfel : public QObject
{
Q_OBJECT
Q_PROPERTY(QString w1 READ getRoll WRITE roll NOTIFY rolled)
public:
explicit Wuerfel(QObject *parent = 0);
void roll(){
srand((unsigned) time(NULL));
head = rand() % 6 + 1;
emit rolled();
}
int getRoll(){
return head;
}
signals:
void rolled();
public slots:
private:
int head;
};
#endif // WUERFEL_H
Debug Error
I have no clue what I have to do. The Documentation and web search results with similar issues confuse me even more. They mention QQView or QComponent etc. but whenever I try one of their solutions, something is missing. Like the method mentioned is not part of the object, so it's not found etc.
Has anyone a clue how to get this working? I want to use this approach to visualize future console applications from a C++ tutorial. And developing front-ends in QT in general.
Thanks in Advance. =)
You can use QQmlContext::setContextProperty to set a value for your name property on the root context :
engine.rootContext()->setContextProperty("w1", &w1);
I create a Sailfish app (using latest Sailfish SDK). I have a problem with exposing a C++ object to QML. It inherits QSettings,
class Settings : public QSettings
{
Q_OBJECT
/**/
public:
explicit Settings() : QSettings("Marcin Mielniczuk", "BigText") {}
~Settings() { qDebug() << "Dying"; }
/**/
};
I noticed that the destructor isn't called at all. (there's not destructor output)
I create the object like that:
import QtQuick 2.0
import Sailfish.Silica 1.0
import BigText 1.0
import "pages"
ApplicationWindow
{
initialPage: MainPage { }
Settings {id: settings}
}
My main.cpp is:
Q_DECL_EXPORT int main(int argc, char *argv[])
{
QScopedPointer<QGuiApplication> app(Sailfish::createApplication(argc, argv));
qmlRegisterType<Settings>("BigText", 1, 0, "Settings");
QScopedPointer<QQuickView> view(Sailfish::createView("main.qml"));
Sailfish::showView(view.data());
return app->exec();
}
What am I doing wrong?
/edit: Text not being printed isn't an actual problem - it's just an indicator of the problem. The QSettings sycing in the destructor doesn't work too.
EDIT2: Please note, that ApplicationWindow in I'm using Sailfish Silica, not QtQuick.Controls, and the window is shown ok. These components must be a somewhat different to the stock qt quick components.
There's nothing inherently wrong with your logic. Here is a simplified version of it. I can run it locally, and consistently get a Dying message on output every time the window is closed and the application terminates.
If you cannot figure it out, I suggest transforming this code into what you're doing until it fails.
By the way, this is surely just a snippet of something larger you're doing, but at least as far as the example goes, these scoped pointers aren't doing much.
main.qml
import QtQuick 2.0
import BigText 1.0
Item {
width: 300; height: 300
Settings {id: settings}
}
main.cpp
class Settings : public QSettings
{
Q_OBJECT
public:
Settings() : QSettings("Marcin Mielniczuk", "BigText") {}
~Settings() { qDebug() << "Dying"; }
};
int main(int argc, char *argv[])
{
QScopedPointer<QGuiApplication> app(new QGuiApplication(argc, argv));
qmlRegisterType<Settings>("BigText", 1, 0, "Settings");
QScopedPointer<QQuickView> view(new QQuickView());
view->setSource(QUrl::fromLocalFile("main.qml"));
view->show();
return app->exec();
}
You could try to put and id yo tour ApplicationWindow and explicity use the destroy() method at some time and see what happens.
You cannot use QQuickView with an ApplicationWindow class. Not only is your destructor not called, your constructor isn't either, because the loading doesn't ever succeed.
The code below works fine under Qt 5.1.1. Tested on both OS X 10.8 and Windows 7.
main.qrc
<RCC>
<qresource prefix="/">
<file>main.qml</file>
</qresource>
</RCC>
main.pro
QT += core gui qml quick
TARGET = qml-appwin-end-18597527
TEMPLATE = app
SOURCES += main.cpp
OTHER_FILES += main.qml
RESOURCES += main.qrc
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QSettings>
#include <QQuickWindow>
#include <QtQml>
#include <QDebug>
class Settings : public QSettings
{
Q_OBJECT
public:
Settings() : QSettings("Marcin Mielniczuk", "BigText") {}
~Settings() { qDebug() << "Dying"; }
};
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
qmlRegisterType<Settings>("BigText", 1, 0, "Settings");
engine.load(QUrl("qrc:/main.qml"));
QObject *topLevel = engine.rootObjects().value(0);
QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
window->show();
return app.exec();
}
#include "main.moc"
main.qml
import QtQuick 2.0
import QtQuick.Controls 1.0
import BigText 1.0
ApplicationWindow {
width: 300; height: 300
Settings {id: settings}
}
Nothing is wrong with my code. It's something with the SDK. Debugging shows
ASSERT: "QThread::currentThread() == QCoreApplication::instance()->thread()" in file debugger/qqmldebugserver.cpp, line 576
Then the program is aborted and therefore destructor not called.