Qt使用createWindowContainer嵌入QWindow出现双窗口问题求助
问题:QMainWindow嵌入QWindow派生类后出现两个窗口
我在Qt应用中实现了继承自QWindow的VtsWindow类,希望将其添加到QMainWindow中,因此使用了QWidget::createWindowContainer方法。但将其设置为中心部件后,出现了两个窗口而非预期的一个。
VtsWindow类代码
#include "common.hpp" #include <QGuiApplication> #include <QMouseEvent> #include <QWheelEvent> #include <vts-browser/log.hpp> #include <vts-browser/map.hpp> #include <vts-browser/mapOptions.hpp> #include <vts-browser/camera.hpp> #include <vts-browser/navigation.hpp> #include <vts-renderer/renderer.hpp> #include <stdexcept> #include <QDebug> static Gl *openglFunctionPointerInstance; void *openglFunctionPointerProc(const char *name) { return (void*)openglFunctionPointerInstance->getProcAddress(name); } Gl::Gl(QSurface *surface) : surface(surface) {} void Gl::current(bool bind) { if (bind) makeCurrent(surface); else doneCurrent(); } void Gl::initialize() { setFormat(surface->format()); create(); if (!isValid()) throw std::runtime_error("unable to create opengl context"); } void DataThread::run() { vts::setLogThreadName("data"); gl->current(); vts::renderer::installGlDebugCallback(); map->dataAllRun(); } VtsWindow::VtsWindow() { QSurfaceFormat format; format.setVersion(3, 3); format.setProfile(QSurfaceFormat::CoreProfile); #ifndef NDEBUG format.setOption(QSurfaceFormat::DebugContext); #endif format.setDepthBufferSize(0); format.setStencilBufferSize(0); setFormat(format); setSurfaceType(QWindow::OpenGLSurface); resize(QSize(800, 600)); show(); // 导致双窗口的关键代码 dataThread.gl = std::make_shared<Gl>(this); dataThread.gl->initialize(); dataThread.gl->current(false); gl = std::make_shared<Gl>(this); gl->setShareContext(dataThread.gl.get()); gl->initialize(); gl->current(); openglFunctionPointerInstance = gl.get(); vts::renderer::loadGlFunctions(&openglFunctionPointerProc); vts::MapCreateOptions mapopts; mapopts.clientId = "vts-browser-qt"; map = dataThread.map = std::make_shared<vts::Map>(mapopts); map->setMapconfigPath( "http://192.168.4.104:9000/store/vts/gebco_global/mapConfig.json", ""); camera = map->createCamera(); navigation = camera->createNavigation(); context = std::make_shared<vts::renderer::RenderContext>(); context->bindLoadFunctions(map.get()); view = context->createView(camera.get()); dataThread.gl->moveToThread(&dataThread); dataThread.start(); lastTime = std::chrono::high_resolution_clock::now(); requestUpdate(); hide(); } VtsWindow::~VtsWindow() { view.reset(); navigation.reset(); camera.reset(); if (map) map->renderFinalize(); dataThread.wait(); } void VtsWindow::mouseMove(QMouseEvent *event) { QPoint diff = event->globalPos() - lastMousePosition; lastMousePosition = event->globalPos(); double n[3] = { (double)diff.x(), (double)diff.y(), 0 }; if (event->buttons() & Qt::LeftButton) navigation->pan(n); if ((event->buttons() & Qt::RightButton) || (event->buttons() & Qt::MiddleButton)) navigation->rotate(n); } void VtsWindow::mousePress(QMouseEvent *) {} void VtsWindow::mouseRelease(QMouseEvent *) {} void VtsWindow::mouseWheel(QWheelEvent *event) { navigation->zoom(event->angleDelta().y() / 120.0); } bool VtsWindow::event(QEvent *event) { switch (event->type()) { case QEvent::UpdateRequest: tick(); return true; case QEvent::MouseMove: mouseMove(dynamic_cast<QMouseEvent*>(event)); return true; case QEvent::MouseButtonPress: mousePress(dynamic_cast<QMouseEvent*>(event)); return true; case QEvent::MouseButtonRelease: mouseRelease(dynamic_cast<QMouseEvent*>(event)); return true; case QEvent::Wheel: mouseWheel(dynamic_cast<QWheelEvent*>(event)); return true; default: return QWindow::event(event); } } void VtsWindow::tick() { auto currentTime = std::chrono::high_resolution_clock::now(); double elapsedTime = std::chrono::duration_cast<std::chrono::microseconds>( currentTime - lastTime).count() * 1e-6; lastTime = currentTime; requestUpdate(); if (!isExposed()) return; if (!gl->isValid()) throw std::runtime_error("invalid gl context"); gl->makeCurrent(this); QSize size = QWindow::size(); // release build -> catch exceptions and close the window // debug build -> let the debugger handle the exceptions #ifdef NDEBUG try { #endif map->renderUpdate(elapsedTime); camera->setViewportSize(size.width(), size.height()); camera->renderUpdate(); view->options().targetFrameBuffer = gl->defaultFramebufferObject(); view->options().width = size.width(); view->options().height = size.height(); view->render(); #ifdef NDEBUG } catch(...) { this->close(); return; } #endif // finish the frame gl->swapBuffers(this); }
main函数代码
#include <clocale> #include <QApplication> #include <QWindow> #include <QtWidgets> #include <QVBoxLayout> #include "common.hpp" #include "mainwindow.h" //#include <vts-renderer/highPerformanceGpuHint.h> int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::AA_UseDesktopOpenGL); QApplication app(argc, argv); std::setlocale(LC_ALL, "C"); // Create the main window MainWindow mainWindow; QWidget *centralWidget = new QWidget(&mainWindow); QVBoxLayout *layout = new QVBoxLayout(centralWidget); VtsWindow vtsWindow; QWidget *container = QWidget::createWindowContainer(&vtsWindow); layout->addWidget(container); mainWindow.setCentralWidget(centralWidget); // Show the main window mainWindow.show(); // run the main event loop return app.exec(); }
原因及解决方法
出现双窗口的核心原因是VtsWindow构造函数中调用了show()方法:
- QWindow调用
show()会直接以独立窗口的形式显示; - 之后用
createWindowContainer将其包装为QWidget并嵌入QMainWindow时,容器又会触发它的显示逻辑,最终导致两个窗口同时出现。
修复方式
直接删除VtsWindow构造函数中的show()调用即可:
// resize(QSize(800, 600)); // show(); // 删掉这行代码
补充说明
- 嵌入后的VtsWindow的显示状态由父容器和QMainWindow控制,无需自行调用
show(); - 构造函数末尾的
hide()可以保留,但不会影响嵌入后的显示效果,因为主窗口显示时会自动让容器内的窗口可见; - 建议将固定resize的逻辑改为由布局控制,比如给container设置合适的大小策略,让它随主窗口自适应。
内容的提问来源于stack exchange,提问作者biscuitvanille
相关产品推荐
相关产品推荐

