038-第三代软件开发-简易视频播放器-自定义Slider (二)

头图

第三代软件开发-简易视频播放器-自定义Slider (二)

文章目录

  • 第三代软件开发-简易视频播放器-自定义Slider (二)
    • 项目介绍
    • 简易视频播放器
    • 自定义Slider (二)
      • 横向
      • 纵向

关键字: QtQml关键字3关键字4关键字5

项目介绍

欢迎来到我们的 QML & C++ 项目!这个项目结合了 QML(Qt Meta-Object Language)和 C++ 的强大功能,旨在开发出色的用户界面和高性能的后端逻辑。

在项目中,我们利用 QML 的声明式语法和可视化设计能力创建出现代化的用户界面。通过直观的编码和可重用的组件,我们能够迅速开发出丰富多样的界面效果和动画效果。同时,我们利用 QML 强大的集成能力,轻松将 C++ 的底层逻辑和数据模型集成到前端界面中。

在后端方面,我们使用 C++ 编写高性能的算法、数据处理和计算逻辑。C++ 是一种强大的编程语言,能够提供卓越的性能和可扩展性。我们的团队致力于优化代码,减少资源消耗,以确保我们的项目在各种平台和设备上都能够高效运行。

无论您是对 QML 和 C++ 开发感兴趣,还是需要我们为您构建复杂的用户界面和后端逻辑,我们都随时准备为您提供支持。请随时联系我们,让我们一同打造现代化、高性能的 QML & C++ 项目!

重要说明☝

☀该专栏在第三代软开发更新完将涨价

简易视频播放器

其实咱们在前面屏保哪里已经搞过视频文件播放了,只是哪里没有进度条,也没有时间线,也不能控制播放暂停,今天我们就是把这些再加上去。如下图所示,这里因为原始录制的Gif 太大,无法上传,所以做了减帧处理,看着有点卡顿了。

这里咱就是直接上代码吧;

import QtQuick 2.15
import QtMultimedia 5.15
import QtQuick.Layouts 1.15                     // 布局需要
import QtQuick.Controls 2.15
Rectangle
{
    property string videoSource: "file"
    property bool fullScreen: false
    id:root
    color: "#000000"
    anchors.centerIn: parent
    width: 720
    height: 480
    visible: false
    SoundEffect {
        id: playSound
        source: "qrc:/Audio/T_Resource/T_Audio/T_Base/buttonTach.wav"
    }
    //    Video
    //    {
    //        id:video_show
    //        anchors.fill: parent
    //        loops: MediaPlayer.Infinite
    //        source: root.videoSource
    //    }



    MediaPlayer
    {
        id:media_video
        source: videoSource                 // 绝对路径
        loops: MediaPlayer.Infinite
        volume: 0.5
    }
    VideoOutput
    {
        id:out_put
        anchors.fill: parent
        source: media_video
    }


    RowLayout
    {
        id:layout_menu
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.bottom: parent.bottom
        height: 26
        spacing: 20
        Item
        {
            width: 26
            height: 20
            Image {
                anchors.centerIn: parent
                height: 26
                fillMode: Image.PreserveAspectFit
                source: (media_video.playbackState === MediaPlayer.PlayingState ) ? "qrc:/Video/T_Resource/T_Image/Vidoe/zt.png" : "qrc:/Video/T_Resource/T_Image/Vidoe/bf.png"
            }
            MouseArea
            {
                anchors.fill: parent
                onClicked: (media_video.playbackState === MediaPlayer.PlayingState ) ? media_video.pause() : media_video.play();
            }

        }

        Item {
            implicitWidth: 50
            Text {
                anchors.centerIn: parent
                font.pixelSize: 20
                color: "#FFFFFF"
                text: {
                    // 创建变量获取时间当前播放位置,单位毫秒
                    var milliseconds = media_video.position
                    // 创建变量,将当前播放位置的毫秒转换为分钟,并向下取舍
                    var minutes = Math.floor(milliseconds / 60000)
                    // 获取不足 60秒的毫秒数
                    milliseconds -= minutes * 60000
                    // 创建变量,不足60秒的毫秒数转换为秒
                    var seconds = milliseconds / 1000
                    // 进行四舍五入
                    seconds = Math.round(seconds)
                    // 判断秒数是否小于10秒,来输出时间格式,最终格式为:mm:ss
                    if(seconds < 10)
                        return minutes + ":0" + seconds
                    else
                        return minutes + ":" + seconds
                }
            }
        }

        Slider
        {
            id:durationTimeSlider
            Layout.fillWidth: true
            value: media_video.position / media_video.duration
            background: Rectangle{
                x: durationTimeSlider.leftPadding
                y: durationTimeSlider.topPadding + durationTimeSlider.availableHeight / 2 - height / 2
                implicitHeight: 4
                implicitWidth: 200
                width: durationTimeSlider.availableWidth
                height: implicitHeight
                radius: 2
                color: "#F0F0F0"    // 进度条背景颜色
                // 视频已经播放的区域
                Rectangle{
                    width: durationTimeSlider.visualPosition * parent.width
                    height: parent.height
                    color: "#36ABDF"    // 进度条已经走完的颜色
                    radius: 2
                }
            }
            // 滑块样式
            handle: Rectangle{
                antialiasing: true
                x: durationTimeSlider.leftPadding + durationTimeSlider.visualPosition
                   * (durationTimeSlider.availableWidth - width)
                y: durationTimeSlider.topPadding + durationTimeSlider.availableHeight / 2 - height / 2
                implicitWidth: 20
                implicitHeight: 20
                radius: 10
                border.color: "#bdbebf"    // 滑块边框颜色
                // 判断滑块按压状态,设置不同的颜色
                color: durationTimeSlider.pressed ? "#B0C4DE" : "#F0F0F0"
                // 滑块中心的区域,我这里设置了透明
                Rectangle{
                    width: 4
                    height: 4
                    radius: 2
                    color: "transparent"
                    anchors.centerIn: parent
                }
            }

            property real index: 0
            property bool changed: false
            // 滑块移动时,将 index 设置为滑块当前位置
            onMoved: {
                if(pressed){
                    index = position
                }
            }

            onPressedChanged: {
                if(pressed === true){
                    changed = true
                }else if (changed === true){
                    media_video.seek(index * media_video.duration)
                    changed = false
                }
            }
        }
        Item {
            implicitWidth: 50
            Text {
                anchors.centerIn: parent
                font.pixelSize: 20
                color: "#FFFFFF"
                text: {
                    var millseconds = media_video.duration.valueOf()
                    var minutes = Math.floor(millseconds / 60000)
                    millseconds -= minutes * 6000
                    var secounds = millseconds / 1000
                    secounds = Math.round(secounds)
                    // 返回 mm : ss 格式时间
                    if(secounds < 10)
                        return minutes + ":0" + secounds
                    else
                        return minutes + ":" + secounds
                }
            }
        }
        Item
        {
            id:item_volume
            width: 26
            height: 20
            Image {
                anchors.centerIn: parent
                height: 26
                fillMode: Image.PreserveAspectFit
                source: "qrc:/Video/T_Resource/T_Image/Vidoe/yl_z.png"
            }
            MouseArea
            {
                anchors.fill: parent
                onClicked: item_volum.visible = !item_volum.visible
            }

        }

        Item
        {
            width: 26
            height: 20
            Image {
                anchors.centerIn: parent
                height: 26
                fillMode: Image.PreserveAspectFit
                source: fullScreen ? "qrc:/Video/T_Resource/T_Image/Vidoe/sx.png" :"qrc:/Video/T_Resource/T_Image/Vidoe/qp.png"
            }
            MouseArea
            {
                anchors.fill: parent
                onClicked: root.fullScreen = !root.fullScreen
            }

        }
    }
    Item {
        id:item_volum
        width: 42
        height: 235
        visible: false
        anchors.bottom: layout_menu.top
        anchors.right: layout_menu.right
        anchors.rightMargin: 36
        Text {
            anchors.top: parent.top
            anchors.horizontalCenter: parent.horizontalCenter
            font.pixelSize: 20
            color: "#36ABDF"
            text: (volumeSlider.value * 100).toFixed(0)
        }
        Slider
        {
            id:volumeSlider
            width: 42
            height: 220
            from:0.0
            to:1.0
            stepSize: 0.01
            value: media_video.volume
            anchors.bottom: parent.bottom
            anchors.horizontalCenter: parent.horizontalCenter
            orientation:Qt.Vertical
            background: Rectangle{
                anchors.horizontalCenter: parent.horizontalCenter
                y: volumeSlider.topPadding + volumeSlider.availableHeight / 2 - height / 2
                implicitHeight: 200
                implicitWidth: 4
                width: 4
                height: volumeSlider.availableHeight
                radius: 2
                color: "#F0F0F0"    // 进度条背景颜色
                // 视频已经播放的区域
                Rectangle{
                    anchors.bottom: parent.bottom
                    width: parent.width
                    height: parent.height - volumeSlider.visualPosition * parent.height
                    color: "#36ABDF"    // 进度条已经走完的颜色
                    radius: 2
                }
            }
            // 滑块样式
            handle: Rectangle{
                antialiasing: true
                anchors.horizontalCenter: parent.horizontalCenter
                y: volumeSlider.topPadding + volumeSlider.visualPosition
                   * (volumeSlider.availableHeight - height)

                implicitWidth: 20
                implicitHeight: 20
                radius: 10
                border.color: "#bdbebf"    // 滑块边框颜色
                // 判断滑块按压状态,设置不同的颜色
                color: volumeSlider.pressed ? "#B0C4DE" : "#F0F0F0"
                // 滑块中心的区域,我这里设置了透明
                Rectangle{
                    width: 4
                    height: 4
                    radius: 2
                    color: "transparent"
                    anchors.centerIn: parent
                }
            }
            onValueChanged: media_video.volume = value

        }

    }


    function play()
    {
        media_video.play();
    }
    function stop(){
        if((media_video.playbackState === MediaPlayer.PlayingState  || media_video.playbackState === MediaPlayer.PausedState))
            media_video.stop();
    }
}

自定义Slider (二)

横向

        Slider
        {
            id:durationTimeSlider
            Layout.fillWidth: true
            value: media_video.position / media_video.duration
            background: Rectangle{
                x: durationTimeSlider.leftPadding
                y: durationTimeSlider.topPadding + durationTimeSlider.availableHeight / 2 - height / 2
                implicitHeight: 4
                implicitWidth: 200
                width: durationTimeSlider.availableWidth
                height: implicitHeight
                radius: 2
                color: "#F0F0F0"    // 进度条背景颜色
                // 视频已经播放的区域
                Rectangle{
                    width: durationTimeSlider.visualPosition * parent.width
                    height: parent.height
                    color: "#36ABDF"    // 进度条已经走完的颜色
                    radius: 2
                }
            }
            // 滑块样式
            handle: Rectangle{
                antialiasing: true
                x: durationTimeSlider.leftPadding + durationTimeSlider.visualPosition
                   * (durationTimeSlider.availableWidth - width)
                y: durationTimeSlider.topPadding + durationTimeSlider.availableHeight / 2 - height / 2
                implicitWidth: 20
                implicitHeight: 20
                radius: 10
                border.color: "#bdbebf"    // 滑块边框颜色
                // 判断滑块按压状态,设置不同的颜色
                color: durationTimeSlider.pressed ? "#B0C4DE" : "#F0F0F0"
                // 滑块中心的区域,我这里设置了透明
                Rectangle{
                    width: 4
                    height: 4
                    radius: 2
                    color: "transparent"
                    anchors.centerIn: parent
                }
            }

            property real index: 0
            property bool changed: false
            // 滑块移动时,将 index 设置为滑块当前位置
            onMoved: {
                if(pressed){
                    index = position
                }
            }

            onPressedChanged: {
                if(pressed === true){
                    changed = true
                }else if (changed === true){
                    media_video.seek(index * media_video.duration)
                    changed = false
                }
            }
        }

纵向

        Slider
        {
            id:volumeSlider
            width: 42
            height: 220
            from:0.0
            to:1.0
            stepSize: 0.01
            value: media_video.volume
            anchors.bottom: parent.bottom
            anchors.horizontalCenter: parent.horizontalCenter
            orientation:Qt.Vertical
            background: Rectangle{
                anchors.horizontalCenter: parent.horizontalCenter
                y: volumeSlider.topPadding + volumeSlider.availableHeight / 2 - height / 2
                implicitHeight: 200
                implicitWidth: 4
                width: 4
                height: volumeSlider.availableHeight
                radius: 2
                color: "#F0F0F0"    // 进度条背景颜色
                // 视频已经播放的区域
                Rectangle{
                    anchors.bottom: parent.bottom
                    width: parent.width
                    height: parent.height - volumeSlider.visualPosition * parent.height
                    color: "#36ABDF"    // 进度条已经走完的颜色
                    radius: 2
                }
            }
            // 滑块样式
            handle: Rectangle{
                antialiasing: true
                anchors.horizontalCenter: parent.horizontalCenter
                y: volumeSlider.topPadding + volumeSlider.visualPosition
                   * (volumeSlider.availableHeight - height)

                implicitWidth: 20
                implicitHeight: 20
                radius: 10
                border.color: "#bdbebf"    // 滑块边框颜色
                // 判断滑块按压状态,设置不同的颜色
                color: volumeSlider.pressed ? "#B0C4DE" : "#F0F0F0"
                // 滑块中心的区域,我这里设置了透明
                Rectangle{
                    width: 4
                    height: 4
                    radius: 2
                    color: "transparent"
                    anchors.centerIn: parent
                }
            }
            onValueChanged: media_video.volume = value

        }

这部分qml 代码很好懂,没有啥需要注意的吧,这里需要注意的就是一部分

    MediaPlayer
    {
        id:media_video
        source: videoSource                 // 绝对路径
        loops: MediaPlayer.Infinite
        volume: 0.5
    }
    VideoOutput
    {
        id:out_put
        anchors.fill: parent
        source: media_video
    }

其实我最开始是用了Video组件的,但是再全屏的时候遇到问题,就是画面不会跟着全屏,应该是哪里跟着改下就可,不过我没有时间处理,这个功能就是播放一下宣教视频和宣传视频,所以目前不会有太多的精力放在这里。


博客签名2021

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/111612.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

我在Vscode学OpenCV 初步接触

OpenCV是一个开源的计算机视觉库&#xff0c;可以处理图像和视频数据。它包含了超过2500个优化过的算法&#xff0c;用于对图像和视频进行处理&#xff0c;包括目标识别、面部识别、运动跟踪、立体视觉等。OpenCV支持多种编程语言&#xff0c;包括C、Python、Java等&#xff0c…

golang 实现雪花算法

雪花算法概述 snowflake 是 twitter 开源的分布式ID生成算法&#xff0c;其核心思想为&#xff0c;一个long型的ID&#xff1a; 41 bit 作为毫秒数 - 41位的长度可以使用69年10 bit 作为机器编号 &#xff08;5个bit是数据中心&#xff0c;5个bit的机器ID&#xff09; - 10位…

【网络知识必知必会】聊聊网络层IP协议

文章目录 前言IP 协议格式总结 前言 在之前的博文中, 我们聊过了传输层中的两个重点协议 TCP 和 UDP, 本文我们再来聊聊网络层中的一个协议IP, 简单认识一下 IP 协议格式. IP 协议与 TCP 协议的复杂度也不妨多让, 不过我们在这里只是简单的聊一聊 IP 协议的报文格式就行, 毕竟…

图书馆书目推荐数据分析与可视化

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

【Java初阶练习题】-- 循环练习题

循环练习题 1. 根据年龄, 来打印出当前年龄的人是少年(低于18), 青年(19-28), 中年(29-55), 老年(56以上)2. 判定一个数字是否是素数3. 打印 1 - 100 之间所有的素数4. 输出 1000 - 2000 之间所有的闰年5. 输出乘法口诀表6. 求两个正整数的最大公约数7. 求出0&#xff5e;999之…

图数据库Neo4j概念、应用场景、安装及CQL的使用

一、图数据库概念 引用Seth Godin的说法&#xff0c;企业需要摒弃仅仅收集数据点的做法&#xff0c;开始着手建立数据之间的关联关系。数据点之间的关系甚至比单个点本身更为重要。 传统的**关系数据库管理系统(RDBMS)**并不擅长处理数据之间的关系&#xff0c;那些表状数据模…

滚动条默认是隐藏的只有鼠标移上去才会显示

效果 在设置滚动条的类名中写 /* 滚动条样式 */.content-box::-webkit-scrollbar {width: 0px; /* 设置纵轴&#xff08;y轴&#xff09;轴滚动条 */height: 0px; /* 设置横轴&#xff08;x轴&#xff09;轴滚动条 */}/* 滚动条滑块&#xff08;里面小方块&#xff09; */.…

分享一下微信小程序抽奖链接怎么做

标题&#xff1a;微信小程序抽奖链接制作全攻略&#xff0c;轻松玩转营销抽奖活动 一、引言 在当今的数字化时代&#xff0c;抽奖活动已经成为一种高效的市场营销策略&#xff0c;而微信小程序作为一个功能强大的移动端平台&#xff0c;为企业和个人提供了制作抽奖链接的便捷…

浅析Redis大Key | 京东云技术团队

一、背景 在京东到家购物车系统中&#xff0c;用户基于门店能够对商品进行加车操作。用户与门店商品使用Redis的Hash类型存储&#xff0c;如下代码块所示。不知细心的你有没有发现&#xff0c;如果单门店加车商品过多&#xff0c;或者门店过多时&#xff0c;此Key就会越来越大…

不同源安装nginx

Nginx是一款高性能的Web服务器软件。在安装Nginx时&#xff0c;可以选择不同的安装源。 1.官方源&#xff1a;在官方网站下载Nginx的源代码&#xff0c;然后进行编译安装。 2.EPEL源&#xff1a;EPEL (Extra Packages for Enterprise Linux)源是针对Red Hat、CentOS、Scienti…

IDEA初步入门

1 安装 现在的系统更迭很快&#xff0c;很多软件都只支持win10 和 11了&#xff0c;但我们过时党还在用win7. 所以就必须找到合适的版本。在windows 7 64位系统下&#xff0c;可以使用IDEA 2020.1.4版本。 在Jetbrain官方下&#xff0c;找到历史版本&#xff0c;找到windows版…

reactive与ref VCA

简介 Vue3 最大的一个变动应该就是推出了 CompositionAPI&#xff0c;可以说它受ReactHook 启发而来&#xff1b;它我们编写逻辑更灵活&#xff0c;便于提取公共逻辑&#xff0c;代码的复用率得到了提高&#xff0c;也不用再使用 mixin 担心命名冲突的问题。 ref 与 reactive…

torch.div()不支持round_mode参数

问题怎么定位的呢&#xff0c;把报错信息一股脑甩给chatgpt&#xff0c;问他什么意思&#xff0c;他就反馈说“在标准的Python库中&#xff0c;div() 函数不接受 rounding_mode 参数。”&#xff08;虽然这个问题也不难&#xff0c;但是改偷的懒还是要偷&#xff09; 问题再现…

【JMeter】逻辑控制器分类以及功能介绍

常用逻辑控制器的分类以及介绍 If Controller 满足if条件才会执行取样器 Loop Controller 对取样器循环多次 ForEach Controller

【POI-EXCEL-下拉框】POI导出excel下拉框数据太多导致下拉框不显示BUG修复

RT 最近在线上遇到一个很难受的BUG&#xff0c;我一度以为是我代码逻辑出了问题&#xff0c;用了Arthas定位分析之后&#xff0c;开始坚定了信心&#xff1a;大概率是POI的API有问题&#xff0c;比如写入数据过多。 PS&#xff1a;上图为正常的下拉框。但是&#xff0c;当下拉…

AGENTTUNING:为LLM启用广义的代理能力

背景 翻译智谱这篇文章的初衷是&#xff0c;智谱推出了他们所谓的第三代大模型。这第三代的特点在哪呢&#xff1a;个人总结主要有一下几个点&#xff1a; 1.用特定prompt方式自闭环方式解决安全注入问题 2.增加了模型function call、agent能力 3.具备代码能力 4.做了能力…

python 安装 pyquicklz 库函数

问题描述&#xff1a; 安装 pyquicklz 库的时候 报错 error: subprocess-exited-with-error 解决方法&#xff1a; 安装 Cython 库&#xff1a; pip install Cython -i https://pypi.tuna.tsinghua.edu.cn/simple/ 安装 Microsoft C Build Tools Microsoft C Build Tools 的下…

idea中启动多例项目配置

多实例启动 日常本地开发微服务项目时&#xff0c;博主想要验证一下网关的负载均衡以及感知服务上下线能力时&#xff0c;需要用到多实例启动。 那么什么是多实例启动嘞&#xff1f;简单说就是能在本地同时启动多个同一服务。打个比方项目中有一个 MobileApplication 服务&…

WPS Office 制作下拉两级联动

文章目录 前言WPS Office 制作下拉两级联动1. 准备两级联动数据![在这里插入图片描述](https://img-blog.csdnimg.cn/dc8c21c5f12349aeb467eed266888618.png)2. 设置一级下拉3. 设置二级联动下拉 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xf…

Java使用OkHttp库采集电商视频简单代码示例

很多朋友经常问我&#xff0c;能不能用OkHttp库的Java编写一个淘宝视频的采集程序&#xff0c;今天它来了&#xff01;在市面上众多的采集框架中&#xff0c;OkHttp库的应用比较广泛&#xff0c;而且也是非常的稳定&#xff0c;下面的代码示例不知道能不能满足大家的胃口呢&…
最新文章