首页 > 解决方案 > QQuickView 在调用 show 时显示一个空窗口

问题描述

我仍在尝试学习使用 QML + c++ 进行编码,所以这个代码片段的本质可能听起来有点不切实际。我正在尝试编写一个继承QQuickView并加载qml文件的类。这是我的头文件:

#ifndef FORMLOGIN_H
#define FORMLOGIN_H

#include <QQuickView>


class FormLogin:public QQuickView
{
public:
    FormLogin();
public slots:
    void myHide();
};

这是它的实现:

#include "formlogin.h"
#include<QCoreApplication>
#include<QQmlEngine>
FormLogin::FormLogin()
{
    this->setSource(QUrl("qrc:/main.qml"));
    QObject::connect(this->engine(),&QQmlEngine::quit,&QCoreApplication::quit);

}
#include "iostream"
using namespace std;
void FormLogin::myHide(){
    cout<<"called"<<endl;
    if(this->isVisible()){
        this->hide();
    }else{
        this->show();
    }
}

这是我的main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include"formlogin.h"
#include<iostream>
#include<QTimer>
using namespace std;
FormLogin *formLogin;
QTimer *myTimer;
int main(int argc, char *argv[])
{
    //QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);
    
    formLogin=new FormLogin();
    myTimer=new QTimer();
    myTimer->start(3000);
    QObject::connect(myTimer,&QTimer::timeout,formLogin,&FormLogin::myHide);
    
    return app.exec();
}

我的main.qml样子是这样的:

import QtQuick 2.0
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import QtGraphicalEffects 1.0
Window {
    Rectangle{
        anchors.fill: parent
        color: "lightblue"
    }   

    title: qsTr("Title")
    width: 450; height: 550
    visible: true
}

现在,您可以从代码中QTimer了解到它有一个连接的myHide,它显示和隐藏我的登录表单。以下是我运行应用程序时发生的情况:

  1. 它打开了我设计的 QML 表单main.qml
  2. 3 秒后它会打开一个空窗口;
  3. 它会在 3 秒后隐藏空窗口,并继续保持这种状态。

我个人的期望是它不应该首先显示我的 QML 表单,它应该等到计时器的超时信号发出。然而,它首先显示正确的 QML 窗口,然后每次this->show被调用时它开始显示那个奇怪的空窗口。现在是我提问的时候了:

  1. 为什么它显示我的 QML 窗口没有“formLogin->show()”?
  2. 这个空窗是什么?
  3. 为什么我不能隐藏我的主窗口?

标签: c++qtqml

解决方案


解释

问题是因为 QQuickView 需要一个项目作为根,而不是一个窗口。

问题是因为 QQuickView 需要一个元素作为根,而不是一个窗口。您的程序执行以下操作:

  1. 当您启动可见的窗口是 QML
  2. 然后出现 QQuickView 窗口
  3. 在它隐藏 QQuickView 并通过第 2 步之后。

步骤 1 和 2 分别回答您的问题 1 和 2。在问题 3 的情况下,答案是您只隐藏了第二个窗口。

QQmlApplicationEngine 文档中指出了这一点:

与 QQuickView 不同,QQmlApplicationEngine 不会自动创建根窗口。如果您使用 Qt Quick 中的可视项目,则需要将它们放置在 Window 内。

解决方案

所以有2个选项:

  • 或将 Window 替换为 Item:

    import QtQuick 2.0
    
    Rectangle{
        anchors.fill: parent
        color: "lightblue"
    }
    
    #include "formlogin.h"
    #include<QCoreApplication>
    #include<QQmlEngine>
    
    #include <iostream>
    
    FormLogin::FormLogin()
    {
        setSource(QUrl("qrc:/main.qml"));
        connect(engine(), &QQmlEngine::quit, &QCoreApplication::quit);
        setTitle("Title");
        resize(450, 550);
    
    }
    
    void FormLogin::myHide(){
        std::cout << "called" << std::endl;
        setVisible(!isVisible());
    }
    
    #include <QGuiApplication>
    #include <QTimer>
    
    #include "formlogin.h"
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        FormLogin formLogin;
        QTimer myTimer;
        myTimer.start(3000);
        QObject::connect(&myTimer, &QTimer::timeout, &formLogin, &FormLogin::myHide);
    
        return app.exec();
    }
    
  • 或者使用 QQmlApplicationEngine 代替 QQuickView

加:

如果您想从 QML 修改窗口,那么您有 2 个选项:

  1. 或者在 C++ 插槽中实现逻辑并从 QML 调用它。

  2. 或者使用 setContextProperty 将窗口导出到 QML

    FormLogin::FormLogin()
    {
        rootContext()->setContextProperty("window", this);
        setSource(QUrl("qrc:/main.qml"));
        connect(this->engine(),&QQmlEngine::quit,&QCoreApplication::quit);
        setTitle("Title");
        resize(450, 550);
    }
    
    import QtQuick 2.0
    
    Rectangle{
        id: root
        anchors.fill: parent
        color: "lightblue"
    
        Component.onCompleted: {
            window.flags = (window.flags | Qt.CustomizeWindowHint | Qt.FramelessWindowHint) & ~Qt.WindowTitleHint
            // window.showMaximized()
        }
    }
    

推荐阅读