自定义标题栏和拖拽边框调整大小——qml

前言

QtWidgets开发实现这两个功能网上有很多,qml却有很少,但是要想用qml去做好看的桌面端,这些工作就必不可少。

这篇文章参考的是网上的一篇博客QtQuick实现无边框窗口的拉伸,拖拽和自定义标题栏 - 简书 (jianshu.com)

,在此基础上进行了一些修改。

自定义标题栏

先说一下标题栏一般有什么功能:

1.显示标题

2.最小化,最大化(还原)、关闭

3.按着鼠标左键,可移动窗口(当时最大化窗口时,还原为常态),双击标题栏放大或还原窗口

由于我应用的标题是图片显示的,所以代码中就没有Text等控件来书写标题,所以代码中只有2、3功能的代码。

对了,在main.qml文件里别忘了设置窗口为无边框(Qt.FramelessWindowHint)

Window {
    id:mainWindow;
    width: 1500;
    height: 846;
    visible: true
    flags: Qt.Window | Qt.FramelessWindowHint;
}

2功能:最小化和关闭按钮都比较简单,写个按钮,直接调用窗口函数就可以。最大化(还原)按钮比较麻烦一些,就是图标切换麻烦些,我用属性maxImg、maxImg_hover和maxImg_pressed

代表最大化(还原)按钮的底图地址,通过切换属性的值来改变最大化时按钮的底图和常态时按钮的底图

3功能,逻辑与QtWidgets开发的一样,只是有不同的语言实现了。

以下是TitleBar.qml的全部内容:

import QtQuick 2.7
import QtQuick.Controls 2.13
import QtQuick.Window 2.2

Item{
    z:1;
    height: 100*hr;
    property bool  isMaximized: false;

    MouseArea{
        anchors.fill: parent
        acceptedButtons: Qt.LeftButton //只处理鼠标左键
        property bool   isDoubleClicked:false
        property point clickPos: "0,0"
         onPressed:
         {
             isDoubleClicked = false;
             clickPos = Qt.point(mouse.x,mouse.y)
         }
         onPositionChanged: {
             if(!isDoubleClicked && pressed && mainWindow.visibility !== Window.Maximized && mainWindow.visibility !== Window.FullScreen) {
                 var delta = Qt.point(mouse.x-clickPos.x, mouse.y-clickPos.y)
                 mainWindow.x += delta.x
                 mainWindow.y += delta.y
             }
             if(mainWindow.visibility === Window.Maximized && pressed && !isDoubleClicked)
             {
                 isMaximized = false;
                 mainWindow.showNormal();
                 normBtn.maxImg="qrc:/res/max.png";
                 normBtn.maxImg_pressed="qrc:/res/max_pressed.png";
                 normBtn.maxImg_hover="qrc:/res/max_hover.png";
             }
         }
         onDoubleClicked :
         {
             isDoubleClicked = true; // 这个时候一定不能响应onPositionChanged不然会一直置顶。
             if(isMaximized){
                 isMaximized = false;
                 mainWindow.showNormal();
                 normBtn.maxImg="qrc:/res/max.png";
                 normBtn.maxImg_pressed="qrc:/res/max_pressed.png";
                 normBtn.maxImg_hover="qrc:/res/max_hover.png";
             }else{
                 isMaximized = true;
                 mainWindow.showMaximized();
                 normBtn.maxImg="qrc:/res/restore.png";
                 normBtn.maxImg_pressed="qrc:/res/restore_pressed.png";
                 normBtn.maxImg_hover="qrc:/res/restore_hover.png";
             }
         }
     }

    Button{
        id:closeBtn
        anchors{right: parent.right; rightMargin: 51*wr; top: parent.top;
                topMargin: 23*wr;}
        width: 65*wr; height:65*wr;
        hoverEnabled : true;

        background: Rectangle{
            color: Qt.rgba(0,0,0,0);
            Image {
                anchors.fill: parent;
                source: closeBtn.hovered ? (closeBtn.pressed ? "qrc:/res/close_pressed.png" :
                       "qrc:/res/close_hover.png") : "qrc:/res/close.png";
            }
        }

        onClicked: {
            mainWindow.close()
        }
    }
    Button{
        id: normBtn;
        property string maxImg: "qrc:/res/max.png";
        property string maxImg_hover: "qrc:/res/max_hover.png";
        property string maxImg_pressed: "qrc:/res/max_pressed.png";

        anchors{right: closeBtn.left; rightMargin: 10*wr; top: parent.top;
                topMargin: 23*wr;}
        width: 65*wr; height:65*wr;
        hoverEnabled : true
        background: Rectangle{
            color: Qt.rgba(0,0,0,0);
            Image {
                id:normBtnBg;
                anchors.fill: parent;
                source: normBtn.hovered ? (normBtn.pressed ? normBtn.maxImg_pressed:
                       normBtn.maxImg_hover) : normBtn.maxImg;
            }
        }
        onClicked:{
            if(isMaximized){
                isMaximized = false;
                mainWindow.showNormal();
                normBtn.maxImg="qrc:/res/max.png";
                normBtn.maxImg_pressed="qrc:/res/max_pressed.png";
                normBtn.maxImg_hover="qrc:/res/max_hover.png";
            }else{
                isMaximized = true;
                mainWindow.showMaximized();
                normBtn.maxImg="qrc:/res/restore.png";
                normBtn.maxImg_pressed="qrc:/res/restore_pressed.png";
                normBtn.maxImg_hover="qrc:/res/restore_hover.png";
            }
        }
    }
    Button{
        id: minBtn
        anchors{right: normBtn.left; rightMargin: 10*wr; top: parent.top;
                topMargin: 23*wr;}
        width: 65*wr; height:65*wr;
        hoverEnabled : true
        background: Rectangle{
            color: Qt.rgba(0,0,0,0);
            Image{
                anchors.fill: parent;
                source: minBtn.hovered ? (minBtn.pressed ? "qrc:/res/min_pressed.png" :
                        "qrc:/res/min_hover.png") : "qrc:/res/min.png";
            }
        }
        onClicked:{
            mainWindow.showMinimized();
        }
    }
}

无边框实现拖拽边沿改变大小

这部分代码和参考博客的不同的是,鼠标的形状的改变是我用qml实现的,而不是用c++.

ResizeItem.qml

import QtQuick 2.0
import QtQuick.Window 2.2

Item {
    property int enableSize: 4
    property bool isPressed: false
    property point customPoint

    //左上角
    Item {
        id: leftTop
        width: enableSize
        height: enableSize
        anchors.left: parent.left
        anchors.top: parent.top
        z: 1000
        MouseArea {
            anchors.fill: parent
            hoverEnabled: true

            onPressed: press(mouse)
            cursorShape: containsMouse?Qt.SizeFDiagCursor:Qt.ArrowCursor;
            onReleased: release()
            onPositionChanged: positionChange(mouse, -1, -1)
        }
    }

    //Top
    Item {
        id: top
        height: enableSize
        anchors.left: leftTop.right
        anchors.right: rightTop.left
        anchors.top: parent.top
        z: 1000
        MouseArea {
            anchors.fill: parent
            hoverEnabled: true

            onPressed: press(mouse)
            cursorShape: containsMouse?Qt.SizeVerCursor:Qt.ArrowCursor;
            onReleased: release()

            onMouseYChanged: positionChange(Qt.point(customPoint.x, mouseY), 1, -1)
        }
    }

    //右上角
    Item {
        id: rightTop
        width: enableSize
        height: enableSize
        anchors.right: parent.right
        anchors.top: parent.top
        z: 1000
        MouseArea {
            anchors.fill: parent
            hoverEnabled: true

            onPressed: {
                press(mouse);
            }
            cursorShape: containsMouse?Qt.SizeBDiagCursor:Qt.ArrowCursor;
            onReleased: release()
            onPositionChanged: positionChange(mouse, 1, -1)
        }
    }

    //Left
    Item {
        id: left
        width: enableSize
        anchors.left: parent.left
        anchors.top: leftTop.bottom
        anchors.bottom: leftBottom.top
        z: 1000
        MouseArea {
            anchors.fill: parent
            hoverEnabled: true

            onPressed: press(mouse)
            cursorShape: containsMouse?Qt.SizeHorCursor:Qt.ArrowCursor;
            onReleased: release()

            onMouseXChanged: positionChange(Qt.point(mouseX, customPoint.y), -1, 1)
        }
    }

    //Center - 5
    Item {
        id: center
        anchors.left: left.right
        anchors.right: right.left
        anchors.top: top.bottom
        anchors.bottom: bottom.top
        MouseArea {
            anchors.fill: parent

            property point clickPos
            onPressed: clickPos = Qt.point(mouse.x,mouse.y)
            onPositionChanged: {
                if(pressed && mainWindow.visibility !== Window.Maximized && mainWindow.visibility !== Window.FullScreen) {
                    var delta = Qt.point(mouse.x-clickPos.x, mouse.y-clickPos.y)
                    mainWindow.x += delta.x
                    mainWindow.y += delta.y
                }
            }
        }
    }

    //Right
    Item {
        id: right
        width: enableSize
        anchors.right: parent.right
        anchors.top: rightTop.bottom
        anchors.bottom: rightBottom.top
        z: 1000
        MouseArea {
            anchors.fill: parent
            hoverEnabled: true

            onPressed: press(mouse)
            cursorShape: containsMouse?Qt.SizeHorCursor:Qt.ArrowCursor;
            onReleased: release()

            onMouseXChanged: positionChange(Qt.point(mouseX, customPoint.y), 1, 1)
        }
    }

    //左下角
    Item {
        id: leftBottom
        width: enableSize
        height: enableSize
        anchors.left: parent.left
        anchors.bottom: parent.bottom
        z: 1000
        MouseArea {
            anchors.fill: parent
            hoverEnabled: true

            onPressed: press(mouse)
            cursorShape: containsMouse?Qt.SizeBDiagCursor:Qt.ArrowCursor;
            onReleased: release()

            onPositionChanged: positionChange(mouse, -1, 1)
        }
    }

    //bottom
    Item {
        id: bottom
        height: enableSize
        anchors.left: leftBottom.right
        anchors.right: rightBottom.left
        anchors.bottom: parent.bottom
        z: 1000
        MouseArea {
            anchors.fill: parent
            hoverEnabled: true

            onPressed: press(mouse)
            cursorShape: containsMouse?Qt.SizeVerCursor:Qt.ArrowCursor;
            onReleased: release()

            onMouseYChanged: positionChange(Qt.point(customPoint.x, mouseY), 1, 1)
        }
    }

    //右下角
    Item {
        id:rightBottom
        width: enableSize
        height: enableSize
        anchors.right: parent.right
        anchors.bottom: parent.bottom
        z: 1000
        MouseArea {
            anchors.fill: parent
            hoverEnabled: true
            cursorShape: containsMouse?Qt.SizeFDiagCursor:Qt.ArrowCursor;
            onPressed: press(mouse)
            onReleased: release()

            onPositionChanged: positionChange(mouse,1,1)
        }
    }

    function press(mouse) {
        isPressed = true
        customPoint = Qt.point(mouse.x, mouse.y)
    }

    function release() {
        isPressed = false
        //customPoint = undefined
    }

    function positionChange(newPosition, directX/*x轴方向*/, directY/*y轴方向*/) {
        if(!isPressed) return

        var delta = Qt.point(newPosition.x-customPoint.x, newPosition.y-customPoint.y)
        var tmpW,tmpH

        if(directX >= 0)
            tmpW = mainWindow.width + delta.x
        else
            tmpW = mainWindow.width - delta.x

        if(directY >= 0)
            tmpH = mainWindow.height + delta.y
        else
            tmpH = mainWindow.height - delta.y

        if(tmpW < mainWindow.minimumWidth) {
            if(directX < 0)
                mainWindow.x += (mainWindow.width - mainWindow.minimumWidth)
            mainWindow.width = mainWindow.minimumWidth
        }
        else {
            mainWindow.width = tmpW
            if(directX < 0)
                mainWindow.x += delta.x
        }

        if(tmpH < mainWindow.minimumHeight) {
            if(directY < 0)
                mainWindow.y += (mainWindow.height - mainWindow.minimumHeight)
            mainWindow.height = mainWindow.minimumHeight
        }
        else {
            mainWindow.height = tmpH
            if(directY < 0)
                mainWindow.y += delta.y
        }
    }
}

 main.qml里加ResizeItem后的代码

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window {
    id:mainWindow;
    width: 1500;
    height: 846;
    visible: true
    flags: Qt.Window | Qt.FramelessWindowHint;

    title: qsTr("RX-Box");

    ResizeItem {
        enableSize: 8
        anchors.fill: parent
        focus: true

        Image {
            id: bgImg;
            z:1;
            anchors.fill: parent;
            source: "qrc:/res/bg.png";
        }
        TitleBar{
            id:titleBar
            z:mystackview.z+1;
            anchors{left: parent.left;right: parent.right; top: parent.top;}
        }


    Component.onCompleted: {
        mainWindow.show();
    }
}

结束语

就这样吧~

  • 4
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值