当前位置:   article > 正文

Qt 实现类似 Python turtle 海龟绘图的动画效果_qt python turtle

qt python turtle

1966年,Seymour Papert 和 Wally Feurzig 发明了一种专门给儿童学习编程的语言——LOGO 语言,它的特色就是通过编程指挥一个小海龟(turtle)在屏幕上绘图。海龟绘图(Turtle Graphics)后来被移植到各种高级语言中,Python内置了 turtle 库,基本上完整复制了原始 Turtle Graphics 的所有功能。

海龟绘图的特点就是以动画的形式绘制出图案,这比直接展示最终图案更有趣。

要在 Qt 中实现这种动画效果,我的思路就是通过定时器刷新当前进度,然后根据进度来决定绘制哪一部分。趁着假期无聊就写了个简易版本的,可以画直线和圆弧,以及填充路径,后面有空再完善下。

代码链接:https://github.com/gongjianbo/QtTurtle

效果展示:

调用代码:

  1. drawPainter.begin(QPointF(300,200));
  2. drawPainter.beginFill(QColor(0,100,0));
  3. drawPainter.setPenWidth(2);
  4. drawPainter.setPenColor(QColor(0,150,0));
  5. drawPainter.arc(QPointF(200,200),100,0,180);
  6. drawPainter.arc(QPointF(400,100),318,-161,53);
  7. drawPainter.arc(QPointF(200,100),318,-72,53);
  8. drawPainter.arc(QPointF(400,200),100,0,180);
  9. drawPainter.endFill();
  10. drawPainter.end();

核心部分就是每一步操作就 new 一个对象,绘制时遍历这些对象,遍历过程中超出当前进度就 break,等定时器 timeout 时进度会增加并再次遍历绘制。

部分代码:

  1. #include "MyPainter.h"
  2. #include <QtMath>
  3. #include <QDebug>
  4. MyPainter::MyPainter(QObject *parent) : QObject(parent)
  5. {
  6. timer=new QTimer(this);
  7. connect(timer,&QTimer::timeout,this,[=]{
  8. drawLength+=10;
  9. update();
  10. //时长超过表示线条绘制完了
  11. if(drawEnd)
  12. timer->stop();
  13. });
  14. }
  15. MyPainter::~MyPainter()
  16. {
  17. qDeleteAll(dataList);
  18. dataList.clear();
  19. }
  20. void MyPainter::draw(QPaintDevice *device)
  21. {
  22. if(drawLength<=0)
  23. return;
  24. QPainter painter(device);
  25. //目前没有设置路径填充规则 TODO
  26. qint64 progress_temp=0;
  27. int i=0;
  28. for(i=0;i<dataList.count()&&progress_temp<drawLength;i++)
  29. {
  30. double len=drawLength-progress_temp;
  31. AbstractElement* item=dataList[i];
  32. //判断begin和end fill,执行到endfill才开始填充begin中的路径
  33. switch (item->type()) {
  34. case 3:
  35. {
  36. const int ele_index=static_cast<BeginFillElement*>(item)->index();
  37. if(drawEndIndex>=ele_index){
  38. item->draw(&painter,0);
  39. }
  40. }
  41. break;
  42. case 4:
  43. drawEndIndex=static_cast<EndFillElement*>(item)->index();
  44. break;
  45. default:
  46. item->draw(&painter,len>item->length()?1:len/item->length());
  47. break;
  48. }
  49. //len不够就是还没画完,后面的就不画了
  50. if(len<item->length())
  51. break;
  52. progress_temp+=item->length();
  53. }
  54. drawEnd=bool(i>=dataList.count()&&progress_temp>=dataLength);
  55. }
  56. void MyPainter::start()
  57. {
  58. timer->start(timerInterval);
  59. drawLength=0;
  60. drawEndIndex=-1;
  61. drawEnd=false;
  62. startTime=QTime::currentTime();
  63. }
  64. void MyPainter::begin(const QPointF &pos)
  65. {
  66. //begin为路径规划开始,状态复位
  67. currentPos=pos;
  68. dataLength=0;
  69. dataList.clear();
  70. }
  71. void MyPainter::end()
  72. {
  73. //end暂无操作
  74. }
  75. void MyPainter::setPenColor(const QColor &color)
  76. {
  77. PenColorElement *ele=new PenColorElement(color);
  78. dataList.push_back(ele);
  79. }
  80. void MyPainter::setPenWidth(int width)
  81. {
  82. PenWidthElement *ele=new PenWidthElement(width);
  83. dataList.push_back(ele);
  84. }
  85. void MyPainter::beginFill(const QColor &color)
  86. {
  87. //开始填充后,beginElement!=null,path在别的函数判断中就能追加路径
  88. fillBeginIndex++;
  89. fillBeginPath=QPainterPath();
  90. fillBeginPath.moveTo(currentPos);
  91. fillBeginElement=new BeginFillElement(fillBeginIndex,color);
  92. dataList.push_back(fillBeginElement);
  93. }
  94. void MyPainter::endFill()
  95. {
  96. if(fillBeginElement){
  97. //end后路径就完成了
  98. fillBeginElement->setFillPath(fillBeginPath);
  99. EndFillElement *ele=new EndFillElement(fillBeginIndex);
  100. dataList.push_back(ele);
  101. fillBeginElement=nullptr;
  102. }
  103. }
  104. void MyPainter::moveTo(const QPointF &pos)
  105. {
  106. if(fillBeginElement){
  107. fillBeginPath.moveTo(pos);
  108. }
  109. currentPos=pos;
  110. }
  111. void MyPainter::lineTo(const QPointF &pos)
  112. {
  113. if(fillBeginElement){
  114. fillBeginPath.lineTo(pos);
  115. }
  116. LineElement *ele=new LineElement(QLineF(currentPos,pos));
  117. dataList.push_back(ele);
  118. dataLength+=ele->length();
  119. currentPos=pos;
  120. }
  121. void MyPainter::arc(const QPointF &center, int radius, int startAngle, int spanAngle)
  122. {
  123. QRectF ele_rect=QRectF(center.x()-radius,center.y()-radius,
  124. radius*2,radius*2);
  125. if(fillBeginElement){
  126. //const int len=std::ceil(std::abs(spanAngle)*M_PI*radius/180.0);
  127. fillBeginPath.arcTo(ele_rect,startAngle,spanAngle);
  128. }
  129. ArcElement *ele=new ArcElement(ele_rect,startAngle,spanAngle);
  130. dataList.push_back(ele);
  131. dataLength+=ele->length();
  132. //currentPos=stop;
  133. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/874167?site
推荐阅读
相关标签
  

闽ICP备14008679号