关于Qt5 QML中Canvas画布叠加区域为透明时,如何传递鼠标事件到下层画布。

来源:互联网 发布:云计算最大特征是什么 编辑:程序博客网 时间:2024/05/23 10:00

本人的第一篇Qt文章!!以此开始激励自己学习!  本人只能算小菜鸟一只,大神们看的话不喜勿喷!


话不多说,看问题先: 下面的图片是所做东西的最后显示界面的一部分。每一个半椭圆形是一个Canvas画布,灰色半透明区域即画布矩形区域,但是只有弧形是我所需要的。可以很明显的看到灰色半透明区域与下层的组件有重合部分,此时如果需要选中下层Canvas,鼠标事件很容易被灰色区域所属的Canvas接收。这个问题虽然不影响功能实现,但是用户使用会有问题。

刚开始是想找自定义异性组件的解决办法,但是并没有在QML中找到相应的办法(如果在C++代码中有一个mask/setMask是实现)。于是想到了手动判定鼠标点击处是否在弧形区域内,不在区域内即转发信号进行判断,直到找到相应的眼睛看着点到的Canvas。

弧形是使用贝塞尔曲线所画,填充颜色。下面的代码是判断鼠标点击点是否在这个弧形内部。

 function judgePoint(mouseX,mouseY)         //传入参数是一个Canvas中的相对坐标
    {
        var up_counter = 0;
        var down_counter = 0;
        for(var t=0.0;t<1.0;t +=0.05)                          //以下计算过程是贝塞尔曲线取点以及判断一点与一小段线段的位置关系,曲线中取20点
        {
//线段起点,计算方法是通过贝塞尔曲线方程而来
            var b_x = Math.pow(1-t,2)*t*3.0*canvas.width/10+3.0*(1-t)*t*t*canvas.width*9/10+t*t*t*canvas.width 
            var b_y = Math.pow(1-t,3)*canvas.height+3.0*Math.pow(1-t,2)*t*(-canvas.height*3/10+5)+
                    3.0*(1-t)*t*t*(-canvas.height*3/10+5)+t*t*t*canvas.height;
            var t2 = t+0.05
            var next_x = Math.pow(1-t2,2)*t2*3.0*canvas.width/10+3.0*(1-t2)*t2*t2*canvas.width*9/10+t2*t2*t2*canvas.width //线段终点
            var next_y = Math.pow(1-t2,3)*canvas.height+3.0*Math.pow(1-t2,2)*t2*(-canvas.height*3/10+5)+
                    3.0*(1-t2)*t2*t2*(-canvas.height*3/10+5)+t2*t2*t2*canvas.height;
            var k = (b_y-next_y)/(b_x-next_x)                           //通过计算获得的曲线上的两点,计算一条线段
            var b = (next_y*(b_x-next_x)-next_x*(b_y-next_y))/(b_x-next_x)
            var temp_y = mouseX*k+b//判断当前点击点是在线段上方或者下方
            if(temp_y>=mouseY)
            {
                up_counter++
            }
            else
            {
                down_counter++
            }
        }
        if(down_counter === 20)         //在全部线段的下方,即肯定在弧形内部
        {
    canvas.in_bubble = true
            .......
        }
        else if(up_counter >3)//如果超过了3次判断在上方,即一定在弧形外部。取值为3是提高容错率,防止斜率较高时误判
        {
     canvas.in_bubble = false
            .......
        }
        else                                //其他情况,经测试在此贝塞尔曲线中基本不会触发,但不排除特殊位置可以触发,故而预留
        {
            console.debug(up_counter,down_counter)
        }
    }
点击判断过后,即已经区分了是否选中了所需要的弧形。如果未选中,则发送信号到父组件,继续判断。备注:canvas为各个弧形的画布
function blockClickAtOut(item, mouseX, mouseY)//一个弧形选中在了透明区域,判断区域后面能点中哪个弧形。参数为信号发送者canvas,以及鼠标点击点在父组件的坐标
    {
        item.visible = false
        var child = parent.childAt(mouseX, mouseY)            //注意!!!如果用了坐标系统的z值来区分层,childAt是从z值0.1.2开始往上判断
        if(child === null)
        {
            item.visible = true
            return;
        }
        child.judgePoint(mouseX-child.x, mouseY-child.y)
        while(child.in_bubble)          //先从下往上找,直到找不到,链表中的最后一个即为目标block
        {    
     parent.block_click_list.push(child)
            child.visible = false
            child.is_checked = false
            child = null
            child = parent.childAt(mouseX,mouseY)
            if(child === null)
                break;
            child.judgePoint(mouseX-child.x, mouseY-child.y)
        }
        child = parent.block_click_list.pop()//此child即为我们所要找的弧形
        child.visible = true
        ......//执行相应的操作
        for(var i=0;i<parent.block_click_list.length;i++)
        {
            parent.block_click_list[i].visible = true
        }
        parent.block_click_list = []
        item.visible = true
    }
至此,child即为我们所需要的对象。当然在执行时间上面没有问题,经测试,响应很快,不用担心。
原创转载之类的话就不写了,要是有人感兴趣我就谢天谢地了!!当然这毕竟是我的劳动成果,希望大家尊重!

0 0
原创粉丝点击