Qml-跨窗口拖动图片、物体

本文使用的是QtCreater,qml的版本是5.15.2.

1、窗口内拖动一个box

首先建一个box,设置为鲜艳的红色,随后使用MouseArea的属性,注意这里要设置MouseArea的大小,可以用x,y,width,height;也可以使用锚定布局元素anchors.fill=parent表示填充成其父物体的形状。

随后使用drag.target: box 表示鼠标的拖拽绑定在box这个物体上,随后就可以拖拽动这个物体了。

核心代码:

我这里的文件名:drag_page.qml

Item {
    Text
    {
        x: 49
        y: 49
        width: 131
        height: 24
        text: qsTr("window_2")
        font.styleName: "Regular"
        font.pixelSize: 18
        color: "#000000"
        horizontalAlignment: Text.AlignHCenter
        verticalAlignment: Text.AlignVCenter
    }
    Rectangle
    {
        id:box
        x:200
        y:60
        width:50
        height: 50
        color:"#FF0000"

        //Drag.active: mouse.drag.active
    }
    MouseArea
    {
        id:mouse
        //hoverEnabled: true
        anchors.fill: parent
        drag.target: box
        //drag.axis: Drag.XAndYAxis
    }
}

2、跨窗口拖动box

我这里使用两个loader加载两个窗口,形状如下:
在这里插入图片描述左右的窗口是目前创建的,就是客户端常有的界面。右侧可以继续绘制一些窗口这里给出代码:
这个文件名叫做:menuBar.qml

import QtQuick 2.0
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Item {
    MenuBar
    {
        Menu
        {
            title: qsTr("&File")
            Action { text: qsTr("&New...") }
            Action { text: qsTr("&Open...") }
            Action { text: qsTr("&Save") }
            Action { text: qsTr("Save &As...") }
            MenuSeparator { }
            Action { text: qsTr("&Quit") }
        }
        Menu
        {
            title: qsTr("&Edit")
            Action { text: qsTr("Cu&t") }
            Action { text: qsTr("&Copy") }
            Action { text: qsTr("&Paste") }
        }
        Menu
        {
            title: qsTr("&Help")
            Action { text: qsTr("&About") }
        }
    }

    Text
    {
        x: 49
        y: 49
        width: 131
        height: 24
        text: qsTr("window_1")
        font.styleName: "Regular"
        font.pixelSize: 18
        color: "#000000"
        horizontalAlignment: Text.AlignHCenter
        verticalAlignment: Text.AlignVCenter
    }
}

结合前面的drag_page.qml,现在就有了上面的两个窗口。如此便可拖动,但是还有是有问题,请继续看下面。

3、丝滑跨窗口拖动box

现在来拖动。发现当鼠标在window_2的时候,是可以拖动红色box的,但是当鼠标出了window_2的时候,红色box是不能被拖动的,这是因为鼠标的作用域不对了。

所以,长按住物体,能跨窗口拖动,但是拖回来有bug,这个时候我们可以考虑在这两个窗口的上面增加一个蒙层,在蒙层上面拖动box,如此就能实现丝滑的跨窗口拖动了。

本质:让box和mouseArea都在一个区域,就能丝滑了。

在这里插入图片描述

这部分代码就写在main.qml里面:

import QtQuick 2.15
import QtQuick.Window 2.15

Window
{
    title: qsTr("Hello World")
    width: 1920
    height: 1080
    visible: true
    Rectangle
    {
        id:left_control
        x:0
        y:0
        width: 320
        height: parent.height
        border.color:"blue"
        //visible: true
        Loader
        {
            id: loader
            width: parent.width
            height:parent.height
            focus: true
            source:"qrc:/menuBar.qml"
        }
    }
    Rectangle
    {
        id:show_window
        x:left_control.width + 5
        y:0
        width:1000
        height: parent.height
        color:"#EDF1F2"
        border.color:"blue"

        Loader
        {
            width: parent.width
            height:parent.height
            source: "qrc:/drag_page.qml"
        }
     }

		//就是下面这两个{}
    Rectangle
    {
        id:box
        x:200
        y:60
        width:50
        height: 50
        color:"#FF0000"

        //Drag.active: mouse.drag.active
    }
    MouseArea
    {
        id:mask
        anchors.fill:parent
        drag.target: box

    }
}

4、鼠标事件遮挡

细心的朋友发现上面还是有问题,这样导致main.qml的鼠标事件 ,会把下面窗口比如drag_page.qml的鼠标事件给遮挡住,如此就不妙了。

没有关系,我们可以进行鼠标事件穿透

核心代码:


propagateComposedEvents: true
mouse.accepted = false

举例如下

MouseArea
{
    id:mask
    anchors.fill:parent
    drag.target: box

    propagateComposedEvents: true
    onClicked:
    {
        mouse.accepted = false
        console.log("this is main's mouse clicked")
    }

}

在这里插入图片描述

main.qml文件代码:

import QtQuick 2.15
import QtQuick.Window 2.15

//import "menuBar.qml"
Window
{
    title: qsTr("Hello World")
    width: 1920
    height: 1080
    visible: true
    Rectangle
    {
        id:left_control
        x:0
        y:0
        width: 320
        height: parent.height
        border.color:"blue"
        //visible: true
        Loader
        {
            id: loader
            width: parent.width
            height:parent.height
            focus: true
            source:"qrc:/menuBar.qml"
        }
    }
    Rectangle
    {
        id:show_window
        x:left_control.width + 5
        y:0
        width:1000
        height: parent.height
        color:"#EDF1F2"
        border.color:"blue"

        Loader
        {
            width: parent.width
            height:parent.height
            source: "qrc:/drag_page.qml"
        }
     }

    Rectangle
    {
        id:box
        x:200
        y:60
        width:50
        height: 50
        color:"#FF0000"

        //Drag.active: mouse.drag.active
    }
    MouseArea
    {
        id:mask
        anchors.fill:parent
        drag.target: box

        propagateComposedEvents: true
        onClicked:
        {
            mouse.accepted = false
            console.log("this is main's mouse clicked")
        }

    }
}

5、不够完美

再深入,可以发现,鼠标穿透事件只能穿透三个函数:只有clicked, doubleClicked and pressAndHold这三个函数才能穿透。这就很不舒服了,那我的positionChanged怎么办,其他的一些函数怎么办?

其实还是有解决的方法的!!!

使用dropArea.

我们在一个窗口绘制box,再另一个窗口设置dopArea区域,这样,当这个box进入到这个dropArea区域的时候,就能被响应,从而完成一些事件。

下面这里就是,boxwindow_2里面,而dropAreawindow1里面,当box进入绿色区域,能引发响应,比如onEntered,onPositionChanged等等。
在这里插入图片描述核心代码:

下面这段写在drop_page.qml

Rectangle
    {
        id:box
        x:200
        y:60
        width:50
        height: 50
        color:"#FF0000"

		//不要忘记这行哟,设置active为ID为mouse的鼠标
        Drag.active: mouse.drag.active
    }
    MouseArea
    {
        id:mouse
        //hoverEnabled: true
        anchors.fill: parent
        drag.target: box
        //drag.axis: Drag.XAndYAxis

		//这里需要自己调用一些函数,有些函数是自动调用的
        onReleased: dropArea_id.Drag.drop()
        onClicked:
        {
            //console.log("this is drag_page's mouse clicked")
        }
    }

下面这段写在menuBar.qml里面:

    Rectangle
    {
        id:dropArea_id
        border.width: 5
        x:50
        y:100
        z:0
        width: 200
        height: 300
        border.color:"#00FF00"

        DropArea{
            anchors.fill: parent
            onEntered: console.info('enter')
            onExited: console.info('exit')
            onDropped: console.info('dropped')
            onPositionChanged: console.info('positon changed')
        }
    }

6、另有拖动妙计

我们可以在蒙层上面绘制一个box,然后在需要控制的窗口去控制它,让他随鼠标移动到window_1,因为我们发现,只要鼠标不放,物体一定可以被跟着走。

因为box是在蒙层上面的,而当前控制物体的鼠标是在window_2的,所以,这里就有一个子窗口鼠标坐标向父窗口鼠标坐标转换的一个过程。

怎么转换呢?借助onPositionChanged函数,知道父子窗口的鼠标偏差,其实就是一个相对位置的问题。子窗口的0,0点是在子窗口的左上角,父窗口一样。鼠标在子窗口的鼠标位置转换到父窗口,就是要加上:子窗口原点的x,y分别距离父窗口原点x,y的距离。

核心代码:

这段写在window_2窗口,用于控制

    MouseArea
    {
        id:mouse
        anchors.fill: parent

        //if hoverEnabled: true
        //not press can be get mouse position change
        hoverEnabled: true
        onPositionChanged:
        {
            //use event_bus_id for sending singal
            //you should add the pos *** from children window to father
            //it means: event_bus_id.sendMousePos(mouse.x + *** ,mouse.y + *** )
            event_bus_id.sendMousePos(mouse.x,mouse.y)

        }
    }

下面这段写在main.qml

另外EventBus.qml加上:signal sendMousePos(double x,double y)

// 全局事件通信
EventBus
{
    id: event_bus_id
}
Connections
    {
        target:event_bus_id
        function onSendMousePos(x,y)
        {

            box.x = x
            box.y = y
            console.log(box.x,box.y)
        }
    }

7、终极大招——改变鼠标样式

以下借鉴:https://blog.csdn.net/ebthon/article/details/84112389

myCursor.h
#include <QObject> 
#include <QCursor>
#include <QPixmap>
#include <QQuickItem>
#include <QString>

class MyCursor : public QObject {
    
    Q_OBJECT
public:
    MyCursor();
    ~MyCursor();

    Q_INVOKABLE void setMyCursor(QObject *obj,QString source,int width,int height);

};
myCursor.cpp
#include "myCursor.h"

MyCursor::MyCursor(){
    
}
MyCursor::~MyCursor(){
    
}
void MyCursor::setMyCursor(QObject *obj_mouse,QString image_source,int width,int height){
    
    if(nullptr==obj_mouse){
    
        return;
    }
    // 需要将 Qml对象转换为 QQuickItem对象才能 setCursor()
    QQuickItem *itemObj = qobject_cast<QQuickItem*>(obj_mouse);
    if(nullptr==obj_mouse){
    
        return;
    }
    //示例
    //itemObj->setCursor(QCursor(QPixmap(":///resource/image/simulation_page/car.png")));
    itemObj->setCursor(QCursor(QPixmap(image_source).scaled(width, height)));  //, Qt::KeepAspectRatio
}

然后在main.cpp里面导入上面两个文件,加上这句代码:

//myCursor是以后用来调用的名字
engine.rootContext()->setContextProperty("myCursor", new MyCursor());

最后在需要改变mouse样式的mouseArea里面传参就行。

//修改鼠标形状,以及大小
image_source = ":///resource/image/car.png"
myCursor.setMyCursor(mouse_id, image_source,75,75)

还不够,这样的话,跨窗口,鼠标id仍然是蒙层的id,这样一样会被遮挡。最后发现,当我们按下的时候,可以手动设置蒙层的mouseArea的大小区域,使得不被干扰,当释放的时候,又可以设置他的区域,甚至乎设置为0.

以上,喜欢来个赞!!

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: QML-QianWindow-V1版本界面是一款用户界面设计程序,它为开发人员提供了大量可自定义的UI组件,使得开发者可以轻松地创建美观、直观且易于使用的界面。QML-QianWindow-V1版本界面具有界面美观,易用性强以及可扩展性强的特点。该程序提供了多种UI组件如窗口、按钮、文本框、下拉框、进度条等等。每个组件都可以基于开发需求进行个性化设计,提高了程序的可读性和可维护性。 QML-QianWindow-V1版本界面的窗口设计功能令人称赞。用户可以定制窗口的样式、位置和大小等属性,使其符合自己的需求。同时,该程序支持类似IOS与Android风格的Tab、Panel、Dialog等视图控件,让应用的界面更具丰富性和交互性,提升用户体验。 此外,QML-QianWindow-V1版本界面可让用户通过实用的数据模型,快速地创建和管理表格和列表,包括多行、多列的表格和单选或多选列表,使得用户可以方便地处理大量数据。 总之,QML-QianWindow-V1版本界面通过提供易用性和可扩展性强的UI组件来简化界面设计过程,使得开发人员可以迅速开发出优秀的桌面应用程序界面,以满足用户高品质的界面需求。 ### 回答2: QML-Qianwindow-v1版本是一款基于QML语言开发的桌面应用程序,其主要特点是界面设计美观、简单易用,适用于多种应用场景。 该软件的主界面包含五个主要区域:侧边栏、消息中心、主视图、小部件和设置菜单。 侧边栏主要用于导航,其中包含主要的应用程序和功能,使用户可以轻松地进入不同的模块。 消息中心用于显示来自其他应用程序的通知,例如电子邮件或要完成的任务。 主视图是QML-Qianwindow-v1的核心区域,其中包含常见的功能和工具,例如打开的文件、书签和搜索栏。 小部件区域用于显示用户选择的小部件,例如天气预报和日历。 设置菜单区域包含应用程序的设置菜单,用户可以在此处更改应用程序的选项、主题和常规设置。 总体来说,QML-Qianwindow-v1版本的界面设计非常简洁,用户友好,易于使用。它增强了用户的生产力和效率,为用户提供了一种令人愉悦的使用体验。 ### 回答3: QML-QianWindow-v1是一种基于Qt QML开发的简单易用的窗口界面库。其设计风格简洁明了,适用于各种桌面应用开发。 该库主要由三个部分组成:Title Bar、Main Body和Sidebar。其中,Title Bar是窗口的标题栏,可以自定义标题、图标、按钮、菜单等。Main Body是页面的主体内容,可以显示各种控件、窗口和布局。Sidebar是侧边栏,可以显示常用的菜单、工具、快捷方式等。 在QML-QianWindow-v1中,可以使用QianWindow来创建窗口。QianWindow提供了常用的窗口操作方法,例如最小化、最大化、关闭等。同时,该库还提供了很多常用的QML组件,例如按钮、文本框、下拉框、列表框等,这些组件可以方便快捷地进行页面设计。此外,在QML-QianWindow-v1中还支持自定义样式,可以根据需要修改组件的颜色、形状、大小等。 QML-QianWindow-v1的界面设计风格简洁明了,同时具有一定的美观度。尤其是Title Bar部分的设计非常灵活,可以根据需要自由定制。Main Body部分支持多种布局方式,可以满足不同页面设计的需求。Sidebar部分则提供了丰富的快捷操作方式,提高了用户的使用效率。 总的来说,QML-QianWindow-v1是一款非常实用的界面库,可以方便快捷地进行桌面应用开发。无论是初学者还是有经验的开发者,都可以轻松使用该库进行界面设计。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值