具体要求:
触发状态:【左键保持按下,并移动鼠标】
要求:将线条从屏幕四周将线拉出来,且同样要求能够进行隐藏,线与线之间有距离限制。
结构框架:重写鼠标点击事件与,鼠标移动事件(鼠标移动事件中若用到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语句。
主要代码:
/*这里关于隐藏线条麻烦了,可以直接赋值为最大,然后隐藏最大值的线条,这样就可以直接比较两条线的距离,不用再去判断存不存在另一条线的情况。
按照上面这个思路可以得到非常大的代码简化(例如:不用考虑下面第一个if中的if(count==0),直接判断if(count==1)else)。笔者这里就不进行改进后的代码展示了。
*/
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); } } }