WindowAppItemLink.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. #include "WindowAppItemLink.h"
  2. #include "WindowAppPouScene.h"
  3. #include "WindowAppItemInterface.h"
  4. // 连接线段数量(正常情况下是五段线)
  5. #define LINK_LINE_NORMAL_COUNT 5
  6. // 并行模式(二段线)
  7. #define LINK_LINE_PARALLEL_COUNT 2
  8. WindowAppItemLink::WindowAppItemLink(
  9. WindowAppItemInterface* startItem,
  10. WindowAppItemInterface* endItem,
  11. LINK_MODE linkMode,
  12. QVector<QLineF> linePoints
  13. )
  14. : m_startInfItem(startItem)
  15. , m_endInfItem(endItem)
  16. , m_mode(linkMode)
  17. {
  18. // 接收悬停事件,用于显示鼠标切换效果
  19. this->setAcceptHoverEvents(true);
  20. // 设置风格,可选择但不可拖动
  21. this->setFlag(QGraphicsItem::ItemIsSelectable, true);
  22. // this->setFlag(QGraphicsItem::ItemIsMovable, true);
  23. // 初始化连接线段
  24. this->initLines(linePoints);
  25. // 2022-6-12,如果初始化时指定了线段坐标,则按照指定的坐标来初始化线段(主要用于反序列化的情况)
  26. if (linePoints.size() <= 0)
  27. {
  28. // 如果没有指定坐标,则还是根据起点和终点自动生成线段信息
  29. this->updateLinkLinesAuto();
  30. }
  31. // 初始化右键菜单
  32. createContextMenu();
  33. //// 将消息全部透传到Group中的成员中处理
  34. //this->setHandlesChildEvents(false);
  35. }
  36. WindowAppItemLink::~WindowAppItemLink()
  37. {
  38. // 删除动态创建的Link连线
  39. for (int i = 0; i < m_linkLines.size(); i++)
  40. {
  41. delete m_linkLines[i];
  42. }
  43. // 清空线段组
  44. m_linkLines.clear();
  45. }
  46. /// <summary>
  47. /// 初始化连接线段
  48. /// </summary>
  49. void WindowAppItemLink::initLines(QVector<QLineF> linePoints)
  50. {
  51. if (m_startInfItem == nullptr || m_endInfItem == nullptr)
  52. {
  53. qDebug() << "[Error] WindowAppItemLink::initLines - start or end InfItem is nullptr.";
  54. return;
  55. }
  56. // 如果是普通模式,则正常初始化五段线
  57. if (this->m_mode == LINK_MODE::LINK_NORMAL)
  58. {
  59. m_nLineCount = LINK_LINE_NORMAL_COUNT;
  60. }
  61. else
  62. {
  63. m_nLineCount = LINK_LINE_PARALLEL_COUNT;
  64. }
  65. // 初始化需要绘制的线条
  66. for (int i = 0; i < m_nLineCount; i++)
  67. {
  68. WindowAppItemLinkLine* line = nullptr;
  69. if (linePoints.size() <= 0)
  70. {
  71. line = new WindowAppItemLinkLine(QPointF(0,0), QPointF(0,0), this, m_mode);
  72. }
  73. else
  74. {
  75. line = new WindowAppItemLinkLine(linePoints[i].p1(), linePoints[i].p2(), this, m_mode);
  76. }
  77. // 设定索引值,用于线条移动时使用
  78. line->m_nLineIndex = i;
  79. m_linkLines.push_back(line);
  80. //// 加入本控件组
  81. //this->addToGroup(line);
  82. // 绑定线段移动消息,用于在拖动时其他线段进行联动
  83. connect(
  84. line,
  85. &WindowAppItemLinkLine::lineMoveSignal,
  86. this,
  87. &WindowAppItemLink::onLineMove
  88. );
  89. }
  90. // 设置第一个线段为起点线段
  91. m_linkLines[0]->setLinkStart(true);
  92. // 设置最后一个线段为终点线段
  93. m_linkLines[m_nLineCount - 1]->setLinkEnd(true);
  94. }
  95. /// <summary>
  96. /// 按照正常模式更新线段
  97. /// </summary>
  98. void WindowAppItemLink::updateNormalLines()
  99. {
  100. if (m_linkLines.size() <= 0)
  101. {
  102. return;
  103. }
  104. // 通过五段线的方式来进行连接
  105. // 五段线起点坐标
  106. QPointF ptStart = m_startInfItem->line().p2();
  107. ptStart = mapFromScene(m_startInfItem->mapToScene(ptStart));
  108. // 五段线终点坐标
  109. QPointF ptEnd = m_endInfItem->line().p1();
  110. ptEnd = mapFromScene(m_endInfItem->mapToScene(ptEnd));
  111. // 每条连接线的起点和终点
  112. QPointF ptLineStart = ptStart;
  113. QPointF ptLineEnd;
  114. // 起点连接线的终点位置坐标
  115. QPointF ptLinkStart;
  116. // 终点连接线的终点位置坐标
  117. QPointF ptLinkEnd;
  118. // 1. 计算起点连接线(起点一定是输出接口)
  119. ptLineEnd = QPointF(ptStart.x() + LINK_START_LINE_SIZE, ptStart.y());
  120. ptLinkStart = ptLineEnd;
  121. // 线条方向从起点向外
  122. m_linkLines[0]->updateLine(ptStart, ptLineEnd);
  123. // 2. 计算终点连接线(终点一定是输入接口)
  124. ptLinkEnd = QPointF(ptEnd.x() - LINK_START_LINE_SIZE, ptEnd.y());
  125. // 线条方向从外部向终点
  126. m_linkLines[4]->updateLine(ptLinkEnd, ptEnd);
  127. // 3. 起点延伸线
  128. ptLineStart = ptLineEnd;
  129. float ptLineEndY = ptLineStart.y() + (ptEnd.y() - ptStart.y()) / 2;
  130. ptLineEnd = QPointF(ptLineStart.x(), ptLineEndY);
  131. // 方向为从起点往外
  132. m_linkLines[1]->updateLine(ptLineStart, ptLineEnd);
  133. // 4. 中间连接线
  134. ptLineStart = ptLineEnd;
  135. float ptLineEndX = ptLineStart.x() + (ptLinkEnd.x() - ptLinkStart.x());
  136. ptLineEnd = QPointF(ptLineEndX, ptLineStart.y());
  137. // 方向为从起点方向到终点方向
  138. m_linkLines[2]->updateLine(ptLineStart, ptLineEnd);
  139. // 5. 终点延伸线
  140. ptLineStart = ptLineEnd;
  141. // 方向为从外部连向终点
  142. m_linkLines[3]->updateLine(ptLineStart, ptLinkEnd);
  143. }
  144. /// <summary>
  145. /// 按照并行模式更新线段
  146. /// </summary>
  147. void WindowAppItemLink::updateParallelLines()
  148. {
  149. if (m_linkLines.size() <= 0)
  150. {
  151. return;
  152. }
  153. // 通过二段竖线的方式来进行连接
  154. // 终点坐标(终点接口的外侧点)
  155. QPointF ptEnd(m_endInfItem->line().p1());
  156. ptEnd = mapFromScene(m_endInfItem->mapToScene(ptEnd));
  157. ptEnd.setX(ptEnd.rx() - LINK_START_LINE_SIZE);
  158. // 起点坐标(并行母线端)
  159. QPointF ptStart(m_endInfItem->line().p1().rx() - LINK_START_LINE_SIZE, m_startInfItem->line().p2().ry());
  160. ptStart = mapFromScene(m_startInfItem->mapToScene(ptStart));
  161. ptStart.setX(ptEnd.rx());
  162. // 1. 垂直连线(方向为从母线端到接口端,可能是向上,可能是向下)
  163. m_linkLines[0]->updateLine(ptStart, ptEnd);
  164. // 2. 终点连接线(终点一定是输入接口,方向为从左到右)
  165. ptEnd.setX(ptEnd.rx() + LINK_START_LINE_SIZE);
  166. QPointF ptLinkEnd = QPointF(ptEnd.rx() - LINK_START_LINE_SIZE, ptEnd.ry());
  167. m_linkLines[1]->updateLine(ptLinkEnd, ptEnd);
  168. }
  169. //=============================================================================
  170. //
  171. // 菜单相关代码
  172. //
  173. //=============================================================================
  174. /// <summary>
  175. /// 显示右键菜单
  176. /// </summary>
  177. /// <param name="event"></param>
  178. void WindowAppItemLink::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
  179. {
  180. scene()->clearSelection();
  181. this->setSelected(true);
  182. contextMenu->exec(event->screenPos());
  183. }
  184. ///// <summary>
  185. ///// 任何一条子线段被选中时,都交给Group统一处理
  186. ///// </summary>
  187. ///// <param name="selItem"></param>
  188. //void WindowAppItemLink::onLineSelected(WindowAppItemLinkLine* selItem)
  189. //{
  190. // //for (const auto& lineItem : m_linkLines)
  191. // //{
  192. // // lineItem->setSelected(true);
  193. //
  194. // // qDebug() << "WindowAppItemLink::onLineSelected.";
  195. // //}
  196. //
  197. // this->setSelected(true);
  198. //}
  199. ///// <summary>
  200. ///// 显示右键菜单
  201. ///// </summary>
  202. ///// <param name="event"></param>
  203. //void WindowAppItemLink::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
  204. //{
  205. // scene()->clearSelection();
  206. // setSelected(true);
  207. //
  208. // contextMenu->exec(event->screenPos());
  209. //}
  210. /// <summary>
  211. /// 初始化功能块的右键菜单
  212. /// </summary>
  213. void WindowAppItemLink::createContextMenu()
  214. {
  215. cutAction = new QAction(("Cut"), this);
  216. connect(cutAction, &QAction::triggered, this, &WindowAppItemLink::onMenuCut);
  217. copyAction = new QAction(QIcon(":/image/Copy.png"), ("Copy"), this);
  218. connect(copyAction, &QAction::triggered, this, &WindowAppItemLink::onMenuCopy);
  219. pasteAction = new QAction(("Paste"), this);
  220. connect(pasteAction, &QAction::triggered, this, &WindowAppItemLink::onMenuPaste);
  221. deleteAction = new QAction(QIcon(":/image/Delete.png"), ("&Delete"), this);
  222. deleteAction->setStatusTip(("Delete item from diagram"));
  223. connect(deleteAction, &QAction::triggered, this, &WindowAppItemLink::onMenuDelete);
  224. contextMenu = new QMenu();
  225. contextMenu->addAction(cutAction);
  226. contextMenu->addAction(copyAction);
  227. contextMenu->addAction(pasteAction);
  228. contextMenu->addSeparator();
  229. contextMenu->addAction(deleteAction);
  230. }
  231. /// <summary>
  232. /// 菜单 - Cut
  233. /// </summary>
  234. void WindowAppItemLink::onMenuCut()
  235. {
  236. QMessageBox::information(nullptr, "Vision Plus", "onMenuCut");
  237. }
  238. /// <summary>
  239. /// 菜单 - Copy
  240. /// </summary>
  241. void WindowAppItemLink::onMenuCopy()
  242. {
  243. QMessageBox::information(nullptr, "Vision Plus", "onMenuCopy");
  244. }
  245. /// <summary>
  246. /// 菜单 - Paste
  247. /// </summary>
  248. void WindowAppItemLink::onMenuPaste()
  249. {
  250. QMessageBox::information(nullptr, "Vision Plus", "onMenuPaste");
  251. }
  252. /// <summary>
  253. /// 菜单 - Delete
  254. /// </summary>
  255. void WindowAppItemLink::onMenuDelete()
  256. {
  257. // 直接调用scene()中的删除方法来统一删除
  258. ((WindowAppPouScene*)scene())->delLink(this);
  259. }
  260. //=============================================================================
  261. //
  262. // 线条拖动相关代码
  263. //
  264. //=============================================================================
  265. /// <summary>
  266. /// Group内的线段准备拖拽时,是否允许其移动(必须在合法的范围内拖动)
  267. /// </summary>
  268. /// <param name="nextP1"></param>
  269. /// <param name="nextP2"></param>
  270. /// <returns></returns>
  271. bool WindowAppItemLink::canMove(QPointF nextP1, QPointF nextP2)
  272. {
  273. Q_UNUSED(nextP1);
  274. Q_UNUSED(nextP2);
  275. return true;
  276. }
  277. /// <summary>
  278. /// 获取所有线段坐标(用于序列化)
  279. /// </summary>
  280. /// <returns></returns>
  281. QVector<QLineF> WindowAppItemLink::getAllLinkLinePoints()
  282. {
  283. QVector<QLineF> allLines;
  284. for (const auto& one_line : m_linkLines)
  285. {
  286. allLines.push_back(one_line->line());
  287. }
  288. return allLines;
  289. }
  290. /// <summary>
  291. /// 将Link设置为Movable(包括Group和所有的子线段)
  292. /// </summary>
  293. /// <param name="bEnable"></param>
  294. void WindowAppItemLink::setMovable(bool bEnable /*= true*/)
  295. {
  296. // 自身设置为 Movable
  297. this->setFlag(QGraphicsItem::ItemIsMovable, bEnable);
  298. // 所有子线段设置
  299. for (auto& subLine : m_linkLines)
  300. {
  301. subLine->setFlag(QGraphicsItem::ItemIsMovable, bEnable);
  302. }
  303. }
  304. /// <summary>
  305. /// 当Link线段移动时,同步调整其他线段的位置
  306. /// </summary>
  307. /// <param name="item"></param>
  308. void WindowAppItemLink::onLineMove(WindowAppItemLinkLine* moveItem)
  309. {
  310. // qDebug() << "WindowAppItemLink::onLineMove";
  311. QPointF moveLinePt1 = moveItem->mapToScene(moveItem->line().p1());
  312. QPointF moveLinePt2 = moveItem->mapToScene(moveItem->line().p2());
  313. // qDebug() << "moveLinePt1:" << moveLinePt1 << " moveLinePt2:" << moveLinePt2;
  314. // 普通模式(普通模式只允许1、2、3号线移动)
  315. if (m_mode == LINK_MODE::LINK_NORMAL)
  316. {
  317. this->moveNormalLines(moveItem, moveLinePt1, moveLinePt2);
  318. }
  319. // 并行模式(并行模式仅有0号线允许移动)
  320. else
  321. {
  322. this->moveParallelLines(moveItem, moveLinePt1, moveLinePt2);
  323. }
  324. }
  325. /// <summary>
  326. /// 线段被拖动时,同步移动其他线段(普通模式)
  327. /// </summary>
  328. /// <param name="item"></param>
  329. /// <param name="movePt1"></param>
  330. /// <param name="movePt2"></param>
  331. void WindowAppItemLink::moveNormalLines(WindowAppItemLinkLine* item, QPointF movePt1, QPointF movePt2)
  332. {
  333. if (m_linkLines.size() <= 0)
  334. {
  335. return;
  336. }
  337. // 如果移动的是1号线(1号线只允许左右移动)
  338. if (item->m_nLineIndex == 1)
  339. {
  340. // 将0号线的pt2以及2号线的pt1设置成与1号线相同
  341. m_linkLines[0]->setP2(mapFromScene(movePt1));
  342. m_linkLines[2]->setP1(mapFromScene(movePt2));
  343. }
  344. // 如果移动的是2号线(2号线只允许上下移动)
  345. else if (item->m_nLineIndex == 2)
  346. {
  347. // 将1号线的pt2以及3号线的pt1设置成与2号线相同
  348. m_linkLines[1]->setP2(mapFromScene(movePt1));
  349. m_linkLines[3]->setP1(mapFromScene(movePt2));
  350. }
  351. // 如果移动的是3号线(3号线只允许左右移动)
  352. else if (item->m_nLineIndex == 3)
  353. {
  354. // 将2号线的pt2以及4号线的pt1设置成与2号线相同
  355. m_linkLines[2]->setP2(mapFromScene(movePt1));
  356. m_linkLines[4]->setP1(mapFromScene(movePt2));
  357. }
  358. // Error
  359. else
  360. {
  361. }
  362. }
  363. /// <summary>
  364. /// 线段被拖动时,同步移动其他线段(并行模式)
  365. /// </summary>
  366. /// <param name="item"></param>
  367. /// <param name="movePt1"></param>
  368. /// <param name="movePt2"></param>
  369. void WindowAppItemLink::moveParallelLines(WindowAppItemLinkLine* item, QPointF movePt1, QPointF movePt2)
  370. {
  371. Q_UNUSED(item);
  372. Q_UNUSED(movePt1);
  373. // 因为只有 0 号线可以拖动,那么直接调整1号线的长度即可
  374. WindowAppItemLinkLine* ajustLine = m_linkLines.last();
  375. ajustLine->setP1(mapFromScene(movePt2));
  376. // 2022-6-8,此时应该一起调整并行母线的长度
  377. m_startInfItem->updatePostion();
  378. }
  379. /// <summary>
  380. /// 根据起点和终点信息更新连接线段信息(自动方式连接)
  381. /// </summary>
  382. void WindowAppItemLink::updateLinkLinesAuto()
  383. {
  384. if (m_mode == LINK_MODE::LINK_NORMAL)
  385. {
  386. this->updateNormalLines();
  387. }
  388. else
  389. {
  390. this->updateParallelLines();
  391. }
  392. }
  393. /// <summary>
  394. /// 根据移动的功能块进行对应的连接线断调整(手动方式连接)
  395. /// </summary>
  396. /// <param name="pBlock"></param>
  397. /// <param name="bStart"></param>
  398. void WindowAppItemLink::updateLinkLinesManual(QGraphicsItem* pBlock, bool bStart)
  399. {
  400. // qDebug() << "WindowAppItemLink::updateLinkLines " << bStart;
  401. Q_UNUSED(pBlock);
  402. // 如果是普通模式
  403. if (m_mode == LINK_MODE::LINK_NORMAL)
  404. {
  405. // 如果移动的是起点位置的功能块,那么移动0号线和1号线
  406. if (bStart)
  407. {
  408. this->updateNormalLinesByStart();
  409. }
  410. // 如果移动的是终点位置的功能块,那么移动4号线和3号线
  411. else
  412. {
  413. this->updateNormalLinesByEnd();
  414. }
  415. }
  416. // 如果是并行模式
  417. else if( m_mode==LINK_MODE::LINK_PARALLEL)
  418. {
  419. // 如果移动的是起点位置的功能块
  420. if (bStart)
  421. {
  422. this->updateParallelLinesByStart();
  423. }
  424. // 如果移动的是终点位置的功能块
  425. else
  426. {
  427. this->updateParallelLinesByEnd();
  428. }
  429. }
  430. }
  431. ///// <summary>
  432. ///// 按照并行模式更新线段(手动连接模式,功能块拖动时)
  433. ///// </summary>
  434. ///// <param name="pBlock"></param>
  435. //void WindowAppItemLink::updateParallelLines(QGraphicsItem* pBlock)
  436. //{
  437. //
  438. //}
  439. /// <summary>
  440. /// 按照正常模式更新线段(手动连接模式,功能块拖动时)
  441. /// </summary>
  442. /// <param name="pBlock"></param>
  443. void WindowAppItemLink::updateNormalLinesByStart()
  444. {
  445. if (m_linkLines.size() <= 0)
  446. {
  447. return;
  448. }
  449. // 移动0号线和1号线
  450. // 计算0号线
  451. QPointF ptLineStart = m_startInfItem->line().p2();
  452. ptLineStart = mapFromScene(m_startInfItem->mapToScene(ptLineStart));
  453. QPointF ptLineEnd = m_linkLines[0]->line().p2();
  454. // 如果0号线的长度少于了最小长度,则整个线条重置
  455. if (qAbs(ptLineEnd.x() - ptLineStart.x()) < LINK_START_LINE_SIZE)
  456. {
  457. updateLinkLinesAuto();
  458. return;
  459. }
  460. // 否则重新计算0号线的y值
  461. // QPointF ptLineEnd = QPointF(ptLineStart.x() + LINK_START_LINE_SIZE, ptLineStart.y());
  462. ptLineEnd.setY(ptLineStart.y());
  463. m_linkLines[0]->updateLine(ptLineStart, ptLineEnd);
  464. // 然后继续调整1号线
  465. // 调整规则,p2始终不变,只调整p1
  466. m_linkLines[1]->setP1(ptLineEnd);
  467. }
  468. /// <summary>
  469. /// 按照正常模式更新线段(手动连接模式,功能块拖动时)
  470. /// </summary>
  471. /// <param name="pBlock"></param>
  472. void WindowAppItemLink::updateNormalLinesByEnd()
  473. {
  474. if (m_linkLines.size() <= 0)
  475. {
  476. return;
  477. }
  478. // 移动4号线和3号线
  479. // 计算4号线
  480. QPointF ptLineEnd = m_endInfItem->line().p1();
  481. ptLineEnd = mapFromScene(m_endInfItem->mapToScene(ptLineEnd));
  482. QPointF ptLineStart = m_linkLines[4]->line().p1();
  483. // 如果4号线的长度少于了最小长度,则整个线条重置
  484. if (qAbs(ptLineEnd.x() - ptLineStart.x()) < LINK_START_LINE_SIZE)
  485. {
  486. updateNormalLines();
  487. return;
  488. }
  489. // 否则重新计算4号线的y值
  490. ptLineStart.setY(ptLineEnd.y());
  491. m_linkLines[4]->updateLine(ptLineStart, ptLineEnd);
  492. // 然后继续调整3号线
  493. // 调整规则,p1始终不变,只调整p2
  494. m_linkLines[3]->setP2(ptLineStart);
  495. }
  496. /// <summary>
  497. /// 按照并行模式更新线段(手动连接模式,起点功能块拖动时)
  498. /// </summary>
  499. void WindowAppItemLink::updateParallelLinesByStart()
  500. {
  501. if (m_linkLines.size() <= 0)
  502. {
  503. return;
  504. }
  505. // 计算0号线
  506. // 只是调整一下 p1 的y值即可
  507. QPointF ptLineStart = m_linkLines[0]->line().p1();
  508. QPointF ptItem = m_startInfItem->line().p2();
  509. ptItem = mapFromScene(m_startInfItem->mapToScene(ptItem));
  510. ptLineStart.setY(ptItem.ry());
  511. m_linkLines[0]->setP1(ptLineStart);
  512. }
  513. /// <summary>
  514. /// 按照并行模式更新线段(手动连接模式,终点功能块拖动时)
  515. /// </summary>
  516. void WindowAppItemLink::updateParallelLinesByEnd()
  517. {
  518. if (m_linkLines.size() <= 0)
  519. {
  520. return;
  521. }
  522. // 计算1号线
  523. // 需要同时调整1号线和0号线
  524. //
  525. // 计算1号线
  526. QPointF ptLineEnd = m_endInfItem->line().p1();
  527. ptLineEnd = mapFromScene(m_endInfItem->mapToScene(ptLineEnd));
  528. QPointF ptLineStart = m_linkLines[1]->line().p1();
  529. // 如果1号线的长度少于了最小长度,则整个线条重置
  530. if (qAbs(ptLineEnd.x() - ptLineStart.x()) < LINK_START_LINE_SIZE)
  531. {
  532. updateParallelLines();
  533. return;
  534. }
  535. // 否则重新计算1号线的y值
  536. ptLineStart.setY(ptLineEnd.y());
  537. m_linkLines[1]->updateLine(ptLineStart, ptLineEnd);
  538. // 然后继续调整0号线
  539. // 调整规则,p1始终不变,只调整p2
  540. m_linkLines[0]->setP2(ptLineStart);
  541. }