I use Qt to create a 3D program with GLEW.
I have a problem when I call glewInit() from run-time creating Widget.
I create an inherited class , MyRender, based on QOpenGLWidget. Then, implemented initializeGL() with
GLenum err;
if( err = glewInit() )
{
printf( "error because: %s\n", glewGetErrorString( err ) );
exit(123);
}
Normally, I use class MyRender via Qt Designer and promote QOpenGLWidget to MyRender. Then I will have MyRender Object since the program starts. There is no problem.
However, when I create MyRender at Run-time. For example;
MyRender * myrender = new MyRender ( this );
The program will crash when calling glewInit()
Missing GL version // glewInit() problem
I found the people who have the same problem as me from this
However, in the post, people use either GLUT or SDL to create context. Since I use only GLEW how could I make the context from QOpenglWidget the same way as
glutInitDisplayMode(GLUT_RGB); //use GLUT
or
sf::Window App(sf::VideoMode(400, 400, 32), "Window"); //use SDL
or
glfwMakeContextCurrent // use glfw
Since I use none of them. I use only QOpenGLWidget and glew. I tried with
myrender->makeCurrent(); // fail
myrender->initializeGL(); // fail
before calling
glewInit()
however, the problem still persists.
About my machine: I use Windows 10 64-bit. Qt 5.11 GLEW 2.1.0
EDIT:
I test my code with
void initializeGL()
{
echo("inside initializeGL");
QOpenGLContext* current = this->context();
if( current == nullptr )
{
printf("current context is null\n");
exit(123);
}
else
{
printf("current context is good\n");
}
GLenum err = glewInit(); // error here
...
}
If I use Qt Designer to promote openGLWidget to MyRender . the context will be OK;
However, if I create MyRender in Run-time
MyRender* myrender = new MyRender( this );
The context will be null and leads glewInit() error.
I found that the problem is context is not created, and when the program call function initializeGL(). The solution that I did is I call show(); right after creating the widget.
myrender = new MyRender( ui->mdiArea );
myrender->show(); // this line make the context for QOpenGLWidget I think..
...
// note class MyRender is an inherited class from QOpenGLWidget
Related
I found an interesting article on how to impement QObject with dynamic properties (see C++ class DynamicObject). The code from the article works fine, the properties of DynamicObject are get and set successfully from both C++ and QML, but the only thing I cannot figure out is how to fire dynamic signals.
I tried to fire "nameChanged()" signal with the following code:
bool DynamicObject::emitDynamicSignal(char *signal, void **arguments)
{
QByteArray theSignal = QMetaObject::normalizedSignature(signal);
int signalId = metaObject()->indexOfSignal(theSignal);
if (signalId >= 0)
{
QMetaObject::activate(this, metaObject(), signalId, arguments);
return true;
}
return false;
}
myDynamicObject->emitDynamicSignal("nameChanged()", nullptr);
the index of the signal is found and signalId is assigned to 5, but the signal is not fired. But if I do, for example,
myDynamicObject->setProperty("name", "Botanik");
the property is changed and the signal is fired successfully.
What is wrong in my code? What should I pass as 'arguments' parameter of QMetaObject::activate ?
EDIT1:
The full source code is temporarily available here.
A signal is also a method. You can invoke it from the meta object.
So, replace your line QMetaObject::activate(...) by:
metaObject()->method(signalId).invoke(this);
And let Qt handles the call to activate().
There is also an issue in DynamicObject::qt_metacall(): you are handling only QMetaObject::ReadProperty and QMetaObject::WriteProperty calls.
You have to add QMetaObject::InvokeMetaMethod if you want to emit your signal.
I have a QGuiAppplication derived class (called Sy_application) that I've wrapped with another (called Sy_application_qml, with extra some QML specific features) and then registered that as a singleton with the QML engine.
This all works fine from the first opened top-level window, but the second (and presumably any more) only gets null from the singleton. Adding some debug:
// The static factory method used in the qmlRegisterSingletonType call.
QObject* Sy_application_qml::factory( QQmlEngine* engine,
QJSEngine* scriptEngine )
{
Q_UNUSED( engine )
Q_UNUSED( scriptEngine )
qDebug() << "Creating";
return new Sy_application_qml();
}
// SY_APP is the qApp macro casted to my Sy_application type.
QObject* Sy_application_qml::get()
{
qDebug() << "Getting:" << SY_APP;
return SY_APP;
}
// This is an example of it's use within QML
onPositiveClicked: {
console.log( Sy_application_qml );
Sy_application_qml.get().newProject( sampleRate.value, frameRate.value );
close();
}
And the debug output:
// Opening first window.
Creating
// Creating second
qml: Sy_application_qml(0x1895b30)
Getting: Sy_application(0x7fff80f051c0)
// Attempting to create third
qml: Sy_application_qml(0x1895b30)
Getting: Sy_application(0x7fff80f051c0)
qrc:/qml/gui/dialogs/Sy_newProjectDialog.qml:62: TypeError: Cannot call method 'newProject' of null
As you can see the singleton is still present and the C++ Sy_application instance is being returned correctly, but is appearing as null on the QML side. Any reason why it works for one window and not another?
So I finally worked it out, and it had nothing to do with QML singletons or having multiple top-level windows - but it had everything to do with passing QObject pointers to the QML engine from Q_INVOKABLE methods (the Sy_application_qml::get() method in my case).
From the docs:
Objects not-created by QML have CppOwnership by default. The exception
to this is objects returned from C++ method calls; in these cases, the
ownership of the returned objects will be set to JavaScriptOwnerShip.
Note this applies only to explicit invocations of Q_INVOKABLE methods
or slots, and not to property getter invocations.
So the QML engine had deleted my Sy_application pointer. The solution was nice and simple:
QObject* Sy_application_qml::factory( QQmlEngine* engine,
QJSEngine* scriptEngine )
{
Q_UNUSED( engine )
Q_UNUSED( scriptEngine )
QQmlEngine::setObjectOwnership( SY_APP, QQmlEngine::CppOwnership );
return new Sy_application_qml();
}
In our target device, we run our QtE app with -qws argument. To rotate the screen, we specify "-display transformed:rot90" as the app argument and it works well.
However, we have a feature to rotate screen inside the app, so we try below API documented in QScreen:
QWSDisplay::setTransformation(QTransformedScreen::Rot90, 0);
But this API doesn't work at all. It's no error message in the console output.
Does anyone know what's going on about this API? Do we need to enable something else?
Contrary to other qt documentation, documentation for the embedded part of qt is indeed poor. After few days of fiddling with it, I finally managed to solve it.
First thing to do is to compile the library with -qt-gfx-transformed option (along with whatever you need).
Then you compile your application, and start it with the option you already used to activate the transformation driver. I actually started like this :
export QWS_DISPLAY=Transformed:Rot90:0
./app
As a test, I implemented this, to test whether the rotation works :
class X : public QObject
{
Q_OBJECT
public :
X() :
QObject()
{
QTimer *t = new QTimer( this );
connect( t, SIGNAL(timeout()), this, SLOT(OnTimerEvent()));
t->start( 2500 );
}
public slots :
inline void OnTimerEvent()
{
static int v = 0;
++v;
QWSDisplay::setTransformation(v%4);
std::cout<<v<<std::endl;
}
};
So, in the timer slot, I am changing the orientation with QWSDisplay::setTransformation function.
In our target device, we run our QtE app with -qws argument. To rotate the screen, we specify "-display transformed:rot90" as the app argument and it works well.
However, we have a feature to rotate screen inside the app, so we try below API documented in QScreen:
QWSDisplay::setTransformation(QTransformedScreen::Rot90, 0);
But this API doesn't work at all. It's no error message in the console output.
Does anyone know what's going on about this API? Do we need to enable something else?
Contrary to other qt documentation, documentation for the embedded part of qt is indeed poor. After few days of fiddling with it, I finally managed to solve it.
First thing to do is to compile the library with -qt-gfx-transformed option (along with whatever you need).
Then you compile your application, and start it with the option you already used to activate the transformation driver. I actually started like this :
export QWS_DISPLAY=Transformed:Rot90:0
./app
As a test, I implemented this, to test whether the rotation works :
class X : public QObject
{
Q_OBJECT
public :
X() :
QObject()
{
QTimer *t = new QTimer( this );
connect( t, SIGNAL(timeout()), this, SLOT(OnTimerEvent()));
t->start( 2500 );
}
public slots :
inline void OnTimerEvent()
{
static int v = 0;
++v;
QWSDisplay::setTransformation(v%4);
std::cout<<v<<std::endl;
}
};
So, in the timer slot, I am changing the orientation with QWSDisplay::setTransformation function.
I took the example of the Poppler Library to render PDF on Qt platform. I am trying to write gesture handling for the example.
The example can be downloaded from "doc.qt.digia.com/qq/qq27-poppler.zip" URL.
In a nutshell, the example has a DocumentWidget.cpp which is Derived from "QLabel" which in turn derives from QFrame and QWidget.
Now since QLabel is inherited from QWidget I have started implementing for Gesture Handling.
in DocumentWidget.h i have added the below function
protected:
bool event( QEvent* e );
in DocumentWidget.cpp constructor
grabGesture( Qt::TapGesture )
bool DocumentWidget :: event( QEvent* e )
{
if( e->type() == ( Qt :: TapGesture )
gestureEvent();
}
In the above gestureEvent function I try to check if it is Tap and correspondingly planning to handle the tap event. However, In my example the event function is getting called but the tap gesture is being handled.
I have included all the necessary header files. I have forward declared the classes too.
Can you please tell me where am I going wrong. Can't we handle these gestures for QLabel.
Thank You in advance.
Chand.M
You are already checking for TagGesture in the event handler. So you need not check it once again in the gestureEvent() function. Moreover after consuming the event you have to return true; stating that the even has been consumed.
If the even is not a TapGesture then pass it to the QWidget itself like this.
if( e->type() == ( Qt :: TapGesture )
gestureEvent();
else
return QWidget::event(e);
You can find documentation on even handling here.