如何将 QML 视图嵌入到本机窗口中

Posted

技术标签:

【中文标题】如何将 QML 视图嵌入到本机窗口中【英文标题】:How to embed a QML view into a native window 【发布时间】:2016-08-05 15:00:08 【问题描述】:

我在尝试将 QML 视图插入本机 OSX 窗口时遇到问题。我知道这是可能的,但我不知道我做错了什么。

基本上,我的目标是,给定一个原生 NSView*,然后嵌入一个基于 QML 的小部件。问题是我让它指出它确实在视图内渲染了 qml,但它在侧面创建了一个额外的透明窗口,并且似乎没有正确重绘 QML 视图。

这是我正在使用的代码(请忽略所有内存泄漏):

@interface AppDelegate ()
-(void)processEvents;

@property(nonatomic) NSTimer* timer;
@property(nonatomic) QApplication* qt;
@end

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification

    // Insert code here to initialize your application
    NSWindow* window = [[[NSApplication sharedApplication] windows] objectAtIndex:0];
    NSView *view = [window contentView];
    assert(view);

    char* test[0];
    int count = 0;

    QApplication::instance()->setAttribute(Qt::AA_MacPluginApplication);
    _qt = new QApplication(count, test);

    QMacNativeWidget* native = new QMacNativeWidget(view);
    assert(native);

    QQuickWidget* qml = new QQuickWidget(native);
    qml->setSource(QUrl(QStringLiteral("main.qml")));

    QVBoxLayout* layout = new QVBoxLayout();
    layout->addWidget(qml);

    native->setLayout(layout);

    qml->show();
    native->show();


    NSView* qmlView = (NSView*)native->winId();
    [view addSubview:qmlView];

    _timer = [NSTimer scheduledTimerWithTimeInterval:0.03 target:self selector:@selector(processEvents) userInfo:nil repeats:YES];


- (void)applicationWillTerminate:(NSNotification *)aNotification

    // Insert code here to tear down your application
    [_timer invalidate];
    _qt->quit();



-(void)processEvents

    _qt->processEvents();
    _qt->sendPostedEvents(0,-1);


@end

这是简单的 qml:

import QtQuick 2.7

Item

    visible: true
    x: 0;
    y: 0;
    width: 100
    height: 100
    Rectangle
    
        anchors.fill: parent
        color: 'blue'
        MouseArea
        
            anchors.fill: parent
            onClicked:
            
                console.log(parent.color);
                if(parent.color == '#0000ff')
                    parent.color = 'green';
                else
                    parent.color = 'blue';
            
        
    

【问题讨论】:

【参考方案1】:

QQuickWidget 以稍微复杂的方式将其内容与其他小部件内容组合在一起,涉及帧缓冲区和屏幕外窗口,我怀疑这可能会解释您看到的奇怪结果 - 我不希望它在插件情况下工作。

最简单的选择是使用QQuickWindow(或QQuickView)和createWindowContainerQWindow 转换为QWidget,您可以将其作为QMacNativeWidget 的父级。

但是,我认为最可靠的方法是完全忽略小部件和窗口,并在帧缓冲区级别集成,使用QQuickRenderControlNSOpenGLView。这是更多的代码工作,但保持 NSView 层次结构简单,并且应该提供最佳性能。您可以直接渲染到原生 OpenGL 视图(这需要从原生上下文创建 QOpenGLContext,可能从 Qt 5.4 开始),或者使用 QtQuick 和 NSOpenGLContext 之间共享的纹理渲染到帧缓冲区。

【讨论】:

非常感谢您花时间回答。我将研究这些选项,看看它们是否有效。同时,您能指出我在某处实现的示例吗? 对于createWindowContainer,只需查看文档-它将采用QQuickWindow并将其包装在小部件中。由于不同的实现选择,这在插件场景中会比 QQuickWidget 更好地工作。 对于 QQuickRenderControl,请参阅 Qt 附带的 QQuickRenderControl 示例 - 您需要将该示例中的 WindowSingleThreaded 替换为 NSOpenGLView,并将关联的 openGLContext 包装在 @987654338 中@ 将其与渲染控件一起使用。 谢谢詹姆斯,有机会我会尝试并在此处发布示例

以上是关于如何将 QML 视图嵌入到本机窗口中的主要内容,如果未能解决你的问题,请参考以下文章

Qt5。在 QML 中嵌入 QWidget 对象

MFC 如何将一个对话框嵌入到视图中

如何使用 QML 更改系统日期和时间(嵌入式 Linux)?

如何将滚动视图嵌入到表格视图中

如何以编程方式将视图控制器嵌入到导航视图控制器中

使用 Discord.js 检查嵌入中图像的 url