3

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

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


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

4

2 回答 2

3

我最初的方法是从 Qt 端请求嵌入。QX11EmbedWidget::embedInto我没有运气,因为我在 Qt5 中找不到任何等价物。放弃后,我决定XReparentWindow试一试,据说使用成功。但是,由于缺乏文档,我无法重现此内容。我的第三次尝试是从服务器端启动嵌入,在我的例子中是 Gtk 窗口。我很高兴地报告,它有效:-)


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

TL;博士:

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

另请参阅文档以供参考,但请注意,给出的示例甚至无法编译,因为他们忘记了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该类的实现相当简单。创建时,它使用 初始化一个 Gtk 窗口,GtkWindowApdater并在该窗口中放入一个空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();
}

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

于 2016-08-06T00:15:01.673 回答
1

引用此链接:

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

所有 x11 的东西都转移到了 Gitorious 上的“附加”部门。(QX11EmbedWidgets 和 QX11EmbedContainer 等不在 5.x 中)

尝试这个:

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

于 2016-08-05T21:59:43.010 回答