【问题标题】:QPushButton export to QML [duplicate]QPushButton 导出到 QML [重复]
【发布时间】:2019-06-04 16:41:21
【问题描述】:

我目前正在使用Qt 5.7,并且我已将QPushButton 子类化为在QML side 上使用Qt Style sheets 的基本思想。这是头文件:

#ifndef LTPUSHBUTTON_H
#define LTPUSHBUTTON_H

#include <QWidget>
#include <QPushButton>
#include <QString>

/**
 * @class Modified push button class
 */
class LtPushButton : public QPushButton
{
    Q_OBJECT

public:
    /**
     * @brief Constructor
     * @param parent
     */
    LtPushButton(const QString& ltText=QString(),
                 QWidget* const parent=Q_NULLPTR);

    /**
     * @brief Method for settings CSS style from QML side
     * @param ltCSSStyle
     */
    Q_INVOKABLE void ltSetCSSStyle(const QString& ltCSSStyle);
};

#endif // LTPUSHBUTTON_H

及其实现:

#include "ltpushbutton.h"

LtPushButton::LtPushButton(const QString &ltText,
                           QWidget* const parent)
    : QPushButton(parent)
{
    this->setText(ltText);
}   // constructor


void LtPushButton::ltSetCSSStyle(const QString& ltCSSStyle)
{
    this->setStyleSheet(ltCSSStyle);
}   // ltSetCSSStyle

LtPushButton 类型在 main.cpp 中注册:

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlEngine>

#include "ltpushbutton.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QApplication app(argc, argv);
    QQmlApplicationEngine engine;

    qmlRegisterType<LtPushButton>("com.testapp.gui",
                                  1,
                                  0,
                                  "LtPushButton");

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);

    engine.load(url);

    return app.exec();
}

当我尝试在main.qml 中设置窗口样式表时:

import QtQuick 2.7
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.3

import com.testapp.gui 1.0

Window
{
    width: 640
    height: 480

    visible: true

    title: qsTr("Hello World")

    color: "red"

    GridLayout
    {
        anchors.fill: parent

        rows: 2
        columns: 2

        LtPushButton
        {
            id: ltUpperLeftButton

            Layout.fillWidth: true
            Layout.fillHeight: true
            Layout.alignment: Qt.AlignHCenter|Qt.AlignVCenter

            text: qsTr("One");
        }   // LtPushButton

        Component.onCompleted:
        {
            ltUpperLeftButton.ltSetCSSStyle("border-top-left-radius: 20px;
                                             border-top-right-radius: 20px;
                                             border-bottom-left-radius: 20px;
                                             border-bottom-right-radius: 20px;
                                             background-color: #0047bd;
                                             border: 2px solid #0047bd;
                                             color: #ffffff;
                                             outline: none;");
        }   // Component.onCompleted
    }   // GridLayout
}   // Window

应用程序崩溃。基本上,我试图用任意数量的径向角实现QML Button,例如,右下角是径向角,其他角是垂直的:

或左下角是径向拐角,其他角是垂直的:

同样适用于上角。

【问题讨论】:

  • 好吧,你不能。 QML 中的绘画系统与 QtWidgets 不同,除了 QPushButton 期望 QWidget 作为父级,但在 QML 中它指出父级是 GridLayout 而不是 QWidget。您可以使用 QQuickWidgets 在 QWidget 中嵌入 QML,但反之则不行
  • 您对 2 个不兼容的概念感到困惑。 QtQuick 在 QPushButton 为 QtWidgets 时使用Scene Graph

标签: qt qml


【解决方案1】:

你不能像这样在 QML 中嵌入 Qt 小部件。 QML 使用场景图(可以将 QGraphicsProxyWidget 与使用 QGraphicsView 的 Qt Quick 1 一起使用。

你现在必须使用QQuickPaintedItem

但是,直接在 QML 中使用 Shape 制作一个带有径向角的按钮非常容易。

一个简单的例子:

Button {
        id: button
        background: Shape {
            ShapePath {
                id: shape
                property int angleRadius: 12
                strokeWidth: 4
                fillColor: "red"
                startX: 0; startY: 0
                PathLine { x: button.width; y: 0 }
                PathLine { x: button.width; y: button.height - shape.angleRadius }
                PathArc {
                        x: button.width - shape.angleRadius; y: button.height
                        radiusX: shape.angleRadius
                        radiusY: shape.angleRadius
                    }
                PathLine { x: 0; y: button.height }
                PathLine { x: 0; y: 0 }
            }
        }
        text: "Confirm"
    }

如果您不想使用Shape,您可以使用基本的Rectangle(无边框):一个带有圆角,另外两个用来遮盖一些角。

例如:

Button {
    id: button2
    background: Rectangle {
        id: bg
        radius: 8
        color: "green"
        Rectangle {
            width: bg.width
            height: bg.radius
            x: 0
            y: 0
            color: bg.color
        }
        Rectangle {
            width: bg.radius
            height: bg.height
            x: 0
            y: 0
            color: bg.color
        }
    }
    text: "Confirm"
}

如果你真的想使用 C++ 类,请使用QQuickPaintedItem

class Button : public QQuickPaintedItem
{
    Q_OBJECT
    Q_PROPERTY(QColor color READ color WRITE setColor)
    Q_PROPERTY(QString text READ text WRITE setText)
public:
    Button(QQuickItem* parent=nullptr): QQuickPaintedItem(parent) {
        setAcceptedMouseButtons(Qt::LeftButton);
    }

    virtual void paint(QPainter* painter) override
    {
        QPainterPath path;
        path.setFillRule(Qt::WindingFill);
        path.addRoundRect(contentsBoundingRect(), 90, 90);
        path.addRect(0, 0, width(), height() / 2);
        path.addRect(0, 0, width() / 2, height());
        painter->save();
        painter->setPen(Qt::NoPen);
        painter->setBrush(color());
        painter->drawPath(path);
        painter->restore();
    }

    QColor color() const { return bgColor; }
    QString text() const { return contentText; }
public slots:
    void setColor(QColor const& color) { bgColor = color; }
    void setText(QString const& text) { contentText = text; }

signals:
    void clicked();
private:
    QColor bgColor;
    QString contentText;

    QElapsedTimer pressedTimer;

    virtual void mousePressEvent(QMouseEvent* event) override
    {
        if (event->button() != Qt::MouseButton::LeftButton)
        {
            pressedTimer.invalidate();
            return;
        }
        pressedTimer.restart();
    }

    virtual void mouseReleaseEvent(QMouseEvent* /*event*/) override
    {
        if (pressedTimer.elapsed() < 200)
            clicked();
        pressedTimer.invalidate();
    }
};


// In main.cpp
qmlRegisterType<Button>("my.app", 1, 0, "MyButton");

// main.qml
MyButton {
    text: "Cancel"
    color: "blue"
    width: 60
    height: 30
    onClicked: console.log("Clicked")
}

【讨论】:

  • 我的目标是具有自定义嵌入式 Linux 发行版的嵌入式设备,其中不包含 Shape 对象。
猜你喜欢
  • 1970-01-01
  • 2015-07-05
  • 2018-11-04
  • 1970-01-01
  • 2020-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多