Hi, welcome to devnet.
A better and more portable design would be if an engine did not run its own loop. The most popular way to do that is to provide a kind of Initialize(), Frame() and Shutdown() interface that you could call from a loop provided by whatever windowing framework (most of them usually have that). The Frame() part would measure the time elapsed from last frame and advance the states proportionally to that.
If you don't want to go that path (just make sure you really don't) you could also run the two loops in parallel, starting your engine's loop in a worker thread. This leads to some synchronization issues, but with some work could be manageable.
Again - it's better if the engine does not provide it's own OpenGL bindings but uses the ones provided by the windowing framework (e.g. QOpenGLFunctions in case of Qt). There should be no problem in using GLEW along with Qt, just make sure you do your GLEW/OpenGL calls with a current GL context provided by Qt.
QGLWidget is replaced now with a more modern QOpenGLWidget. If all you need is a window and input management (like with GLFW) then consider using QWindow with an OpenGL surface format instead. You will get better performance and drop the requirement of QtWidgets module.
As for triggering the update - there's an update() method for that. You can call it how often you need and it will schedule OpenGL painting. The usual way to tackle this is either using a timer or calling update() at the end of the painting method to schedule updates "as often as possible" i.e. as often as v-sync allows.