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

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.

Related

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).

Using QtScript outside my main form

I am using Qt5, and trying to learn on how to make an application scriptable.
For this I created a main window that contains some text edits, labels, etc. I then added an option called "script console" to that forms' menu in order for me to open a second form containing just a text edit and a button called "Evaluate".
What I was aiming at was being able to use that second form and through Qt script engine be able to set or get values from my main form, and generally be able to script various functions.
What I tried doing was set up the engine like this
scriptingconsole::scriptingconsole(QWidget *parent) :
QDialog(parent),
ui(new Ui::scriptingconsole)
{
ui->setupUi(this);
QScriptValue appContext = myScriptEngine.newQObject(parent);
myScriptEngine.globalObject().setProperty("app", appContext);
}
I don't get what I was expecting though.
If I try to evaluate the expression "app" I get null as an output.
This works fine if I use myScriptEngine.newQObject(parent) with an object inside the current class (if instead of parent I enter this), but I want to be able to access object in other classes too (hopefully all public slots that are used by my app in general).
Does anyone know what I am doing wrong here and how can I use my scripting console
class to access public slots from my main window?
What's wrong?
I guess it's because you didn't explicitly pass the pointer, which points to your main form, to the constructor of your scriptingconsole. That's why you got NULL as a result. (NULL is default, as you can see QWidget *parent = 0 in every QWidget constructor)
This happens if your object is not dynamically instantiated.
Solution
Dynamically allocate scriptingconsole in your main form:
scriptingconsole* myScriptConsole;
//...
myScriptConsole = new scriptingconsole(this);
// ^^^^
// pass the pointer which points to parent widget
The Qt documentation of QScriptEngine::newQObject says:
Creates a QtScript object that wraps the given QObject object, using the given ownership. The given options control various aspects of the interaction with the resulting script object.
http://qt-project.org/doc/qt-4.8/qscriptengine.html#newQObject
i.e. it wraps a QObject.. You are probably passing NULL to newQObject, for whatever reason. Try setting a breakpoint and evaluating the value of 'parent'.

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

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));

To create a new folder in Qml

I want to create a new folder in Qml…So I found out it via Qt…..so i want to integrate this below Qt C++ with Qml…..How is it possible…
QDir dir(“path/to/dir”);
if (!dir.exists())
{
dir.mkpath(”.”);
}
Or else,is there any options for creating new folder directly in Qml…Please suggest a solutions.Thanks in advance.
There's no way to create a directory directly from QML nor JavaScript. You will have to create an object in C++ and "export" it (make visible) to QML. Than you can call this object's method from your QML code and it will create the directory.
The basic idea of connecting C++ and QML is covered here:
Reading and writing files in QML
The only thing you'd have to change is to exchange write method for createDir (or whatever you want) and insert your code.
Another way to do it is to set contextProperty ex.
QQmlContext *context;
context = viewer.rootContext();
context->setContextProperty("DirManager", &dManager);
(where DirManager is your class) and use macro Q_INVOKABLE before the return type of your method.

Is it possible to enumerate the wxFrame children in wxWidgets?

I'm using the wxGlade designer to generate the GUI for a small application.
It generates a class, inherited from wxFrame, which is the main application window.
In order to facilitate the maintenance, I'd like to avoid writing additional code in this generated class.
But all the widgets created with the wxGlade are actually created in the auto-generated method do_layout() and it is not possible to access them outside the scope of that generated method in the generated class.
Is there a way to get pointer of certain widget outside that generated class - by name, by type, by enumerating the children or something like that?
All classes inherited from wxWindow (wxFrame being one of them) have a function "GetChildren", which returns a list of child windows that you can then enumerate over. If you are looking for a specific field by name then use the "FindWindow" function.
Actually I found the answer myself:
wxWindowList & children = myframe->GetChildren();
for ( wxWindowList::Node *node = children.GetFirst(); node; node = node->GetNext() )
{
wxWindow *current = (wxWindow *)node->GetData();
// .. do something with current
}
May I recommend you try wxFormBuilder. I also used wxGlade before, but it presents too much constraints on how you use it. For example, with wxFormBuilder you can select 'visibility' (public,protected,private) for each control on the form. It can also generate virtual functions for event handlers, so you just derive your class from wxFormBuilder generated class and implement those functions.