2016-08-05 43 views
9

Ich habe ein Problem beim Einfügen einer QML-Ansicht in ein natives OSX-Fenster. Ich weiß, dass es möglich ist, aber ich weiß nicht, was ich falsch mache.So betten Sie eine QML-Ansicht in ein natives Fenster ein

Grundsätzlich ist mein Ziel, mit einem nativen NSView * ein QML-basiertes Widget einzubetten. Das Problem ist, dass ich es dahin bringen kann, wo es in der Tat die qml innerhalb der Ansicht rendert, aber es erzeugt ein extra transparentes Fenster zur Seite und es scheint die QML Ansicht nicht richtig neu zu zeichnen.

Hier ist der Code, den ich (bitte ignorieren alle Speicherlecks) bin mit:

@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 

Und hier ist die einfache 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'; 
      } 
     } 
    } 
} 

Antwort

1

QQuickWidget composities seinen Inhalt mit anderen Widget Inhalt in eine etwas komplexe Art, die einen Framebuffer und ein Offscreen-Fenster beinhaltet, von dem ich vermute, dass er die seltsamen Ergebnisse erklärt, die Sie sehen - ich würde nicht erwarten, dass es in einer Plugin-Situation funktioniert.

Die einfachste Option mit createWindowContainer eine QQuickWindow (oder QQuickView) würde verwenden, um die QWindow in eine QWidget drehen Sie können Eltern Ihre QMacNativeWidget.

Ich denke jedoch, der robusteste Ansatz wäre, Widgets und Fenster vollständig zu ignorieren und auf dem Framebuffer-Level zu integrieren, mit QQuickRenderControl und einem NSOpenGLView. Dies ist mehr Arbeit beim Code-Up, aber hält die NSView-Hierarchie einfach und sollte die bestmögliche Leistung bieten. Sie können entweder direkt in die native OpenGL-Ansicht (die aus dem nativen Kontext eine QOpenGLContext erstellen muss, seit Qt 5.4 möglich) oder in einen Framebuffer rendern, der eine Textur verwendet, die zwischen QtQuick und NSOpenGLContext geteilt wird.

+0

Vielen Dank, dass Sie sich die Zeit genommen haben zu antworten. Ich werde diese Optionen untersuchen und sehen, ob sie funktionieren. Können Sie mich in der Zwischenzeit auf ein irgendwo implementiertes Beispiel hinweisen? – bitwise

+0

Für 'createWindowContainer' schauen Sie sich einfach die Dokumente an - es wird ein' QQuickWindow' nehmen und es in ein Widget einbinden. Dies funktioniert in einem Plugin-Szenario besser als QQuickWidget, da die Implementierung unterschiedlich ist. –

+0

Für QQuickRenderControl, siehe 'QQuickRenderControl' Beispiel, das mit Qt ausgeliefert wird - Sie müssen die' WindowSingleThreaded' in diesem Beispiel durch eine 'NSOpenGLView' ersetzen und den zugehörigen' openGLContext' in einen 'QOpenGLContext' umhüllen, um ihn mit dem Render zu verwenden Steuerung. –