How do I cast QML items to corresponding C++ Item in Qt Quick - c++

My question is best clarified by an example. I have QML with a Text{} item. In C++ I can get to this item and I have no problem using qobject_cast to turn anything into a QQuickItem*. But how do I turn it into the closest corresponding item so that I can call more specific methods directly like setText() the same way I might call setWidth()? I realize I can use the generic setProperty() method but I'm after the compile time checking that casting offers.
I'm after a more general answer for finding the correspondence between QML and their C++ classes, so that I can find out how to do this for Rectangles, MenuBars etc. I can't seem to find this in the docs. For those that prefer code examples:
auto text_object = app_item->findChild<QObject*>("myTextArea");
text_object->setProperty("text","New Text set from Code"); //THIS WORKS BUT...
auto text_qitem = qobject_cast<QQuickItem*>(text_object);
text_qitem->setWidth(128);
auto text_quick_text = qobject_cast<WHATGOESHERE???*>(text_object);
text_quick_text->setText("new Text for qml item"); //I WANT TO DO THIS

Q: but I'm after the compile time checking that casting offers.
qobject_cast does not offer any compilation-time checking. It is all runtime and dynamic, thus this request is not plausible. The context property is fine, or you could also get the class name with QMetaObject. Then, you could build a static LUT, but the effort may not be worth it overall...

All QML properties and methods are exposed to the meta-object system and can be called from C++ using Object::setProperty and QMetaObject::invokeMethod() respectively. invokeMethod parameters and return values passed from QML are always translated into QVariant values in C++:
QString msg("That's it");
auto text_object = app_item->findChild<QObject*>("myTextArea");
if (text_object)
QMetaObject::invokeMethod(text_object, "append", Q_ARG(QString, msg));

Related

QDialog::setResult with custom return values

please note: qt/c++ newbie here
Purpose:
I have a QDialog from which I want to return a result. I am aware of the QDialog::exec() which combined with setResult, results in the use of Accept() or Reject(),
but as the documentation page reads, the developers suggest to sue the QDialog return codes, implying that different values can be used although I have had no luck with this.
enum ReturnResult{
success=0,
fail=1
error=2
warning=3
}
How may I use the QDialog::setResult() function to send custom enum values to (as seen above),
as a result, back to the parent class, if this is not possible, any suggestion as to how I may solve this problem?
You can call QDialog::done(int res) to close a dialog with the desired result code, which then will be the return value of QDialog::exec().
The documentation for result() states that
In general returns the modal dialog's result code, Accepted or Rejected.
If I understand correctly, that means that even if the current implementation allows passing custom values, you cannot be certain that it won't change and break your code in the future.
In your case, simply add another signal to it and connect to it, or add your own field to your dialog and use it to pass the data.

Sending a list of strings from QML to C++

I have ListModel which I manage in QML. After editing I want to send this model to C++ (as a QStringList for example, or something else I can work with in c++).
I know I can expose a list from C++ to qml and edit it from there, but for my app logic that does not really make sense. Can I somehow create a list like datatype in QML which I can send to c++ with a signal?
I think you can just send the QStringList to the C++ code and it ill be handled. See the docs linked below.
string QML Basic Type
When integrating with C++, note that any QString value passed into QML
from C++ is automatically converted into a string value, and
vice-versa.
Data Type Conversion Between QML and C++
Sequence Type to JavaScript Array
Certain C++ sequence types are supported transparently in QML as
JavaScript Array types.
In particular, QML currently supports:
QList<int>
QList<qreal>
QList<bool>
QList<QString> and QStringList
QList<QUrl>
If you for some reason QVariants to send data (as I do), you can convert it the following way:
// Test if the value is of the correct type (not nessary of one is sure that it is a list of strings)
if (val.canConvert<QStringList>() && val.convert(QVariant::StringList))
{
return val.toStringList();
}

Qt: Generate ui_ classes using uic, load dynamically by class name

Is it possible to load an .ui class generated by uic, dynamically by class name? I need to decide which UI class to load dynamically. I do not have that information at compile time. I do not want to use QUiLoader. Instead, I want to combine the direct approach here with QMetaType object instantiation by string.
I.e.
add the UI file to FORMS in project file,
declare the UI classes for QMetaType usage Q_DECLARE_METATYPE(Ui::planar_break) or Q_DECLARE_METATYPE(Ui_planar_break)
then form a string class name dynamically depending on user action: "Ui::planar_break" or "Ui_planar_break"
and invoke the below function to get the UI widget pointer for usage?
QWidget* initiateClassByName(QString name){
int id = QMetaType::type(name.toLatin1());
QWidget* widget=nullptr;
if (id != QMetaType::UnknownType) {
widget=static_cast< QWidget* > (QMetaType::create(id));
//QMetaType::destroy(id, myClassPtr);
//myClassPtr = 0;
}
return widget;
}
I am trying to increase the performance, compared to loading a dozen or so UI files (stored in Qt resource files) dynamically every time a specific dialog is instantiated. When I do this I seem to get a QMetaType::UnknownType every time. Ideas? Thanks.
(Hm, not sure why my function wasn't showing as code block here, until I made it a quotation.)
uic creates C++ code. If you really want to dynamically create a widget/dialog out of an xml file at runtime, you need to use the Qt Ui Tools. The class QUiLoader might be what you are looking for. If you do this, you can query the created QWidget through QWidget::findChild You can interact with the UI items through QObject::findChild(), provided you give your widgets distinct and meaningful object names.
Essentially, based on discussion had in #qt irc channel on Freenode I think what I am asking is actually not feasible.
My understanding is that even if I could get the C++ headers compiled and the classes registered using perhaps also qRegisterMetaType(), and perhaps even get them instantiated using QMetaType, to actually get the UI built I would have to call setupUi() on the instance.
Since UI files do not implement a common interface that includes setupUi, and I don't know compile-time which class I am instantiating, calling setupUi becomes impossible.

Arbitrary Inspection of Qt Stylesheet

I have several Qt stylesheets that look something like this:
MyClass
{
my_color: #abcdef;
}
However, I recently moved MyClass into a new namespace, ns, which means that its corresponding qss classname is now "ns--MyClass", not just "MyClass". As a result, all my stylesheets are now invalid. Unfortunately, they aren't all under my control, so I cannot edit them manually.
So my question is: how can I configure ns::MyClass to use all the same style settings of MyClass?
Obviously, Qt has to parse the style sheet at some point. So if I could access the parsed style sheet and extract just the portions that affect MyClass, I should be able to add those portions into ns::MyClass via setStyle() or setStyleSheet(). But I cannot find a way to do this.
I am targeting Qt 4.8.
You'll need to patch Qt to add two methods to QApplication:
void setClassSubstitutions(const QMap<QString, QString> &);
QMap<QString, QString> classSubstitutions() const;
The substitutions would be held in the application's PIMPL, and you'd need to have the stylesheet mechanism use them. The entirety of the patch needed for Qt would be probably two dozen lines (or so I hope).

Standard and "exotic" icons

I'm trying to use the standard icons in Qt for a QToolButton but I have a problem. My code is:
m_buttonZoomPlus->setIcon(QStyle::standardIcon(QStyle::SP_DesktopIcon));
I get the error message :
cannot call member function 'QIcon QStyle::standardIcon(QStyle::StandardPixmap, const QStyleOption*, const QWidget*) const' without object
What does it mean? Do I Have to create an empty QStyle object and call the standardIcon function on it?
Besides, I found a list of standard icons here: http://doc.trolltech.com/main-snapshot/qstyle.html#StandardPixmap-enum
Is this list exhaustive or are there other standard icons? I'm looking for instance for a zoom-in/out icon and I've not yet been able to find it.
Thank you very much for you help.
It means standardIcon is not a static method so you can't call it that way. You need to construct a QStyle and initialize it appropriately then you can use that method to get a specific icon.
Edit: Jeremy is right. If you aren't changing the style or defining your own style you can simply use the following:
QApplication::style()->standardIcon(QStyle::SP_DesktopIcon);
Reference: http://doc.qt.io/qt-5/qstyle.html#standardIcon