QML可拉伸、可拖拽为独立窗口的UI框架

这篇具有很好参考价值的文章主要介绍了QML可拉伸、可拖拽为独立窗口的UI框架。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引言

本文来源于项目预研,根据项目需求,需要新的客户端软件且使用qml实现。之前没有使用过qml,也是通过这个demo进行学习。以下时项目需求:

1.界面分模块,可调整模块大小
2.模块可通过拖拽为独立窗口

最终效果如下图所示:

QML可拉伸、可拖拽为独立窗口的UI框架

代码实现

窗口分割

首先是分模块可调整大小,可以使用Qt已经封装好的组件SplitView,使用的版本是QtQuick.Controls 2.14,效果上来说和QSplitter相同。代码如下:

    SplitView {
        id: splitView
        anchors.fill: parent
        anchors.margins: 4
        orientation: Qt.Vertical
        handle: splitHandle

        SplitView {
            SplitView.fillHeight: true
            SplitView.minimumHeight: 200
            orientation: Qt.Horizontal
            handle: splitHandle

            FootageView {
                id: footageView
                SplitView.preferredWidth: 200
                SplitView.maximumWidth: 250
                SplitView.minimumWidth: 100
            }
            PlayerView {
                id: playerView
                SplitView.fillWidth: true
                SplitView.minimumWidth: 100
            }
            ParamView {
                id: paramView
                SplitView.preferredWidth: 200
                SplitView.fillWidth: true
                //SplitView.maximumWidth: 250
                SplitView.minimumWidth: 100
            }
        }

        TimelineView {
            id: timelineView
            SplitView.preferredHeight: 160
            SplitView.minimumHeight: 100
        }
    }

    Component {
        id: splitHandle

        Rectangle {
            implicitWidth: 4
            implicitHeight: 4
            opacity: 0
        }
    }

可以看到有两SplitView部分组成,上半部分的横向分割,和整体的竖向风格,横向和竖向的控制是通过属性orientation实现(Qt.Horizontal为横向、Qt.Vertical为竖向)。同时布局里面还放置了演示用的四个组件(FootageView、PlayerView、ParamView、TimelineView),其布局的策略如下:

SplitView.fillHeight: 高度自动拉伸
SplitView.fillWidth: 宽度自动拉伸
SplitView.minimumHeight: 最小高度
SplitView.maximumWidth: 最大宽度
SplitView.minimumWidth: 最小宽度
SplitView.preferredHeight: 默认高度
SplitView.preferredWidth: 默认宽度

默认是有用于调整大小的控制条,需要对其进行隐藏,也就是用组件设置handle属性,此处设置了透明的Rectangle达到隐藏的效果,如下所示:

    Component {
        id: splitHandle

        Rectangle {
            implicitWidth: 4
            implicitHeight: 4
            opacity: 0
        }
    }

拖拽为独立窗口

这里需要解决两个问题,一个就是模块拖拽顶部特定区域对外发送信号,另一个就是独立窗口展示。拖拽的交互其实就是鼠标按下和鼠标松开的联动,这里可以使用MouseArea实现。独立窗口展示意味着在接收到拖拽信号后,在悬浮窗口中展示模块内容,同时隐藏主窗体中的模块。

拖拽信号

此处有4个模块,目前只是背景颜色和文字不同,因此应该有共同的原型,用于提供拖拽信号,代码如下:

Item {
    property var backgroundColor: "#1b1b1b"
    property var customText: "View"
    signal dragFinished(var postion)

    // 背景
    Rectangle {
        anchors.fill: parent
        color: backgroundColor
        radius: 8
        Text {
            color: "#ffffffff"
            text: customText
            font.bold: true
            anchors.centerIn: parent
        }
    }

    // 工具栏背景
    Rectangle {
        width: parent.width
        height: toolbar.radius
        anchors.bottom: toolbar.bottom
        color: "#2d2d2d"
    }

    // 工具栏
    Rectangle {
        id: toolbar
        width: parent.width
        height: 30
        color: "#2d2d2d"
        radius: 8

        MouseArea {
            id: dragArea
            anchors.fill: parent;

            property int pressedX: -1
            property int pressedY: -1

            onPressed: (mouse)=>{
                           console.log("Pressed", mouse.x, mouse.y)
                           pressedX = mouse.x
                           pressedY = mouse.y
                       }

            onReleased: (mouse)=>{
                            console.log("Released", mouse.x, mouse.y)
                            if(pressedX >= 0 && pressedY >= 0){
                                let distance = Math.pow(pressedX - mouse.x, 2) + Math.pow(pressedY - mouse.y, 2);
                                distance = Math.pow(distance, 0.5)
                                if(distance > 10){
                                    dragFinished(mapToGlobal(mouse.x, mouse.y))
                                }
                            }
                        }
        }
    }
}

通过代码可以看到组件里面有3个Rectangle,一个是主背景,一个是工具栏,还有一个是为了制造出只有上半部分圆角的效果,做的一个底部直角,因为radius属性没法单独设置。在工具栏处锚定了一个MouseArea,用于实现拖拽信号,在鼠标按下时记录初始位置,松开是计算当前位置与初始位置距离,大于10则视为正常操作,将当前坐标转换为屏幕坐标后发送出去。

独立窗口

独立窗口为主窗体中的一个默认隐藏的悬浮窗体,当模块方式拖拽动作之后触发悬浮窗体显示,动态加载对应模块的.qml文件,同时隐藏主窗体中的模块,代码如下:

import QtQuick 2.14
import QtQuick.Window 2.14
import QtQuick.Controls 2.14

Window {
    visible: true
    width: 800
    height: 480
    title: qsTr("Hello World")

    Component {
        id: splitHandle

        Rectangle {
            implicitWidth: 4
            implicitHeight: 4
            opacity: 0
        }
    }

    SplitView {
        id: splitView
        anchors.fill: parent
        anchors.margins: 4
        orientation: Qt.Vertical
        handle: splitHandle

        SplitView {
            SplitView.fillHeight: true
            SplitView.minimumHeight: 200
            orientation: Qt.Horizontal
            handle: splitHandle

            FootageView {
                id: footageView
                SplitView.preferredWidth: 200
                SplitView.maximumWidth: 250
                SplitView.minimumWidth: 100
            }
            PlayerView {
                id: playerView
                SplitView.fillWidth: true
                SplitView.minimumWidth: 100
            }
            ParamView {
                id: paramView
                SplitView.preferredWidth: 200
                SplitView.fillWidth: true
                //SplitView.maximumWidth: 250
                SplitView.minimumWidth: 100
            }
        }

        TimelineView {
            id: timelineView
            SplitView.preferredHeight: 160
            SplitView.minimumHeight: 100
        }
    }

    Window {
        id: floatWindow
        visible: false
        width: 330
        height: 380
        property var source: ""
        property var sourceLoader: loader

        Loader {
            id: loader
            anchors.fill: parent
        }
    }

    Connections {
        target: floatWindow
        onVisibleChanged: {
            if(floatWindow.visible){
                if(floatWindow.source != ""){
                    floatWindow.sourceLoader.source = floatWindow.source
                }
            }
            else{
                footageView.visible = true;
                playerView.visible = true;
                paramView.visible = true;
                timelineView.visible = true;
            }
        }
    }

    Connections {
        target: footageView
        onDragFinished : (postion)=>{
            diplayFloat(0, postion)
        }
    }

    Connections {
        target: playerView
        onDragFinished : (postion)=>{
            diplayFloat(1, postion)
        }
    }

    Connections {
        target: paramView
        onDragFinished : (postion)=>{
            diplayFloat(2, postion)
        }
    }

    Connections {
        target: timelineView
        onDragFinished : (postion)=>{
            diplayFloat(3, postion)
        }
    }

    function diplayFloat(viewType, postion){
        if(floatWindow.visible){
            return false
        }

        let qmlSource
        switch(viewType){
        case 0:
            qmlSource = "FootageView.qml"
            footageView.visible = false;
            break
        case 1:
            qmlSource = "PlayerView.qml"
            playerView.visible = false;
            break
        case 2:
            qmlSource = "ParamView.qml"
            paramView.visible = false;
            break
        case 3:
            qmlSource = "TimelineView.qml"
            timelineView.visible = false;
            break
        }
        floatWindow.source = qmlSource

        if(postion){
            floatWindow.x = postion.x - floatWindow.width / 2
            floatWindow.y = postion.y
        }
        floatWindow.show()

        return true
    }
}

动态加载使用到Loader ,在悬浮窗体显示后将对应资源显示的路径替换Loader 的source属性文章来源地址https://www.toymoban.com/news/detail-490127.html

到了这里,关于QML可拉伸、可拖拽为独立窗口的UI框架的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Vue:可拖拽组件

            在实际开发中,很可能会遇到开发可拖拽组件的需求,目的是应对某些弹框组件会遮盖某些重要信息/可操作面板,通过可拖拽的形式可以将上层的弹框组件移动到其他位置,从而不影响整个系统的操作。下面,我们分两步走,开发一个可拖拽的弹框组件,最终效果如

    2024年02月12日
    浏览(36)
  • 实现ElementUI tab标签可拖拽

    通过sortablejs实现 参考:https://blog.csdn.net/wangjiecsdn/article/details/121995534

    2024年01月22日
    浏览(69)
  • 前端弹窗可拖拽功能实现

           前端弹窗可拖拽功能主要实现思路就是监听鼠标移动事件,根据鼠标位置实时修改弹窗距离父级窗口(或者屏幕,根据需求设置)的left和right,但是考虑到鼠标拖拽一般都是在div的标题栏处发生,鼠标按下的位置不可能是弹窗的左上角位置,为此需要计算 鼠标按下的

    2024年02月19日
    浏览(45)
  • 可拖拽编辑的流程图X6

     先上图

    2024年02月11日
    浏览(42)
  • vue 进度条组件(可拖拽可点击)

    在日常的开发当中,随着项目的需求复杂化,自定义组件也越来越常见,而且扩展性也比一些组件库要更加全面,比如视频播放器的进度条。 可自定义设置以下属性: 当前进度value,默认50 是否可拖拽isDrag,默认true 设置最小值min,默认0 设置最大值max,默认100 进度条颜色

    2024年02月16日
    浏览(35)
  • Qt编写可拖拽的自定义控件

    一直想做一个像卡牌游戏一样的,可以拖动卡片,实现改变位置,顺序交换的效果,今天我们一起来尝试一下。 类名为Card h文件 cpp文件 我们完成了一个很简单的200*400的圆角卡片 在主界面中展示看看 widget.h widget.cpp 运行后的效果: 首先要实现控件拖动,需要有2个要素,1:

    2024年02月11日
    浏览(45)
  • Vue3封装可拖拽的弹窗

    核心代码(复制就可以使用了) 使用方式

    2024年01月19日
    浏览(41)
  • vue3实现组件可拖拽 vuedraggable

    npm i -S vuedraggable@next 中文文档,里面有完整代码案例,值得一看 vue.draggable vue3 版本在工作台中的应用场景 - itxst.com

    2024年02月13日
    浏览(38)
  • 基于vue的可拖拽设计的报表看板设计器

    gitee上的不错项目,基于vue实现的可拖拽的看板设计器可以自由搭配颜色和图标,开发者可以只关注业务数据接口,前端不擅长的人员可以直接轻松上手。 1.可支持的元素 文字,边框,常见图表,柱形图,折线饼图等等,还有一些列表数据,当然还支持iframe嵌套,当组件满足

    2024年02月11日
    浏览(58)
  • tauri-vue:快速开发跨平台软件的架子,支持自定义头部UI拖拽移动和窗口阴影效果

    一个使用 tauri+vue+ts 开发跨平台软件的模板,支持窗口头部自定义 UI 和拖拽和窗口阴影,不用再自己做适配了,拿来即用,非常 nice。而且已经封装好了 tauri 的 http 请求工具,省去很多弯路。开源地址:GitHub - Sjj1024/tauri-vue: 一个使用tauri和vue开发跨平台软件的架子 使用到的技

    2024年02月12日
    浏览(67)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包