I have a Configuration that holds some basic information about file locations like download, install, picture, music, document etc. location.
These are currently exposed to QML using Q_PROPERTY. They all have their own accessors:
Q_PROPERTY(QUrl download_location READ download_location WRITE set_download_location NOTIFY download_location_changed)
These accessors basically do all the same stuff and I'd like to get rid of all this redundant code I have to write.
My first idea is to have a little nested class FileLocation that provides get, set and validation functions. But then, how would I connect these to the Q_PROPERTY?
Also, if I had something like a static functions which took parameters, (e.g. check_validity( QUrl location )), how would I hand over this parameter from QML side?
I think I'm on the wrong path here, so my question is how to keep redundant code in the context of Q_PROPERTY within reasonable limits, avoiding to write loads and loads of get, set and changed functions for very similar objects?
Here's some more code:
class Configuration : public QObject
{
QObject
Q_PROPERTY(QUrl download_location READ download_location WRITE set_download_location NOTIFY download_location_changed)
Q_PROPERTY(QUrl music_location READ music_location WRITE set_music_location NOTIFY music_location_changed)
...
signals:
void download_location_changed();
void music_location_changed();
...
public slots:
void set_download_location(QUrl location)
{
download_location = location;
emit download_location_changed(download_location);
}
void set_music_location(QUrl location)
{
music_location = location;
emit music_location_changed(music_location);
}
...
private:
QUrl download_location,
music_location,
...;
}
So as you see there's a lot of recurring code that does the same, and I'd like to damp that down a little. How do I do that? I was thinking about some general functions set, get, changed etc. that get the member to work on was a parameter. But then I didn't know how to hand over which member to work on from qml.
I just found out about the possibility to expose C++ classes to qml via qmlRegisterType(...) - maybe this is the way to go here?
You could go for an evil macro:
#define IMPL(data, name) \
inline decltype(data) name() const { return data; } \
inline void set_##name(decltype(data) value) { if (value != data) { data = value; emit name##Changed();} }
Of course, if you don't need any extra stuff, you can simply use a MEMBER property and have Qt auto generate accessors for you.
This will however not work if you need to do custom things in the accessors, the macro will, just add your stuff to it.
Lastly, when you declare a Q_PROPERTY, you can right-click the property, go to refactoring, and select "generate missing members...", Qt will generate the default stubs for the accessors, and you will only have to add your custom stuff in. The downside to this is it has the nasty habit of putting the generated code in the silliest place possible, so if you want your class to look neat, you have to move it by hand.
qmlRegisterType() is when you want to register a type so it can be created in QML, you generally don't have to do anything to access a QObject derived object from QML - it works for QObject derivatives, you only need to register a metatype for types which do not have meta information generated.
Last but not least - I don't see any point in having your configuration as a C++ object, you can just as well do it in QML, and use Qt.labs.settings to make your settings persistent. C++ is optimal for performance critical parts only. If you do your configuration in QML, you don't need to worry about any of that boilerplate code, as it is all automatic in QML, no need to write accessors, no need to recompile your project on every tiny change.
Related
I have a couple of widgets in QtCreator that are promoted from the same class. However, I'd like them to have subtle differences between the two, so I'd like to pass some differences in the UI file that the promoted class can use to distinguish itself. Dynamic properties seem like the way to go so in the UI editor I've assigned a dynamic property to each promoted widget. In the code I tried accessing the property, but noticed it seems to only be available post construction (probably because Qt is calling setProperty() after the object is created.
MyWidget::MyWidget(QWidget* parent) : QGLWidget(parent)
{
this->property("someProperty").toString(); // returns blank
}
void MyWidget::initializeGL()
{
this->property("someProperty").toString(); // returns string set in UI file
}
So my question how do people use these properties for constructor-type stuff? I could just do that in initializeGL, but that seems odd since these properties might not be related to initializing OpenGL. I imagine I could also connect to the property changed signal and do it there. Is that the common way to handle this?
If the generated code for setupUi() from your .ui file does something like this:
MyWidget *w = new MyWidget;
w->setProperty(...);
then your constructor is accessing a meta property that does not yet exist.
You can reimplement QObject::event() to capture QDynamicPropertyChangeEvents, letting you act once the property is initialized.
bool MyWidget::event(QEvent *ev)
{
if (ev->type() == QEvent::DynamicPropertyChange) {
if (QDynamicPropertyChangeEvent *propEv = static_cast<QDynamicPropertyChangeEvent *>(ev)) {
if (propEv->propertyName() == "someProperty")
...
}
}
}
Bear in mind that this code will be called every time there is a dynamic property change.
A better approach may be to create a function to perform the necessary initilization on the widget after setupUi() etc. are called and the dynamic property is created.
void setupMyWidget(MyWidget *w)
{
QString s = w->property("someProperty").toString();
...
}
Typically, dynamic properties are assigned a default value in the constructor so that they are always available and non-null later.
setProperty("someProperty", defaultValue);
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.
Say I have two main classes, Application and ApplicationGUI. Application does lots of things and can happily run without any knowledge that ApplicationGUI exists. ApplicationGUI is linked to Application in many ways, it has maybe 50 or 100 different knobs that can change Application's behavior.
ApplicationGUI is a hierarchical structure such that it has many instances of ControlGroup, each containing an arbitrary number of Buttons and Knobs, or even another ControlGroup.
Current design: Upon instantiation of the ApplicationGUI (Application was already running with some set of default parameters), I pass pointers of Application's parameters to various components of the GUI. For example:
my_gui.sound_controlgroup.knob.link_to_param(&(my_application.volume));
If I need to do something more complex, say call a member function of Application, my_application.update_something(), how is this done?
The easy answer is to pass a pointer to my_application to my_gui.sound_controlgroup.knob, but if I only ever need to call one of my_application's functions, it seems like I am giving my knob an option to change all kinds of things that it should even know about (my_application.update_something_unrelated(), for instance). What is the cleanest thing to do in this case?
Additionally, this either requires making all subcomponents of ApplicationGUI public or having a function at each stage of the hierarchy to forward that pointer to the bottom level. This leads to quite a lot of functions. Is this a necessary consequence of a UI with a lot of knobs?
Quick Short Answer
In order to implement interaction between your non GUI related Application object and your GUIApplication object I suggest apply the "Property and Method and Event Handler" paradigm.
Extended Complex Answer
G.U.I. development is one of the most practical implementation of the O.O.P. theory.
What is the "Property and Method and Event Handler" paradigm ?
That means build, both Non GUI Classes, and GUI Classes, should have:
Properties
Methods
Event handlers
"Events" (Handlers) are also called "Signals", and are implemented with functions pointers. Not sure, but, I think your "knob" (s) are like Event Handlers.
It's a technique to apply the my_application.update_something_unrelated(), you have in your question.
Since, C++, like Java, does not have property syntax, you may use "getter" and "setter" methods, or use a "property" template.
For example, if your application has a Close method, you may declare something like the following examples.
Note: They are not full programs, just an idea:
// Applications.hpp
public class BaseApplicationClass
{
// ...
};
public class BaseApplicationClientClass
{
// ...
};
typedef
void (BaseApplicationClientClass::*CloseFunctor)
(BaseApplicationClass App);
public class ApplicationClass: public BaseApplicationClass
{
// ...
public:
Vector<BaseApplicationClientClass::CloseFunctor>
BeforeCloseEventHandlers;
Vector<BaseApplicationClientClass::CloseFunctor>
AfterCloseEventHandlers;
protected:
void ConfirmedClose();
public:
virtual void Close();
} Application;
// Applications.cpp
void ApplicationClass::ConfirmedClose()
{
// do close app. without releasing from memory yet.
} // void ApplicationClass::ConfirmedClose()
void ApplicationClass::Close()
{
// Execute all handlers in "BeforeCloseEventaHandlers"
this.ConfirmedClose();
// Execute all handlers in "AfterCloseEventaHandlers"
} // void ApplicationClass::Close()
// AppShells.cpp
public class AppShell: public BaseApplicationClientClass
{
// ...
};
void AppShell::CloseHandler(ApplicationClass App)
{
// close GUI
} // void AppShell.CloseHandler(ApplicationClass App)
void AppShell::setApp(ApplicationClass App)
{
App->BeforeCloseEventHandlers->add(&this.CloseHandler);
} // void AppShell.setApp(ApplicationClass App)
void main (...)
{
ApplicationClass* AppKernel = new ApplicationClass();
ApplicationGUIClass* AppShell = new ApplicationGUIClass();
AppShell.setApp(App);
// this executes "App->Run();"
AppShell->Run();
free AppShell();
free AppKernel();
}
UPDATE: Fixed type declaration from global function pointer (a.k.a. "global functor") to object function pointer (a.k.a. "method functor").
Cheers.
Do you know about the model-view-controller (MVC) paradigm? Think of the Application class as the model, the entire hierarchy of GUI controls as the view, and the ApplicationGUI class as the controller. You don't want Application to know about the controls, and you don't want the controls to know about Application; they should both talk only to the controller, ApplicationGUI.
Using ApplicationGUI as the conduit for communication between controls and Application means that you can test either Application or controls by replacing the other with a mock object, for example. More importantly, you can change either the controls or Application without impacting the other. Individual controls don't need to know anything about Application -- they only need to know where to send their value when it changes. And Application shouldn't care whether an input comes from a knob or a slider or a text field. Keeping those two areas separate will simplify each of them.
Additionally, this either requires making all subcomponents of
ApplicationGUI public or having a function at each stage of the
hierarchy to forward that pointer to the bottom level. This leads to
quite a lot of functions. Is this a necessary consequence of a UI with
a lot of knobs?
A given control shouldn't care what value it manages. It doesn't need to know whether the value determines the number of alien invaders on the screen or the coolant level in a nuclear reactor. It does needs to know things like the minimum and maximum values, label to display, scale to use (linear, log, etc.), and other things that directly impact the way the control works. It also needs to know who to tell when something changes, and it might need some way to identify itself.
With that in mind, ApplicationGUI doesn't need to expose accessors for every possible parameter of Application. Instead, it should have a general method that lets controls send it updates. When a control changes, it should send a message to ApplicationGUI containing the new value(s) along with its identifier, and ApplicationGUI takes care of mapping that identifier to some particular parameter of Application. A control's identifier could be some identifying number that's given to it, or it could just be a pointer to the control.
Of course, sometimes communication has to go the other way, too... a GUI usually has both inputs and outputs, so you'll want some means for ApplicationGUI to get updates from Application and update the state of the GUI. For the same reasons described above, Application should send those updates to ApplicationGUI and let the latter find the actual UI components that need to be changed.
I'm making a board game in Qt/C++ using qml. All the important game data is represented in a single class. My intention is to have the qml sheets access this one object and draw the game board depending on the data.
What is the simplest approach to exposing the C++ data members to QML?
Now I know the question has been asked, I've seen the answers and the Qt Documentation. I am, however, not satisfied. What I've seen, the way to do this seems to be to make Q_PROPERTY out of every single variable I want to access from QML. This looks to me tedious and unnecessary, not to mention it will stretch the code to 3x it's original length, making it significantly worse to read. Also, in most cases I won't need write function to the data members, for example.
And why bother with Q_PROPERTY overhead when I could just write Q_INVOKABLE getters for just the situations I need?
Here's an example of how simple I hoped it would be when I read in the Qt Project documentation: "This enables C++ data and functions to be accessible directly from QML, often with little or no modification."
class game : public QObject
{
Q_OBJECT
public:
explicit game(QObject *parent = 0);
colors NPC[3]; // colors being an enum declared elsewhere
player players[4]; // player is a non-QObject class containing player stats
}
...
game gMain;
QDeclarativeContext *context = viewer.rootContext();
context->setContextProperty("Game",&gMain);
QML in my ideal world:
Image {
id : Image1
source: { if (Game.NPC[0] === 0) {
if (Game.players[1].LifeCount > 0) {
return "pics/FigG.png"
}
else {
return "pics/StoneG.png"
}
}
Now how close to that can I actually get with QML and how do I go about it?
I'm especially interested in handling simple C++ style arrays and enums (have a lot of those in the game) - would I need to write helper functions, e.g. int Game.GetNPCAt(int i) instead of using just Game.NPC[i] ?
I realize that the way I DON'T want to do it is the tried and trusted, and for good reason... however in my situation (small one-man project) it seems like using a cannon to kill a fly (although the GUI building part in qml is amazingly simple and quite a joy to use) - also having to wrap around every data member including the simplest like an int seems... ridiculously excessive.
Maybe I have missed something somewhere, In which case I humbly apologize. Thank you for any thoughts on the matter.
In order:
Q_PROPERTY: When you look at the page that you quoted, they discuss using the Q_PROPERTY method to expose properties to QML. If you don't use Q_PROPERTY, it is my understanding that your variables won't be registered by QMLViewer (or what have you). The Q_PROPERTY needs a Q_INVOKABLE to get/set your variables. If you don't use Q_PROPERTY, though, your class properties will not appear in QML.
Setting the image source: If you may remember, QML is a forge between CSS and JavaScript. If you're just looking to make the image's source change depending on a condition outside of your Image element, you can just create a JavaScript function to achieve what you have quoted:
Image {
id: Image1
function getImage()
{
if (Game.NPC[0] === 0)
{
if (Game.players[1].LifeCount > 0) {
Image1.source="pics/FigG.png";
}
else {
Image1.source="pics/StoneG.png";
}
}
}
However, the function won't run by itself: you'll have to associate it with a signal, which I would create in your C++ class (put the function under a label named signals: (NOT within public -- see here on how to write signals)). Based on your example, I'm guessing that your C++ object is called Game.
Game {
id: gameKeeper //or whatever you want to name it
onUpdate: Image1.getImage() //replace onUpdate with your signal
}
Image {
id: Image1
function getImage()
{
if (gameKeeper.NPC[0] === 0)
{
if (gameKeeper.players[1].LifeCount > 0) {
Image1.source="pics/FigG.png";
}
else {
Image1.source="pics/StoneG.png";
}
}
}
In theory, you should be able to reference arrays this way with JavaScript (I'm not all that familiar with JS myself).
Array handling: On the C++ side, it looks like the best way to do it is through a QList. Fortunately, a QList iterates very similar to a normal array. I found this, which should help -- just ignore the second dimension.
Hope this helps.
I don't often have to create GUI's but today I do so I was hoping for some design input.
Basically I have a backend which I intend to add a GUI too using the MVC pattern. The issue is I feel whatever class encapsulates the main GUI window is going to have A LOT of state (all of the sub elements); and on top of that it's going to have a lot of setters, and possibly getter, clear, colour, size, position and refresh functions too.
One option is to march ahead with this idea and have a very large public interface which deals with the types the GUI uses (std::string, std::vector<std::string>...) the more control I want over the UI the more public member function I am going to need.
The other option would be to pass the program state to the GUI and have it decide how it display it, I fear doing this would mean it would give me less fine detail control and would break down the separation of concerns and would mean any changes to the representation of the program state would require changes in the GUI too.
Any input on the matter would be of great help.
If it makes any difference this is a C++ gui using an ncurses abstraction.
It sounds like to me you've thought alot about the M and the V, but not much about the C. The pattern should really be called MCV because the whole idea is that the controller IS the bridge between your model (data) and view (GUI). It sounds like you need a controller with most of the functionality you've mentioned.
Simply put though, your model obviously should know nothing about display and your display (view) should not know how to access the model. You need a controller that reads the data (model) and gives instructions to the display (view). If you have user interaction within the view, the controller can interpret that and modify the model as necessary.
The idea is that you never have to change all 3, but if you change the model or the view, you almost always have to update the controller.
Hope that helps...
There is at least one alternative to the giant interface. Instead of having a function that handles each thing (size, font, color, what-to-display, etc...) have a singular function that accepts a "role" and data that represents the role. This requires some sort of wrapper that can contain multiple data types.
QT's QAbstractItemModel Class Reference has a good example:
QVariant QAbstractItemModel::data ( const QModelIndex & index, int
role = Qt::DisplayRole ) const [pure virtual]
What that function will do is return the QVariant that represents the role indicated at the index provided.
The downside of this approach, is you have to know what roles exist, and what they do. QT's default roles are shown here.
I like to have parts of the model able to instrument themselves:
class Model {
private:
int value;
public:
void instrument(Instrumenter& instrumenter);
};
The Instrumenter manages the creation of controls. The model will tell it how it can be controlled and give it access to the data.
void Model::instrument(Instrumenter& instrumenter) {
instrumenter.addRangeController(0, 100, 5, value);
}
Then for different input devices (e.g keyboard, touchscreen) you can create appropriate controls:
class KeyboardInstrumenter : public Instrumenter {
public:
void addRangeController(int min, int max, int increments, int& controlled) {
// create 3 widgets, up arrow, down arrow, and value
}
};
class TouchscreenInstrumenter : public Instrumenter {
public:
void addRangeController(int min, int max, int increments, int& controlled) {
// create slider with min, max and increments
}
};
Instead of passing in the int directly we could have wrapped it in a controlling object, to aid encapsulation.