如何在QT5 QMainWindow中嵌入gnome-terminal窗口?(C++/RHEL8)
问题描述
- 在Qt QMainWindow中嵌入gnome-terminal窗口,通过
xwininfo获取窗口ID硬编码到代码测试 - gnome-terminal嵌入后显示冻结画面或全黑空白屏,但嵌入wireshark等应用完全正常
- 未设置固定宽高时,gnome-terminal打开尺寸极小,wireshark则为正常大小
相关代码
#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); QMainWindow *w = new QMainWindow; w->setWindowTitle("Terminal on QT"); QWindow *window = QWindow::fromWinId(0x3e0174a); if(window == nullptr){ qDebug() << "it is a null pointer"; } window->setFlags(Qt::FramelessWindowHint); QWidget *widget = QWidget::createWindowContainer(window); widget->setAttribute(Qt::WA_NativeWindow, true); // This didn't really make any difference w->setCentralWidget(widget); w->setFixedHeight(502); w->setFixedWidth(735); w->show(); return a.exec(); }
问题分析与解决方案
gnome-terminal基于VTE框架,采用客户端装饰(CSD)和异步渲染机制,直接嵌入已启动的终端窗口会导致X11重绘事件被Qt容器拦截,引发渲染异常。以下是可行解决思路:
1. 代码内启动并绑定父窗口(避免硬编码ID)
不要手动启动终端再获取窗口ID,而是通过代码启动gnome-terminal时直接指定Qt窗口作为父容器,让终端以子窗口形式创建:
#include "mainwindow.h" #include <QApplication> #include <QProcess> #include <QWindow> #include <QWidget> #include <QMainWindow> int main(int argc, char *argv[]) { QApplication a(argc, argv); QMainWindow w; w.setWindowTitle("Terminal on QT"); w.resize(735, 502); w.show(); // 获取Qt主窗口的X11窗口ID WId parentWinId = w.winId(); // 启动gnome-terminal并绑定到父窗口 QProcess *terminalProcess = new QProcess(&w); QStringList args; args << "--parent" << QString::number(parentWinId); terminalProcess->start("gnome-terminal", args); return a.exec(); }
2. 解决尺寸异常问题
用--parent参数启动时,终端会继承父窗口尺寸,若需精细化控制,可启动时指定终端行列数:
args << "--parent" << QString::number(parentWinId) << "--geometry" << "80x24"; // 80列、24行的终端尺寸
3. 替代方案:使用Qt原生终端组件
如果不想依赖gnome-terminal,可使用QTermWidget(QtTermWidget库,需额外安装),这是原生Qt终端组件,嵌入稳定性更高:
#include "mainwindow.h" #include <QApplication> #include <QMainWindow> #include <QTermWidget> int main(int argc, char *argv[]) { QApplication a(argc, argv); QMainWindow w; w.setWindowTitle("Terminal on QT"); QTermWidget *terminal = new QTermWidget; terminal->setFont(QFont("Monospace", 10)); w.setCentralWidget(terminal); w.resize(735, 502); w.show(); return a.exec(); }
CMake项目需添加依赖:
find_package(Qt6 REQUIRED COMPONENTS Widgets) find_package(QtTermWidget REQUIRED) target_link_libraries(your_app PRIVATE Qt6::Widgets QtTermWidget::QtTermWidget)
关键原因说明
gnome-terminal的客户端装饰(CSD)和VTE异步渲染逻辑,与传统X11应用(如wireshark)的服务端装饰(SSD)差异较大,直接嵌入已启动的终端窗口会导致重绘事件被Qt容器拦截,终端无法正常更新画面;而wireshark这类应用的渲染逻辑更简单,适配X11窗口嵌入机制更好。
内容的提问来源于stack exchange,提问作者baba4yagah
相关产品推荐
相关产品推荐

