Qt QML draw in cpp subclass - c++

so I am trying to understand drawing in Qt, but I dont get this one:
So first of all I had a qml file where I embedded a custom class called Game which has this constructor: Game::Game(QQuickItem *parent) : QQuickItem(parent)
Writing setFlag(ItemHasContents, true); in the constructor code was sufficient to being able to draw with QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *); using QSGGeometry (This worked). Now I tried to draw in a subclass, using the same procedure but now it does not work anymore: So what I did was create a class called qcurver, and in Game I create an instance of qcurver. QCurver has the same constructor like Game and I pass the parent of Game so that technically it has the same parent as Game, but now when I try to draw in this class, nothing happens. Does anyone know, how I can pass the QML object for drawing, so that I actually see the drawing?

You're creating a Game object from QML code, so it's registered correctly in the QML scene. But the QCurver isn't created there, so it won't work.
Yes, it has the same parent, but it only means that if the parent gets deleted - the QCurver will be deleted too. Qt doesn't revise all QObjects that are added as children to find out if they are of type QQuickItem and should be rendered.
Also, QML itself was added to be able to avoid doing widget hierarchies in C++. So, compose hierarchies in QML. Or, if you want some of them in C++ for the performance reasons - then it is possible to do QSGNode hierarchies inside a QQuickItem (that's useful for rendering complex scenes with OpenGL).

Related

Opening Qt window from QML

I have created a C++ Qt class, inheriting from QWidget. I have also created a QML file, which runs as my main, and I want in some point of the program to open another separated window containing this widget.
The point is to draw line graphs in QML, and I don't quite understand how to do it.
First of all, take a look at this question and its answers: Qt5. Embed QWidget object in QML
You got into XY-problem. You do not need to embed QWidget to your QtQuick/QML application. (I hope) You can easily deal with your task using only QML. For example, there is Canvas Element that can help you to organize drawing. Take a look at tutorial related to Canvas in QmlBook.
Hope this helps!

Moving from QGLWidget to QWindow

I have some code using Qt 4. I want to migrate it to Qt 5 and switch to QOpenGL stuff. I can't understand where the code from void paintGL() and void initializeGL() needs to go in a QWindow. Can anyone help me with an example?
I have created a simple example of using QWindow with OpenGL.
To simplify OpenGL development I have created an abstract class GLWindow, which contains the virtual functions initializeGL(), paintGL() and resizeGL(int w, int h). I believe the source code shows the relationship between the old style and the new style.
The example is available here:
https://github.com/mortennobel/QtOpenGLChapter/tree/master/OpenGL3xAlt
Qt has at least one example (Overpainting) of putting widgets over an OpenGL scene. By looking at that, it appears the easiest way would be to inherit from QGLWidget instead of QWidget and override the appropriate virtual functions for initialize and paint.
The standard example for using QWindow with OpenGL is hellowindow in qtbase/examples/opengl.
There is no direct replacement for initializeGL and paintGL. Instead you do something like this:
Have a QWindow with surface type OpenGLSurface.
Create a QOpenGLContext with a matching format.
When the window receives an expose event, start rendering (makeCurrent, your GL calls and finally swapBuffers).

Hosting QOpenGL widget inside QML

I have a library proving me a QGLWidget, and the interface allow me to only to resize/set size, and control some GL animation; but no GL command is exposed outside, all i do it initialize GLWidget, and then pass the context to library and later call swap buffer to show animation..
I want to integrate this QGLWidget library into QML, is it possible to hove a QGLWidget inside QML ? if yes how ?
It's totally possible! You can write a QML plugin that will define a new QML element to encapsulate the library.
Then you will import this plugin from the QML document and you'll be good to use the new element and harness the features that the library offers.
Tip: if the application that loads your QML document was setup to have it's on QGLWidget, then you won't need to create a new QGLWidget inside your plugin. I did this mistake once.
This blog post shows how to create a simple/new QML element from scratch and how to use it in a QML document.
QGLWidget derives from the QWidget while QML widgets are implemented as QDeclarativeItem which derives from QGraphicsObject and these two are to different worlds.
Possible way of doing OpenGL drawings in a QML item is to declare a new QDeclarativeItem, expose it to the QML system and then override the draw method of this QDeclarativeItem subclass to do native painting(by calling the beginNativePainting and endNativePainting of the QPainter instance provided in the draw method).
Have a look at these two links:
http://doc.qt.nokia.com/4.7-snapshot/qml-extending.html
http://developer.qt.nokia.com/forums/viewthread/4109

Resizing a QGraphicsItem to take up all space in a QGraphicsView, problems when window is resized

I have a QGraphicsItem (actually, a QDeclarativeItem) and I want it to take up the entire visible space of the QGraphicsView (again, its actually the derived QDeclarativeView class) to which it was added. Normally, you can use QDeclarativeView::setResizeMode(QDeclarativeView::SizeRootObjectToView) and QDeclarativeView will automatically resize the root object to fit the view.
The problem I'm having is that I am manually creating the root widget using
QDeclarativeComponent component(declarativeView->engine(), QUrl(qml));
QDeclarativeItem* object = qobject_cast<QDeclarativeItem*>(component.create());
if (object)
{
declarativeView->scene()->addItem(object);
...
instead of letting QDeclarativeView do it automatically by calling setSource(). The reason I'm doing this is because I want to swap the QML scene when certain events occur, but I don't want to destroy the previous scene. Calling setSource() deletes all items that were added before setSource() is called. So, instead I'm creating the "root object" myself and adding it to the scene manually.
I am using the windows resizeEvent to resize my QDeclarativeItem, like this:
void AppWindow::resizeEvent (QResizeEvent* event)
{
QDeclarativeItem* object = sceneCache.value(sceneName, 0);
if (object)
{
object->setWidth(declarativeView->viewport()->width());
object->setHeight(declarativeView->viewport()->height());
}
}
This does work! But, its not very pretty. If you resize the window quickly, the QDeclarativeItem is not resized quickly enough and you briefly see a gray background before it catches up and resizes it. Its also not very smooth.
This only happens if I have a complex item being resized (in my case, its a QWebKit widget). It works fine for simpler items. The thing is, however, that if I let QDeclarativeView do it, I have neither of these problems: its resized correctly and smoothly.
I imagine this is not specific to the QtDeclarative stuff, but rather QGraphicsView, though maybe I'm wrong there.
Does anyone have any ideas?
I have solved my problems.
The problem seems to be with QML's WebView element. I switched it out for a QGraphicsProxyWidget registered from C++, with the widget set to a normal QWebView and all the problems disappear. It now behaves exactly how I expected the WebView to behave.
The downside is that I need to manually expose the QWebView signals/slots/properties to QML. (EDIT: I've solved this by having a read-only property called object, which returns the set widget. Since QObjects are automagically converted to javascript accessible objects, I can access the web view, for exmaple, like this: object.url = 'http://google.com'. For convenience, I also invoke an init javascript function ont he QML object, if it exists, so I simply set the web view up there - works great!)
Another change I made since I asked the question is to move the "root object" switching from C++ into QML itself, by creating a fullscreen Rectangle with a C++ -callable javascript function that uses Qt.createComponent() to load the "actual" QML file and anchor it with anchors.fill. This way the logic (and caching of objects) is done in QML, instead of C++, so I can simply setSource(), let Qt handle resizing and such and I work purely in QML (for this part of the app, anyway).
I am not sure if this will get rid of the flickering but you can use fitInView in your resizeEvent():
declarativeView->fitInView(object, Qt::IgnoreAspectRatio);

Seeking advice on using QGLWidget in Qt4

I'm new here, and have a question about opengl in Qt4, which I've been learning over the last few months.
Particularly, I'm seeking advice on the best way to compose a scene in a good object-oriented fashion using the QGLWidget. I'd ideally like every item in my scene to be sub-classes of a super 'Entity' class. Then in my main QGLWidget I can sort the entities and render them accordingly.
I noticed though that certain openGL functions (like bindTexture) need to be called from the QGLWidget (or the widget's QGLContext). At the moment I'm passing a pointer to the QGLWidget that controls my main viewport to each entity and storing it so that I can gain access to those functions. Is this a good idea?
Any advice would be gratefully received, or even directions to good websites/books that might be of help. I've got the Blanchette/ Summerfield book but the OpenGL section is quite short and most of the examples on the Qt website are pretty simplistic.
Thanks,
Dan
I agree with Vime: You're building a scene graph, and there are a number of classical approaches for designing its object hierarchy. Check out "3D Game Engine Design," by Dave Eberly, for details on one such engine, and look at OGRE for another example.
Since only one GL context can be active at a time on a particular thread, consider storing the QGLWidget pointer as a static class member to save effort:
class MyGLWidget : public QGLWidget {
// ...
public:
static inline MyGLWidget *GetActiveWidget() {
return ms_activeWidget;
}
protected:
static __declspec(thread) MyGLWidget *ms_activeWidget = 0; // uses MSVC extension
inline void SetActiveWidget() {
ms_activeWidget = this;
}
};
void MyGLWidget::paintGL() {
SetActiveWidget();
// ...
}
Then in your entity classes you can simply call MyGLWidget::GetActiveWidget() on the few occasions when you need to call QGLWidget member functions, and not need to copy a (probably invariant) pointer all over the place.
You are building something that is usually called "scene graph". In our engine scene graph objects need no access to QGLWidget. It's enough if you create your OpenGL objects inside void initializeGL() and render everything inside void paintGL().
There is a slightly higher level Qt/OpenGL example called Boxes. It can be found from qt/demos/boxes folder in Qt 4.6 installation.