使用 Qt Quick 创建可扩展的光泽按钮

2024-03-03

我想使用 Qt Quick 创建下面的光泽按钮(最好使用纯 QML,无 C++):

它需要可扩展,所以我不能使用PNG等。

到目前为止我的代码:

import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2

ApplicationWindow {
    id: window
    color: "#cccccc"
    width: 200
    height: 200

    Button {
        id: button
        width: Math.min(window.width, window.height) - 20
        height: width * 0.3
        anchors.centerIn: parent
        text: "Button"

        style: ButtonStyle {
            background: Rectangle {
                gradient: Gradient {
                    GradientStop {
                        position: 0
                        color: "#bbffffff"
                    }
                    GradientStop {
                        position: 0.6
                        color: "#00c0f5"
                    }
                }

                border.color: "grey"
                border.width: height * 0.05
                radius: height / 5
            }

            label: Label {
                text: button.text
                color: "#ddd"
                font.pixelSize: button.height * 0.5
                horizontalAlignment: Text.AlignHCenter
                verticalAlignment: Text.AlignVCenter
            }
        }
    }
}

我有两个问题:

  1. 我不知道如何创建弯曲的光泽效果。
  2. 我需要将文本置于发光之下,但目前它位于其上方。

使用矩形这是不可能的。您可以使用Canvas http://qt-project.org/doc/qt-5/qml-qtquick-canvas.html, 然而。我将引导您完成整个过程。

第 1 步:纯色

由于有多个“层”,我们必须创建一个 Item 来包含它们。我们将根据 Z 顺序添加图层,从平面颜色开始:

import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2

ApplicationWindow {
    id: window
    color: "#cccccc"
    width: 200
    height: 200

    Button {
        id: button
        width: Math.min(window.width, window.height) - 20
        height: width * 0.3
        anchors.centerIn: parent
        text: "Button"

        readonly property real radius: height / 5

        style: ButtonStyle {
            background: Item {
                Canvas {
                    anchors.fill: parent

                    onPaint: {
                        var ctx = getContext("2d");
                        ctx.reset();

                        ctx.beginPath();
                        ctx.lineWidth = height * 0.1;
                        ctx.roundedRect(ctx.lineWidth / 2, ctx.lineWidth / 2,
                            width - ctx.lineWidth, height - ctx.lineWidth, button.radius, button.radius);
                        ctx.strokeStyle = "grey";
                        ctx.stroke();
                        ctx.fillStyle = "#00c0f5";
                        ctx.fill();
                    }
                }
            }

            label: Label {
                text: button.text
                color: "white"
                font.pixelSize: button.height * 0.5
                horizontalAlignment: Text.AlignHCenter
                verticalAlignment: Text.AlignVCenter
            }
        }
    }
}

Canvas 项目应该填充按钮,所以我们写anchors.fill: parent.

然后我们获得用于在画布上绘制的 2D 上下文。我们也打电话reset(),这会在每次绘制之前清除画布。

该按钮有圆角,因此我们定义只读radius属性并将其设置为我们想要的值,在本例中为按钮高度的 20%。

接下来,我们调用beginPath()。这将启动一条新路径,并关闭所有先前的路径。

我们将笔划的线宽设置为按钮高度的 10%。

帆布用途QPainter http://qt-project.org/doc/qt-5/QPainter.html内部。 QPainter 在目标内侧描画 50%,在外侧描画 50%。在绘制圆角矩形时我们必须考虑到这一点,否则笔画将隐藏在画布之外。我们可以通过绘制边距等于线宽一半的矩形来做到这一点。

定义圆角矩形路径后,我们剩下一条需要描边和填充的路径。

这一步的结果是:

第 2 步:标签

由于我们希望文本位于按钮的照射下,因此我们接下来必须定义它:

import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2

ApplicationWindow {
    id: window
    color: "#cccccc"
    width: 200
    height: 200

    Button {
        id: button
        width: Math.min(window.width, window.height) - 20
        height: width * 0.3
        anchors.centerIn: parent
        text: "Button"

        readonly property real radius: height / 5

        style: ButtonStyle {
            background: Item {
                Canvas {
                    anchors.fill: parent

                    onPaint: {
                        var ctx = getContext("2d");
                        ctx.reset();

                        ctx.beginPath();
                        ctx.lineWidth = height * 0.1;
                        ctx.roundedRect(ctx.lineWidth / 2, ctx.lineWidth / 2,
                            width - ctx.lineWidth, height - ctx.lineWidth, button.radius, button.radius);
                        ctx.strokeStyle = "grey";
                        ctx.stroke();
                        ctx.fillStyle = "#00c0f5";
                        ctx.fill();
                    }
                }

                Label {
                    text: button.text
                    color: "white"
                    font.pixelSize: button.height * 0.5
                    anchors.centerIn: parent
                }
            }

            label: null
        }
    }
}

请注意,label样式的组件设置为null。这是因为我们不希望文本高于其他所有内容。如果ButtonStyle had a foreground组件,这不是必需的。相反,我们将 Label 项目添加为background.

此代码的视觉结果与上一步相同。

第三步:闪亮效果

画布可以画画linear http://qt-project.org/doc/qt-5/qml-qtquick-context2d.html#createLinearGradient-method, radial http://qt-project.org/doc/qt-5/qml-qtquick-context2d.html#createRadialGradient-method and conical http://qt-project.org/doc/qt-5/qml-qtquick-context2d.html#createConicalGradient-method梯度。我们将使用线性渐变在按钮上绘制“闪耀”效果:

import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2

ApplicationWindow {
    id: window
    color: "#cccccc"
    width: 200
    height: 200

    Button {
        id: button
        width: Math.min(window.width, window.height) - 20
        height: width * 0.3
        anchors.centerIn: parent
        text: "Button"

        readonly property real radius: height / 5

        style: ButtonStyle {
            background: Item {
                Canvas {
                    anchors.fill: parent

                    onPaint: {
                        var ctx = getContext("2d");
                        ctx.reset();

                        ctx.beginPath();
                        ctx.lineWidth = height * 0.1;
                        ctx.roundedRect(ctx.lineWidth / 2, ctx.lineWidth / 2,
                            width - ctx.lineWidth, height - ctx.lineWidth, button.radius, button.radius);
                        ctx.strokeStyle = "grey";
                        ctx.stroke();
                        ctx.fillStyle = "#00c0f5";
                        ctx.fill();
                    }
                }

                Label {
                    text: button.text
                    color: "white"
                    font.pixelSize: button.height * 0.5
                    anchors.centerIn: parent
                }

                Canvas {
                    anchors.fill: parent
                    onPaint: {
                        var ctx = getContext("2d");
                        ctx.reset();

                        ctx.beginPath();
                        ctx.lineWidth = height * 0.1;
                        ctx.roundedRect(ctx.lineWidth / 2, ctx.lineWidth / 2,
                            width - ctx.lineWidth, height - ctx.lineWidth, button.radius, button.radius);
                        ctx.moveTo(0, height * 0.4);
                        ctx.bezierCurveTo(width * 0.25, height * 0.6, width * 0.75, height * 0.6, width, height * 0.4);
                        ctx.lineTo(width, height);
                        ctx.lineTo(0, height);
                        ctx.lineTo(0, height * 0.4);
                        ctx.clip();

                        ctx.beginPath();
                        ctx.roundedRect(ctx.lineWidth / 2, ctx.lineWidth / 2,
                            width - ctx.lineWidth, height - ctx.lineWidth,
                            button.radius, button.radius);
                        var gradient = ctx.createLinearGradient(0, 0, 0, height);
                        gradient.addColorStop(0, "#bbffffff");
                        gradient.addColorStop(0.6, "#00ffffff");
                        ctx.fillStyle = gradient;
                        ctx.fill();
                    }
                }
            }

            label: null
        }
    }
}

我们绘制与步骤 1 中相同的圆角矩形,只不过这次我们用从上到下的透明渐变填充它。

看起来不错,但还没有完全实现。闪耀效果在按钮的中间停止,为了使用 Canvas 实现这一点,我们需要在绘制渐变矩形之前进行一些裁剪。您可以将 Canvas 的剪裁视为类似于“减法”矩形选框工具 http://helpx.adobe.com/photoshop/using/selecting-marquee-tools.html在 Photoshop 中,除非使用您定义的任何形状。

如果我们幸运并且闪耀的曲线是凹的,我们可以在绘制渐变矩形之前简单地添加以下行:

ctx.beginPath();
ctx.roundedRect(ctx.lineWidth / 2, ctx.lineWidth / 2, width - ctx.lineWidth, height - ctx.lineWidth,
    button.radius, button.radius);
ctx.moveTo(0, height / 2);
ctx.ellipse(-width / 2, height / 2, width * 2, height);
ctx.clip();

相反,我们将使用手动绘制曲线贝塞尔曲线To() http://qt-project.org/doc/qt-5/qml-qtquick-context2d.html#bezierCurveTo-method.

确定要传递到的值bezierCurveTo()并不容易,这就是为什么我建议使用 Craig Buckler 等出色的工具来找到您想要的曲线画布贝塞尔曲线示例 http://blogs.sitepointstatic.com/examples/tech/canvas-curves/bezier-curve.html。这将允许您操纵曲线,直到找到您想要的东西,但最重要的是,它将为您提供创建这些曲线的代码。如果您想做相反的事情,并编辑代码以实时查看曲线,请查看HTML5 Canvas 贝塞尔曲线教程 http://www.html5canvastutorials.com/tutorials/html5-canvas-bezier-curves/.

下面,我做了一个小例子,它描画了剪切路径以使其更容易可视化:

import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2

ApplicationWindow {
    id: window
    color: "#cccccc"
    width: 200
    height: 200

    Button {
        id: button
        width: Math.min(window.width, window.height) - 20
        height: width * 0.3
        anchors.centerIn: parent
        text: "Button"

        readonly property real radius: height / 5

        style: ButtonStyle {
            background: Item {
                Rectangle {
                    anchors.fill: parent
                    color: "transparent"
                    border.color: "black"
                    opacity: 0.25
                }

                Canvas {
                    anchors.fill: parent
                    onPaint: {
                        var ctx = getContext("2d");
                        ctx.reset();

                        var cornerRadius = height / 5;

                        ctx.beginPath();
                        ctx.moveTo(0, height * 0.4);
                        ctx.bezierCurveTo(width * 0.25, height * 0.6, width * 0.75, height * 0.6, width, height * 0.4);
                        ctx.lineTo(width, height);
                        ctx.lineTo(0, height);
                        ctx.lineTo(0, height * 0.4);
                        ctx.strokeStyle = "red";
                        ctx.stroke();
                    }
                }
            }

            label: null
        }
    }
}

红色区域的反面是我们将在其中绘制光泽的区域。

因此,进行裁剪的代码如下:

import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2

ApplicationWindow {
    id: window
    color: "#cccccc"
    width: 200
    height: 200

    Button {
        id: button
        width: Math.min(window.width, window.height) - 20
        height: width * 0.3
        anchors.centerIn: parent
        text: "Button"

        readonly property real radius: height / 5

        style: ButtonStyle {
            background: Item {
                Canvas {
                    anchors.fill: parent

                    onPaint: {
                        var ctx = getContext("2d");
                        ctx.reset();

                        ctx.beginPath();
                        ctx.lineWidth = height * 0.1;
                        ctx.roundedRect(ctx.lineWidth / 2, ctx.lineWidth / 2,
                            width - ctx.lineWidth, height - ctx.lineWidth, button.radius, button.radius);
                        ctx.strokeStyle = "grey";
                        ctx.stroke();
                        ctx.fillStyle = "#00c0f5";
                        ctx.fill();
                    }
                }

                Label {
                    text: button.text
                    color: "#ddd"
                    font.pixelSize: button.height * 0.5
                    anchors.centerIn: parent
                }

                Canvas {
                    anchors.fill: parent
                    onPaint: {
                        var ctx = getContext("2d");
                        ctx.reset();

                        ctx.beginPath();
                        ctx.lineWidth = height * 0.1;
                        ctx.roundedRect(ctx.lineWidth / 2, ctx.lineWidth / 2,
                            width - ctx.lineWidth, height - ctx.lineWidth, button.radius, button.radius);
                        ctx.moveTo(0, height * 0.4);
                        ctx.bezierCurveTo(width * 0.25, height * 0.6, width * 0.75, height * 0.6, width, height * 0.4);
                        ctx.lineTo(width, height);
                        ctx.lineTo(0, height);
                        ctx.lineTo(0, height * 0.4);
                        ctx.clip();

                        ctx.beginPath();
                        ctx.roundedRect(ctx.lineWidth / 2, ctx.lineWidth / 2,
                            width - ctx.lineWidth, height - ctx.lineWidth,
                            button.radius, button.radius);
                        var gradient = ctx.createLinearGradient(0, 0, 0, height);
                        gradient.addColorStop(0, "#bbffffff");
                        gradient.addColorStop(0.6, "#00ffffff");
                        ctx.fillStyle = gradient;
                        ctx.fill();
                    }
                }
            }

            label: null
        }
    }
}

该按钮现在看起来像零件,并且可以单击,但它没有任何鼠标交互的视觉指示。我们也添加一下。

第 4 步:使其看起来具有交互性

只需两行代码即可实现此目的。第一行使闪耀画布部分透明:

opacity: !button.pressed ? 1 : 0.75

第二个增加按钮悬停时文本的亮度:

color: button.hovered && !button.pressed ? "white" : "#ddd"

您可以更进一步,将样式分离到自己的 QML 文件中,提供颜色属性并方便地允许不同颜色的按钮。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Qt Quick 创建可扩展的光泽按钮 的相关文章

  • Android ToggleButton 始终检查

    如果切换按钮处于选中或取消选中状态 我想存储在 SharedPreferences 中 toggle setOnCheckedChangeListener new OnCheckedChangeListener public void on
  • 如何在禁用的 HTML 按钮上呈现工具提示

    我有一个 HTML 按钮 我尝试根据按钮的 标题 属性在其上渲染工具提示 但它没有渲染 主要是因为它被禁用了 然后 我尝试将按钮包装在跨度中并设置跨度的 标题 属性 将鼠标悬停在包含在跨度中的按钮上仍然没有效果 工具提示将呈现在不属于按钮标
  • 与 Qt 项目的静态链接

    我有一个在 Visual Studio 2010 Professional 中构建的 Qt 项目 但是 当我运行它 在调试或发布模式下 时 它会要求一些 Qt dll 如果我提供 dll 并将它们放入 System32 中 它就可以工作 但
  • 动态生成的控件 ID 返回为 NULL

    我可以在 Page PreInit 函数中创建动态控件 如何检索控件及其 ID 我的 C 代码用于创建动态控件之一 var btn new WebForms Button btn Text btn ID Addmore btn Click
  • 如何获取 QTableView 的标题列表?

    我有一个QTableView我的对话框中的对象 我需要访问该表的水平标题并将它们放入QStringList object 尽管进行了大量搜索 但我在 Qt 文档中找不到如何获取此标头列表 编辑 我发现的最接近的地方是this https w
  • 使用 QtWebEngine 将 C++ 对象暴露给 Qt 中的 Javascript

    使用 QtWebkit 可以通过以下方式将 C 对象公开给 JavascriptQWebFrame addToJavaScriptWindowObject如中所述https stackoverflow com a 20685002 5959
  • 在 MacOS 终端上运行 ffmpeg [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我对 MacOS 相当陌生 我发现使用终端来获取信息并不容易ffmpeg和我在 Window 上一样正常运行 我有 ffmpeg 二进制文件ffmpe
  • Visual C++ 打开第二个窗体

    我有一个包含两个表单的项目 Form1 h 和 Form2 h 每个的 cpp 文件是test cpp 和Form2 cpp 我想通过单击按钮从第一个表单打开第二个表单 其中我已经有代码 放置在 button1 Click 方法内 Form
  • Qt 插槽是否与其他代码并行运行?

    在此函数示例中 void MyClass myFunction emit MySignal1 emit MySignal2 如果我有slot1倾听MySignal1 and slot2倾听MySignal2 1 Is slot1总是会在之前
  • 如何在函数执行后停止 tkinter?

    我在停止 提要 时遇到问题 cancel 参数似乎对 after 方法没有任何影响 尽管 feed stop 被打印到控制台 我正在尝试使用一个按钮来启动源 另一个按钮来停止源 from Tkinter import Tk Button i
  • 无法在带有 QSortFilterProxyModel 的 QTreeView 的点击信号中使用 itemFromIndex

    我有一个 QTreeView 在视图和 QStandardItemModel 之间有一个 QSortFilterProxyModel 来对树进行排序 然后我想通过 clicked 信号对视图中的点击进行操作 模型 视图的设置类似于 mymo
  • 同时从多个流中捕获、最佳方法以及如何减少 CPU 使用率

    我目前正在编写一个应用程序 该应用程序将捕获大量 RTSP 流 在我的例子中为 12 个 并将其显示在 QT 小部件上 当我超过大约 6 7 个流时 问题就会出现 CPU 使用率激增并且出现明显的卡顿 我认为它不是 QT 绘制函数的原因是因
  • Qt 是否已经有了自己的 new 和 delete 运算符?

    我正在使用一个QGraphicsScene小部件并在其上显示一些点QGraphicsRectItem 这意味着要拨打很多电话new addItem 当出现时 并且removeItem delete摆脱未使用的点 当然 对于性能问题 我已经实
  • Qt moc 在头文件中实现?

    是否可以告诉 Qt MOC 我想声明该类并在单个文件中实现它 而不是将它们拆分为 h 和 cpp 文件 如果要在 cpp 文件中声明并实现 QObject 子类 则必须手动包含 moc 文件 例如 文件main cpp struct Sub
  • 如何为 Windows 构建静态 Qt 库并将其与 Qt Creator 一起使用

    我已经下载了以下 Qt 源 http download qt nokia com qt source qt everywhere opensource src 4 7 3 zip http download qt nokia com qt
  • Mac 上的 Qt — 如何访问帮助菜单中的“搜索”

    我正在将我的 Qt 应用程序移植到 Mac OS X 在 Windows Linux 上 我使用 QLineEdit 在帮助菜单中提供搜索功能 In Mac OS X I saw something like this is built i
  • 如何在 Qt 应用程序中通过终端命令运行分离的应用程序?

    我想使用命令 cd opencv opencv 3 0 0 alpha samples cpp cpp example facedetect lena jpg 在 Qt 应用程序中按钮的 clicked 方法上运行 OpenCV 示例代码
  • 将 QByteArray 从大端转换为小端

    我想我在这里有点不知所措 我尝试了这么简单的事情 我不敢相信没有任何内置的 Qt 使用 Qt 5 6 2 我尝试将 QByteArray 内的数据从大端转换为小端 总是从相同的测试 QByteArray 开始 就像这样 QByteArray
  • 如何在PYQT中创建按钮点击

    我在 PyQT 中创建按钮单击时遇到了一些问题 当我创建如下按钮的点击时 这张图片无法保存 cv SetImageROI image pt1 0 pt1 1 pt2 0 pt1 0 int pt2 1 pt1 1 1 if self But
  • Android 自定义警报对话框中的 OnClickListener

    我是一个自学成才的初学者 感谢耐心 谢谢 在 Eclipse 中 我使用自己的 xml 文件 custom dialog 创建了一个自定义警报对话框 称为 usernamealert 如果用户尚未输入用户名 即 username lengt

随机推荐