Create and execute a function in a Qt application? [closed] - c++

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I am trying to develop a form that allows users to define variables and use conditions iterations. The form will then pass the texts to the application, where they will be translated and become part of the coding. It's like a template that allows a user to write relatively complex functions. It is more than a calculator because it allows for some programming within the structure. I am using Qt.
I was wondering if this is doable. If so what type of forms and the logic I should use.

It is possible to do it, but the complexity varies depending on where you are aiming at.
For QML it will be quite easy, because it is an interpreted language, it doesn't require compilation, so you can write some code in a text field and execute it.
For C++ it is not as easy, as it is a compiled language, you will have to bundle a compiler with the application, compile the code to a shared library, load it, get a pointer to the function and run it.
In both cases you will need to have a defined interface of the format of data input and linkage to already existing program objects. Based on the wording of your question, your skills may not be quite up to the task yet.
Here is a simple example how to do it in QML:
import QtQuick 2.7
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
Window {
id: main
visible: true
width: 500
height: 300
property int appData : 0
Column {
spacing: 5
Text {
text: "addData is " + appData
}
TextInput {
id: code
width: 500
height: 200
Rectangle {
anchors.fill: parent
border.color: "black"
border.width: 1
z: -1
}
}
Button {
text: "execute"
onClicked: {
var obj = Qt.createQmlObject('import QtQuick 2.0; QtObject { function foo(app) { ' + code.text + ' } }', main)
if (obj) {
obj.foo(main)
obj.destroy()
}
}
}
}
}
Then you can try out executing different statements, as long as they are valid, for example:
app.appData = 5;
app.appData--;
console.log(app.appData);
app.width = 300;

Related

How to make QFileSystemModel work with a ListView

I am unable to make the QFileSystemModel go along with the ListView. All the examples and documentation that I found would use QFileSystemModel with the TreeView (which works fine), but this is not what I need.
I do not want to use FolderListModel QML type either because I want to add extra roles to my model later and edit/delete files and folders from the application.
I used DelegateModel to be able to set an other root index. For some reason, my files are correctly displayed for a fraction of a second and then the view jumps to the root of my filesystem. I'm not sure what happens, maybe the indexes are invalidated somehow.
Below is a sample of my code:
main.cpp
QFileSystemModel *fsm = new QFileSystemModel(&engine);
fsm->setRootPath(QDir::homePath());
fsm->setResolveSymlinks(true);
engine.rootContext()->setContextProperty("displayFileSystemModel", fsm);
engine.rootContext()->setContextProperty("rootPathIndex", fsm->index(fsm->rootPath()));
fsview.qml
ListView {
width: 300
height: 400
model: DelegateModel {
model: displayFileSystemModel
rootIndex: rootPathIndex
delegate: Rectangle {
width: 200; height: 25
Text {
text: model.filePath
Component.onCompleted: {
console.log(text)
}
}
}
}
}
What am I doing wrong?
UPDATE
So, apparently QFileSystemModel uses a separate thread to populate itself and shoots a directoryLoaded signal once the the thread has finished to load the path.
I tried connecting my view to only set the root index once the path has been properly loaded by adding the following code to my listview
Connections {
target: displayFileSystemModel
function onDirectoryLoaded(path) { delegatemodel.rootIndex = rootPathIndex }
}
However, this does not solve the problem. A dirty workaround was to set a timer to try set the rootIndex after a period of time.
Timer {
interval: 100
running: true
onTriggered: delegatemodel.rootIndex = examPathIndex
}
And this "solves" the problem but of course is far from a satisfactory solution. Any idea?
UPDATE 2
Turns out every time the model is updated (and the directoryLoaded signal is triggered), the view resets. Even trying to reassign the rootIndex every time new data is loaded doesn't work.

QML TableView Model Silently Failing?

edit: added some clarification
Using QML 5.14
It seems the model attribute of TableView does not want to display a QList<int>, or any variation of int, be it qint8, qint32, etc. I can make it work with unsigned QList<uint>, however I need to keep the negative range of values in my application.
I've found that the information is making it to the qml layer, because when i call:
console.log("cfs.amounts is " + cfs.amounts)
console.log("model is " + model)
console.log("modellength is " + model.length)
I actually am getting the expected console output of:
qml: cfs.amounts is 11,12
qml: model is 11,12
qml: modellength is 2
I've ensured the TableView is functional by directly passing it data, i.e. model: [11, 22] and it displays correctly, i.e. it displays the indexes 0, 1. However I can't get it to display anything at all when I pass it the cfs.amounts, which is a QList<int> in c++. So according to the console.log, the model data is there, it is correct, it's getting passed from c++ to qml without issues, and the length is good -- the TableView is just failing to display it.
The only thing I can think of, is that the TableView is silently failing to display arrays of signed integers. However I may also be completely wrong, because I can't get a Repeater item to recognize it in its model, neither. I've searched but I can't find any bug reports on this subject. Does anyone have any suggestion on how to get the qml model to recognize the passed QList<int> ? This is all in QML 5.14.
cashflowschedule.h
#ifndef CASHFLOWSCHEDULE_H
#define CASHFLOWSCHEDULE_H
#include "QObject"
#include "QList"
class CashFlowSchedule : public QObject
{
Q_OBJECT
Q_PROPERTY(QList<int> amounts READ amounts)
public:
CashFlowSchedule() {};
QList<int> amounts() { return {11,12}; }
};
#endif // CASHFLOWSCHEDULE_H
main.qml
import QtQuick 2.14
import QtQuick.Window 2.14
import cpps 1.0
Window {
visible: true
width: 640
height: 480
CashFlowSchedule { id: cfs }
TableView {
anchors.fill: parent
model: cfs.amounts
delegate: Text { text: index }
Component.onCompleted: {
console.log("cfs.amounts is " + cfs.amounts)
console.log("model is " + model)
}
}
}
included in the main.cpp
#include "cashflowschedule.h"
...
qmlRegisterType<CashFlowSchedule>("cpps", 1, 0, "CashFlowSchedule");
...
QList<int> is not one of the official supported C++ types used for models (see the list here). A bug report exists to clarify the documentation on that point. A QVariantList is a good alternative to use.

Qt/QML: Text with inline QML elements

We are building a graphical user interface with QtQuick/QML. We have some dynamic, multi-line text coming from a database, which should be displayed in the application. Currently, we are using the Text element to display the text. However, we need some QML components inline embedded into the text. For this, the text coming from the database contains placeholders such as ::checkbox|1:: which should then be replaced and displayed by the program.
In HTML, this is easy, you can simply mix inline elements with text to produce a result like this:
but in QML, this seems to be more difficult, as Text elements cannot be word-wrapped into two halves if there is not enough space (both the text and the container size should be dynamic).
The best solution we could come up with, is creating a Flow layout with one Text element for each word, but this seems too hacky.
Using RichText with HTML is not enogh, since we really need our custom QML elements in the text.
Also, we want to avoid using a WebView due to performance reasons.
Is there a sophisticated way to implement this with QML/C++ only?
You can create custom widgets and embed them into QML:
Writing QML Extensions with C++
I haven't tried placing something in the middle, but I did try adding a tag to the beginning (and I might try adding a tag at the end).
QML's Text has a lineLaidOut signal that let's you indent the first line of text.
http://doc.qt.io/qt-5/qml-qtquick-text.html#lineLaidOut-signal
Here's what I did:
Text {
text: issue.summary
onLineLaidOut: {
if (line.number == 0) {
var indent = tagRect.width + tagRect.rightMargin
line.x += indent
line.width -= indent
}
}
Rectangle {
id: tagRect
implicitWidth: padding + tagText.implicitWidth + padding
implicitHeight: padding + tagText.implicitHeight + padding
color: "#400"
property int padding: 2
property int rightMargin: 8
radius: 3
Text {
id: tagText
anchors.centerIn: parent
text: issue.product
color: "#fff"
}
}
}

QML global access to C++ class

My app has 3 level:
- Main Form
- Settings
- Device searching
From the main form I open others using:
var component = Qt.createComponent("qrc:/touch/content/SettingsMain.qml");
win = component.createObject(rootWindow2);
In main form I created object Network (it is C++ class)
Network{
id: net1
}
Object "net1" is accesible by other QML objects which were not invoked by above code creating component. Unfortunately, all QML objects created by using the code above do not see "net1".I need something like global object for all QML files. Any ideas?
You should use a singleton for that, it exists for that exact purpose:
// in main.cpp
qmlRegisterSingletonType(QUrl(QStringLiteral("qrc:/touch/content/SettingsMain.qml")), "Core", 1, 0, "Settings");
Then you can access that from every QML file by importing:
import Core 1.0
//.. and use it
Settings.someProperty
Settings.someFoo()
You would also have to add a pragma Singleton line in the beginning of SettingsMain.
You can also skip registering the singleton from C++ if you implement a qmldir file, but IMO registering in C++ is better when the singleton is an integral part of the application.
When using qml singletons, you don't need to create the instance yourself, it will be automatically created.
Your question is ambigious as to what you actually want to be "global", I assume settings is one thing you would like to be global.
You can also register C++ objects as singletons in QML, for example:
qmlRegisterSingletonType<Network>("Core", 1, 0, "Network", someFooReturningValidNetworkPtr);
Singleton is not the only way. QML provides lots of ways to get same results.
Another way is to pass the net1 id in as a property when calling Qt.createObject(). Example below:
main.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
visible: true
width: 640
height: 480
Item {
id: rootWindow2
property Item settingsMain
Network{
id: net1
}
Component.onCompleted: {
var component = Qt.createComponent("qrc:/touch/content/SettingsMain.qml");
settingsMain = component.createObject(rootWindow2, {"net1": net1});
}
}
}
SettingsMain.qml
import QtQuick 2.0
Item {
property Item net1
Component.onCompleted: {
console.log("SettingsMain.qml: can I see net1? %1".arg(net1 ? "yes" : "no"))
}
}

BlackBerry 10 development- TextField

Guys I am developing the basic app in BlackBerry 10 and I want to get text which is in TextField (in cpp). I am trying to find method for that but not getting the right one .So can anyone please tell me how to get the value from TextField in cpp (not in qml) ???
Well, the first thing you need to do is expose your QML TextField to C++. This is done with an object name property ala:
TextField {
objectName: "myTextField"
...
}
Next, find this child from your C++:
QmlDocument *qml = QmlDocument::create("asset:///my.qml");
Container *root = qml->createRootObject<bb::cascades::Container>(); //or whatever the root control is
TextField *textField = root->findChild<TextField*>("myTextField");
From then on, simply use textField->text().
We have 3 parts in this problem
First on in Qml your text area and bottom when clicked send text area to function in c++
TextField {
id: n2
}
Button {
id: button
text: "send text"
onClicked: {
app.sendtext(n2.text)
}
Second part your c++ function in your ApplicationUI to receive this text
QString ApplicationUI::sendtext(QString txtarea)
{
QString text = txtarea;
return text;
}
Third and final part in your ApplicationUI.h u must make this function INVOKABLE to access it in Qml
so u will need this line
Q_INVOKABLE QString sendtext(QString txtarea);