问题
I am currenctly using Qt 5.7 and I have subclassed QPushButton with the basic idea of using Qt Style sheets on QML side. Here is header file:
#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
and its implementation:
#include "ltpushbutton.h"
LtPushButton::LtPushButton(const QString <Text,
QWidget* const parent)
: QPushButton(parent)
{
this->setText(ltText);
} // constructor
void LtPushButton::ltSetCSSStyle(const QString& ltCSSStyle)
{
this->setStyleSheet(ltCSSStyle);
} // ltSetCSSStyle
The LtPushButton
type is registered in 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();
}
and when I try to set stylesheet of window in 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
the app crashes. Basicly, I am trying to implement QML Button with arbitrary number of radial corners, for example, lower right corners is radially cornered, other corners are perpendicular:
or lower left is radially cornered, other corners are perpendicular:
Same applies to upper corners.
回答1:
You can't embed a Qt widget in a QML like that. QML uses a scene graph (it was possible to use QGraphicsProxyWidget
with Qt Quick 1 which used a QGraphicsView
.
You have to use a QQuickPaintedItem
, now.
But, making a button with a radial corner is quite easy directly in QML by using Shape
.
A quick example:
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"
}
If you don't want to use Shape
, you could use basic Rectangle
(without border): one with rounded corners and two others to mask some corners.
For example:
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"
}
And if you really want to use a C++ class, use 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")
}
来源:https://stackoverflow.com/questions/56425885/qpushbutton-export-to-qml