【问题标题】:What's the counterpart of QX11EmbedWidget in Qt5?Qt5 中 QX11EmbedWidget 的对应物是什么?
【发布时间】:2016-08-05 21:54:12
【问题描述】:

在 Qt4 中,我们可以使用 QX11EmbedWidget 类的 embedInto 方法将任何 QWidget 嵌入到另一个应用程序中。但是在 Qt5 中,QX11EmbedWidget 类被删除了。我已经在 Google 上搜索了好几个小时,但我发现的所有内容都表明要使用 QWidget::createWindowContainer 方法。但是,据我了解,这种方法是QX11EmbedContainer 的替代品。

那么问题来了:我们如何将 Qt5-Widget 嵌入到非 Qt 窗口中? - 如果遇到问题:非 Qt 窗口是 Gtk3。


有人问我用例,所以让我简要说明一下:考虑一个基于 Gtk 的应用程序,您愿意扩展它 - 以及 UI 组件,它您需要,已经存在,但是是用 Qt 编写的。目标是避免将应用程序移植到 Qt 或将组件移植到 Gtk。

【问题讨论】:

    标签: c++ qt5 x11 gtk3 qx11embedcontainer


    【解决方案1】:

    我最初的方法是从 Qt 端请求嵌入。我对此并不走运,因为我在 Qt5 中找不到 QX11EmbedWidget::embedInto 的任何等价物。放弃这个之后,我决定试一试XReparentWindow,也就是reportedly used with success。但是,由于缺乏文档,我无法重现此内容。我的第三次尝试是从 server 端启动嵌入,在我的例子中是 Gtk 窗口。我很高兴地报告,它有效:-)


    记录:如何将任意 Qt5 Widget 嵌入到 Gtk 窗口中

    TL;DR:

    1. 确保将 Gtk 代码编写在与 Qt 部分分开的单元中。这是必要的,以避免 Qt5 和 Gtk3 之间的名称冲突。
    2. 只需使用gtk_socket_add_id 将任何X11 窗口嵌入GtkSocket

    另请参阅the documentation 以供参考,但请注意,给出的示例甚至无法编译,因为他们忘记了GTK_SOCKET 宏。相反,以下代码有效

    详情

    QGtkWindow 类提供到 Gtk 窗口的接口。

    class QGtkWindow : public QObject
    {
    
    public:
    
        QGtkWindow();
        virtual ~QGtkWindow();
    
        void setCentralWidget( QWidget* const widget );
        void show();
    
    private:
    
        GtkWindowAdapter gtkWindow;
        QWidget* const container;
    
    }; // QGtkWindow
    

    GtkWindowAdapter 类封装了 Gtk 调用并将它们与应用程序的 Qt 部分隔离开来。此类的一个对象代表 Gtk 窗口。

    class GtkWindowAdapter
    {
    
    public:
    
        GtkWindowAdapter();
        ~GtkWindowAdapter();
    
        void show();
        void embed( unsigned long clientWinId );
    
    private:
    
        struct Details;
        const std::auto_ptr< Details > pimpl;
    
    }; // GtkWindowAdapter
    

    实例化时,GtkWindowAdapter 对象首先初始化 Gtk,

    static bool gtkInitialized = false;
    
    struct GtkWindowAdapter::Details
    {
        GtkWidget* widget;
        GtkWidget* socket;
    
        void setupUi();
    };
    
    GtkWindowAdapter::GtkWindowAdapter()
        : pimpl( new Details() )
    {
        if( !gtkInitialized )
        {
            int argc = 0;
            gtk_init( &argc, NULL );
            gtkInitialized = true;
        }
        pimpl->setupUi();
    }
    

    然后设置Gtk窗口:

    void GtkWindowAdapter::Details::setupUi()
    {
        widget = gtk_window_new( GTK_WINDOW_TOPLEVEL );
        socket = gtk_socket_new();
        gtk_widget_show( socket );
        gtk_container_add( GTK_CONTAINER ( widget ), socket );
        gtk_widget_realize( socket );
    }
    

    您可能已经注意到该类提供的embed 方法。此方法启动任何 X11 窗口的嵌入。 show 方法使封装的 Gtk 窗口可见。

    void GtkWindowAdapter::embed( unsigned long clientWinId )
    {
        gtk_socket_add_id( GTK_SOCKET( pimpl->socket ), clientWinId );
    }
    
    void GtkWindowAdapter::show()
    {
        gtk_widget_show( pimpl->widget );
    }
    

    现在,QGtkWindow 类的实现相当简单。创建后,它使用GtkWindowApdater 初始化一个Gtk 窗口,并将一个空的QWidget 放入该窗口:

    QGtkWindow::QGtkWindow()
        : container( new QWidget() )
    {
        container->setLayout( new QVBoxLayout() );
        gtkWindow.embed( container->winId() );
        container->show();
    }
    

    QGtkWindow 类的用户决定将一些小部件放入窗口时,setCentralWidget 就是要走的路。它只是清除最初嵌入到 Gtk 窗口中的父小部件,然后插入用户的小部件:

    void QGtkWindow::setCentralWidget( QWidget* const widget )
    {
        qDeleteAll( pimpl->container->layout()->children() );
        pimpl->container->layout()->addWidget( widget );
    }
    
    void QGtkWindow::show()
    {
        pimpl->gtkWindow.show();
    }
    

    希望这可以节省一些时间。

    【讨论】:

      【解决方案2】:

      引用此链接:

      https://forum.qt.io/topic/32785/qwindow-qwidget-qt5-x11embedding-how/2

      所有 x11 的东西都移到了 贪婪。 (QX11EmbedWidgets 和 QX11EmbedContainer 之类的都是 不在 5.x 中)

      试试这个:

      http://qt-project.org/doc/qt-5.1/qtx11extras/qx11info.html

      【讨论】:

      • 谢谢,但我已经遇到了QX11Info 类,我真的不明白它与QX11EmbedWidget 有什么关系。事实上,我认为这个论坛的帖子具有误导性。
      • “它的关系”是:1)“所有 x11 的东西都移到了“附加”部门”,2)“x11extras”中唯一的东西......是 QX11Info!跨度>
      • 对,“x11extras”中唯一的内容是QX11Info,那么这告诉我们什么?显然,不是所有与 x11 相关的东西都被移到了“extras”包中。因此,论坛发帖错误
      • 不,论坛帖子说“你是 SOL...” ;) QT 5.x 及更高版本似乎不再支持这些 API。建议:也许你可以用类似 QWidget::createWindowContainer() 的东西来实现类似的功能?
      • 也许吧。这实际上是我过去 6 个小时一直在阅读的内容,但似乎没有人能够提供示例或体面的解释。问题是,我认为QWidget::createWindowContainer 取代了QX11EmbedContainer,而不是QX11EmbedWidget。您是否知道如何使用QWidget::createWindowContainerQWidget 嵌入到非Qt 窗口中?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-28
      • 2012-05-11
      • 1970-01-01
      相关资源
      最近更新 更多