在屏幕上绘制四条动态线

ylww / 2023-07-20 / 原文

具体要求:

触发状态:【左键保持按下,并移动鼠标】

要求:将线条从屏幕四周将线拉出来,且同样要求能够进行隐藏,线与线之间有距离限制。

结构框架:重写鼠标点击事件与,鼠标移动事件(鼠标移动事件中若用到event()->pos()这个会将一开始的鼠标位置传入,后面会持续刷新坐标)。通过鼠标移动事件触发拖拽线条功能函数,并通过update()触发重写的重绘事件。

思路:来说说拖拽线条功能函数的实现,在功能类中设置四个点QPointF[4]用于保存上下左右四条线(下标与方向对应,一开始初始化为(0,0)。其中0,1下标对应的点若纵坐标为0则代表隐藏,2,3下标对应的点若横坐标为0则代表隐藏)。为了方便我们一次只能选中一根线(对这根线进行操作时,不能影响其他线的位置)。我当时写法是在主体中直接判断何时拉线何时隐藏。然而这样很麻烦,因为鼠标移动事件是不停的会触发的。有时候根本无需这样的判断,而且直接放在主体中,还会影响到其他线(这里当时思考不清晰)。那么如何保证我们在拉动一条线时不影响其他线呢,我们在类中定义一个标志位,用于判断当前是否有线被拖动,若没有,我们通过鼠标的位置来找到合适的线,若有我们则直接跳过通过鼠标位置找合适的线的判断,直接更新QPointF中的对应坐标(这样线的移动比通过鼠标位置来判断更流畅)。松开鼠标时才会将这个标志位置false。(m_bNearTheLine)也就是说当按住鼠标进行拖拽时,每次执行鼠标移动函数中的此函数时,都会跳过判断选取合适线的if(!m_bNearTheLine)语句。直接移动相对应的线。

最终思路:随着移动事件点击的按下,直接通过for循环将移动鼠标事件的位置与QPointF进行判断,若有符合移动条件的点,则将count计数加一。循环结束后,若是count==1则将m_bNearTheLine置true,若是count>1则将m_bNearTheLine置false,若是count==0则继续判断点否在边上,若是,则count=1,且更新index。且将m_bNearTheLine设置为true.之后通过此标识位与index进入下面的更新坐标的if语句。

主要代码:

const double mLineDis = 45;       //两线相隔35不可移动
    qreal distance = 15;             //10px开始拖动
    double respondlen = 20;           //点击处距离线条15像素进行响应。

    int count = 0;   //计算被选中的条数,只能为1
    static int index = 0;   //被选中的线

    if (!m_bNearTheLine) {  //随着点击的按下,直接进行条件判断      初始化中为flase, 鼠标左键松开后也为false.
        for (int i = 0; i < sizeof(m_points) / sizeof(m_points[0]); i++) {     //m_points也就是上面的QPointF[4]对应的变量,下标对应上下左右
            if (i < 2) {
                if (m_points[i].y() != 0 && fabs(mousePos.y() - m_points[i].y()) < respondlen) {
                    count++;
                    index = i;
                }
            }
            else {
                if (m_points[i].x() != 0 && fabs(mousePos.x() - m_points[i].x()) < respondlen) {
                    count++;
                    index = i;
                }
            }
        }

        if (count == 0) {
            if (mousePos.y() < distance && m_points[0].y() == 0) {
                count = 1;
                index = 0;
                m_bNearTheLine = true;
            }
            else if ((mousePos.y() > (m_newPaintRect.height() - distance)) && m_points[1].y() == 0) {
                count = 1;
                index = 1;
                m_bNearTheLine = true;
            }
            else if ((mousePos.x() < distance) && m_points[2].x() == 0) {
                count = 1;
                index = 2;
                m_bNearTheLine = true;
            }
            else if ((mousePos.x() > (m_newPaintRect.width() - distance)) && m_points[3].x() == 0) {
                count = 1;
                index = 3;
                m_bNearTheLine = true;
            }
        }
        else if (count == 1) {
            m_bNearTheLine = true;
        }
        else {
            m_bNearTheLine = false;
        }
    }

    if (m_bNearTheLine) {   //线条正在拖拽中

        bool isMoving = true;   //是否更新线条
            //index就是此刻要移动的线
        if (index == 0) {      //上线
            if (m_points[1].y()) {
                if (mousePos.y() >= m_points[1].y() - mLineDis)
                    isMoving = false;
            }
            else {
                if (mousePos.y() >= m_newPaintRect.height() - mLineDis)
                    isMoving = false;
            }

            if (isMoving) {   
                m_points[0].setY(mousePos.y());
                if (mousePos.y() < distance) //追加这个是由于要实现隐藏功能
                    m_points[0].setY(0);
            }
        }

        if (index == 1) {      //下线
            if (m_points[0].y()) {
                if (mousePos.y() <= m_points[0].y() + mLineDis)
                    isMoving = false;
            }
            else {
                if (mousePos.y() <= mLineDis)
                    isMoving = false;
            }

            if (isMoving) {
                m_points[1].setY(mousePos.y());
                if (mousePos.y() > m_newPaintRect.height() - distance)
                    m_points[1].setY(0);
            }
        }

        if (index == 2) {      //左线
            if (m_points[3].x()) {
                if (mousePos.x() >= m_points[3].x() - mLineDis)
                    isMoving = false;
            }
            else {
                if (mousePos.x() >= m_newPaintRect.width() - mLineDis)
                    isMoving = false;
            }

            if (isMoving) {
                m_points[2].setX(mousePos.x());
                if (mousePos.x() < distance)
                    m_points[2].setX(0);
            }
        }

        if (index == 3) {      //右线
            if (m_points[2].x()) {
                if (mousePos.x() <= m_points[2].x() + mLineDis)
                    isMoving = false;
            }
            else {
                if (mousePos.x() <= mLineDis)
                    isMoving = false;
            }

            if (isMoving) {
                m_points[3].setX(mousePos.x());
                if (mousePos.x() > m_newPaintRect.width() - distance)
                    m_points[3].setX(0);
            }
        }
    }