Qt use of Class and CLassPrivate - qt

When examining classes written by Qt, I discover many contain a class called "Class", and another called "ClassPrivate". For example QFile contains QFile and QFilePrivate, QIODevice contains QIODevice and QIODevicePrivate.
What is the purpose of this design?

This is a common design pattern called private implementation, or pimpl for short. Qt actually calls it d/q pointer, but it is the same thing.
The Q_D and Q_Q macros are part of a design pattern called the d-pointer (also called the opaque pointer) where the implementation details of a library may be hidden from its users and changes to the implementation can be made to a library without breaking binary compatibility.
The main reason for this in binary compatibility. Qt, unlike many other projects like boost, has had the guarantee of API (source) and ABI (binary) compatibility for the same major version.
So, the API and ABI would not break e.g. inside the Qt 5.x series. They would have to change the major version to break any of this.
Now, the private implementation really helps with this as the implementation details are no longer in the publicly available header file.
They can add further private members (method or variable) in the private implementation while the public interface would still online contain a private implementation pointer.
This makes the public interface completely opaque allowing flexibility in changing the implementation details without having to worry about the public interface.
Here is an example they give:
class Widget
{
// ...
private:
Rect m_geometry;
String m_stylesheet; // NEW in WidgetLib 1.1
};
class Label : public Widget
{
public:
// ...
String text() const
{
return m_text;
}
private:
String m_text;
};
This would break the client code using Widget causing a crash. However, if you hide the implementation details of the Widget class behind a private pointer, you can do anything with it since it is hidden. So, in the above example, you can add "m_stylesheet" without any risks and the client code using Label will not crash.
In case you wonder why binary compatibility is such a big deal: Qt has been a popular framework used by many applications, some really big. It would be a major pain in the neck to upgrade the Qt dependency for them if it did not offer binary compatibility.
When designing libraries like Qt, it is desirable that applications that dynamically link to Qt continue to run without recompiling even after the Qt library is upgraded/replaced with another version. For example, if your application CuteApp was based on Qt 4.5, you should be able to upgrade the Qt libraries (on Windows shipped with the application, on Linux often comes from package manager automatically!) from version 4.5 to Qt 4.6 and your CuteApp that was built with Qt 4.5 should still be able to run.
Basically, when you upgrade Qt in this way for your application, you can just drop in the new version without even having to recompile your application. And the features of your application will just keep working as before. This is great because you do not need to send a new version of your application to the customers. They can just upgrade Qt on their side and benefit from performance improvements in Qt or bug fixes indeed, etc.
And as a matter of convention, these private implementation are written in Qt inside files with the _p.h suffix.
You can also refer to this page for further binary compatibility examples.

In Qt 4.8, we see this structure please look at this doc
But in Qt6 we don't have QFilePrivate or ClassPrivate classes. look at this
If you see in Qt 4.8 Structure of classes has one QObjectData and one QObject
for more detail, you can compare this source which was for Qt 4.8 and now the new version of QObject class.
QFile inherits QObject and QFilePrivate inherits QObjectData
What is the purpose of this design?
I guess they want to provide very strong encapsulationYou cannot access the d pointer as a user of the API, which is the whole point of encapsulation.
d_ptr is a pointer in QObject class in Qt 4.8
Look at D-Pointer document.
The trick is to keep the size of all public classes of a library
constant by only storing a single pointer. This pointer points to a
private/internal data structure that contains all the data. The size
of this internal structure can shrink or grow without having any
side-effect on the application because the pointer is accessed only in
the library code and from the application's point of view the size of
the object never changes - it's always the size of the pointer. This
pointer is called the d-pointer.
The spirit of this pattern is outlined in the code below (all code in
this article doesn't have destructors, of course you should add them
in real code).

Related

Livereload after save but keep some objects

Livereload for development purposes: after save the application should reload the GUI entirely.
But there are some C++ objects (used in QML code) that should stay and find themselves in the new version of the GUI.
Possible approach is to add to such object a string property that will be the same in the newely-loaded QML code, so it'll attach to that. Obviously, the object has two parts: the QObject and Qt-independent implementation.
There is a problem with that: the other bindings need such object to be already attached. These signals/properties mustn't arrive earlier.
I'm thinking about setting that 'persist' property in the Component.onCompleted, so it'll be like atomic with the C++ constructor. Will it work? Other suggestions? How do you do it?

QT for OpenglEs on Desktop

I have an existing project which uses openglEs library (libGLESv2.lib) on DESKTOP platform.
Now I want to use QT as its user interface by using QGLwidget. However after calling any OpenGL function in QGLwidget::initializeGL function I get Access violation executing location 0x00000000 error at the code below,
void MyGLWidget::initializeGL()
{
if (!context()->create())
throw std::exception("no context :)");
context()->makeCurrent();
glViewport(0, 0, 640, 480);
}
If I also include the library opengl32.lib then glviewport function works but when I hit to glGenFramebuffers then I get the same error.
Could you please let me know how can I configure my project to use QT with opengles on desktop platform.
If I also include the library opengl32.lib then glviewport function works but when I hit to glGenFramebuffers then I get the same error.
glViewport is a OpenGL function found in every OpenGL version and profile since version 1. As such it's immediately available simply by linking against the basic OpenGL interface library.
glGenFramebuffers is a function introduced only with OpenGL-3 (OpenGL-ES 2, BTW, OpenGL-ES is not natively supported on Windows) and before you can use it, you have to
check that it is actually supported
load the OpenGL context dependent function pointer at runtime into the variable symbol you're actually calling
Failing to do the second step will give you the error you encounter. Failing to do the first step you try to load it, but loading may fail leading to the same result as if you didn't do (2) at all.
Qt provides all the function loading checks and executions for you, so I suggest you use it: http://doc.qt.io/qt-4.8/qglfunctions.html
It's not perfect, but it gets the job done.
Update (from comments)
Most likely you already have some OpenGL loader library in your project, that actually resolves everything, but before using Qt you did properly initialize it. Now using Qt you've got a mix of statically resolved symbols through opengl32.lib and symbols provided by that loader, yet the loader is not initialized. Look through the code as it was before integrating Qt and look for some initializing call (called after creating the OpenGL context/window but before doing any OpenGL work).
My best guest would be, that the EGL bindings you use also implement the OpenGL-ES wrapper/loader. As I already explained, Windows doesn't natively support OpenGL-ES (only regular OpenGL) and some kind of compatibility layer is required. It is most likely this layer that's getting in your way now. The good news is, that since you're on Windows you can use regular native OpenGL-3 instead; for the most part OpenGL-ES is a subset of OpenGL-3. You'll still need to runtime load GL-3 functions, but as already said, Qt can do that for you.
What to do:
Replace all occurrences of #include <EGL/egl.h> with #include <GL/gl.h> – that should get rid of the symbol shadowing.
Next, for all classes in which use of OpenGL functions is made, add an inheritance of QGLFunctions so that in the classes' namespaces the dynamically loaded functions are used.
Note that every class that inherits QGLFunctions must be instanced only when the target OpenGL context is made current OR you call initializeFunctions on the instances from QGLWidget::initializeGL (or its derivatives). you have to do the function initialization once for each instance of the class inheriting QGLFunctions and the initialization function must be called when the OpenGL context that's to be used is currently active. Like I said, Qt's QGLFunctions is not perfect; if it were it would do the necessary function pointer loading on demand, cache the result and in case of a OpenGL context switch automatically reinitialize.

How can I write a shared library with Qt that wraps another library?

I'm trying to create a Qt shared library that wraps a lower level C library, meaning that I don't want that C library's header file to be accessed by the calling code that links to the library.
I'm following the steps here, which seem to be straightforward. I've constructed a SUBDIRS project in QtCreator. The library project builds fine, all classes and C functions are marked with the macro that expands to Q_DECL_EXPORT. The library defines a some headers that I want to include in the app project. The problem here is that when I include one of those headers, the chain is followed down to the C library header that is included, and at which point the application project fails to build since it can't find that header.
Qt's documentation specifically points out this issue, but is kind of vague about how to solve it.
#include <footronics/device.h>
class MyDevice {
private:
FOOTRONICS_DEVICE_HANDLE handle;
};
When deploying the library, there should be no dependency to the internal headers footronics/device.h or ui_widget.h.
So, how can I avoid the headers that I'm including from the library, from implicitly including the headers from the C library that I'm wrapping?
If you only use pointers or references to classes of the shared library you can use Forward Declarations:
class FooTronicsDevice;
class MyDevice {
private:
FooTronicsDevice* _device;
}
The compiler doesn't need to know the structure of the class in order to define a pointer (or a reference).
If this isn't possible, you can use the Pointer to Implementation idiom which is suggested in the Qt Documentation.
This basically means you separate the implementation from your public interface.

Why is Qt QColor a part of QtGUI - possible workarounds?

I'm building a commandline version of an an application that utilizes QColor for cross-platform handling of color data.
For some reason, this datatype is a part of QtGUI even thou it doesn't have anything to do with Widgets - any way to get this class without linking with GUI?
Probably because it includes all the hooks into the QPainter class to draw colors.
Yes in a perfect design it would be possible to abstract all that away, but Qt is mostly a gui library and time is money.
But since it's open source you can just copy the Qcolor .h/.cpp and modif them yourself. If you only need the color space conversion routines you can probably just use the.h
Note: Qt is LGPL so the source to any modifications to the Qt code (but not your own app) must be offered to any users of your app.

Spark lifecycle changes between Flex 4.5 and 4.6

I have recently migrated some of my projects to the shiny new Flex 4.6 SDK. I wasn't expecting much trouble since it was only a minor release. But as a matter of fact I got hundreds of errors all over the place. These errors would mostly come from Spark SkinnableComponents; for example:
override protected function getCurrentSkinState():String {
return mySkinPart.someProperty ? "normal" : "someOtherState";
}
would work just fine under 4.5, but would throw me a nullpointer error in 4.6. The reason is simple enough: in 4.6 getCurrentSkinState() is called before the skinparts are created, whereas in 4.5 I could be certain that the skinparts in the default state would be there.
Further investigation led me to believe that the initial state of a Skin is now undefined instead of the first state in the States array (until it calls getCurrentSkinState() that is).
Fixing these problems is usually pretty easy and requires just somewhat more defensive programming from my part. But that's not my real issue.
The real issue is that if the component lifecycle has changed, I'd like to know exactly what has changed and what parts of my projects might be affected.
I would be very appreciative if someone could shed some light on this or at least point me to the right place where I can read all about it (because the only release notes I could find were only covering the new mobile components).
Edit (this doesn't change the question; I just wanted to share my findings with you)
Another issue I just ran into: the dynamic modifier seems to no longer be inherited by subclasses. This is a pure ActionScript issue, so I guess it's the compiler that treats it differently.
Let me explain. Consider this class:
public class MyClass extends Array { }
Now, if I try to push a new item into this custom Array like this:
var t:Array = new MyClass();
t.push("hello");
SDK 4.5.1: no problem
SDK 4.6: "Cannot create property 0 on MyClass" at runtime
Apparently that's because Array is dynamic and MyClass isn't, so it's easily fixed:
public dynamic class MyClass extends Array { }
and the error's gone.
But what if I used a third-party library that has code like this and to which I had no source code access? My application would break and there's no way I could fix it. I mean: come on, that's no minor change for a dot-release.
I think there are two questions in there.
1 ) The real issue is that if the component lifecycle has changed, I'd
like to know exactly what has changed and what parts of my projects
might be affected.
I haven't seen a comprehensive low-level analysis of the differences between the two version. If you are really concerned, and you have the time to spare, you could use a diff tool to compare the source code for the two SDK's. There shouldn't be too many major structural changes - e.g. renamed classes or packages, so it might not be so bad. I expect a lot of classes won't have changed at all.
2 ) Another issue I just ran into: the dynamic modifier seems to no longer
be inherited by subclasses. This is a pure ActionScript issue, so I
guess it's the compiler that treats it differently.
This one is easier. dynamic has never been inherited. Object is dynamic, so if the attribute was inherited every class would have to be dynamic too.
If there appears to be a change in behaviour related to dynamic class instances, then there is something else going on in your code.

Resources