动态使用 QGLWidget 或 QOpenGLWidget,具体取决于 Qt 版本

Dynamically use QGLWidget or QOpenGLWidget depending on Qt version

本文关键字:取决于 Qt 版本 QOpenGLWidget QGLWidget 动态      更新时间:2023-10-16

我的代码应该在Qt 5.4之前和之后的平台上编译和运行,其中引入了QOpenGLWidget,取代了QGLWidget。我想我可以编写这样的代码来支持两者:

#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
#  define USE_Q_OPEN_GL_WIDGET
#endif
#ifdef USE_Q_OPEN_GL_WIDGET
#  include <QOpenGLWidget>
#else
#  include <QGLWidget>
#endif
class GLWidget :
#ifdef USE_Q_OPEN_GL_WIDGET
    public QOpenGLWidget
#else
    public QGLWidget
#endif
{
    Q_OBJECT
public:
    [...]

但这不会成功,因为moc似乎不理解预处理器指令,并且会为错误的类生成代码。

我试图通过向我的CMakeLists.txt添加一个 add_custom_command 指令来解决此问题,该指令将在文件传递到 moc 之前${CMAKE_CXX_COMPILER}" -E -P -x c++-header ...上运行。但这似乎也不起作用,因为预处理器将删除魔术Q_OBJECT行,表明确实必须在运行 C 预处理器之前运行moc

我还有哪些其他选择?

我是否必须诉诸于两个几乎相同的头文件(两行除外),然后在 cmake 中构建时选择正确的一个?

编辑

若要测试此问题,请尝试以下操作:

  • 在 qt 5.2.1 附带的 Ubuntu 可信系统上(您可以使用 sudo debootstrap trusty ubuntu-trusty 创建 chroot) 执行以下操作:
  • apt-get install libqt5opengl5-dev build-essential qttools5-dev qt5-default
  • 然后创建包含以下内容的glwidget.h

    #ifndef GLWIDGET_H
    #define GLWIDGET_H
    #include <QtGlobal>
    #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
    #  define USE_Q_OPEN_GL_WIDGET
    #endif
    #ifdef USE_Q_OPEN_GL_WIDGET
    #  include <QOpenGLWidget>
    #else
    #  include <QGLWidget>
    #endif
    class GLWidget :
    #ifdef USE_Q_OPEN_GL_WIDGET
        public QOpenGLWidget
    #else
        public QGLWidget
    #endif
    {
        Q_OBJECT
    };
    #endif
    
  • 然后运行:

    $ moc -v
    moc 5.2.1
    $ moc glwidget.h | grep QGL || echo "not found"
    not found
    $ moc glwidget.h | grep QOpenGL >/dev/null && echo "found!"
    found!
    
  • 所以你会看到,即使Qt 5.2.1没有QOpenGL,moc也会以这种方式解释预处理器指令

  • 我们可以将版本检查更改为更简单的

    #if QT_VERSION >= 0x050400
    
  • 如果我们再次尝试该检查,那么 Ubuntu 中 Qt 5.2.1 中的 moc 信任会生成正确的结果

  • 因此,我们认为我们找到了解决方案,并尝试在同一代码上运行来自更新的Qt发行版的MOC。这次我在 Debian 不稳定中使用 qt 5.5.1 的 moc,我得到:

    $ moc -v
    moc 5.5.1
    $ moc glwidget.h | grep QOpen || echo "not found"
    not found
    $ moc foo.h | grep QGL > /dev/null && echo "found"
    found
    
  • 最有趣的是,如果在 qt 5.5.1 下我将版本检查宏 mack 转换为使用

    #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
    
  • 那么它确实有效!

因此,总而言之,moc 确实理解一些预处理器指令,但它理解的指令在 qt 5.4 之前和之后的版本之间是不同的。似乎不存在双方都能理解的通用预处理器指令。因此,我看不到使用预处理器指令解决此问题的方法。

可以使用 CMake 生成此标头。把这段代码放进去:

#include <@GL_CLASS@>
class GLWidget : @GL_CLASS@
{
    Q_OBJECT
public:
    [...]

然后在CMakeLists.txt中执行此操作:

set(GL_CLASS <depending on Qt version>)
include_directories(${CMAKE_CURRENT_BINARY_DIR}) #this is because configure_file produces its output in the build dir
configure_file(yourheader.h output.h @ONLY)

最后,在代码中使用#include "output.h"