c++ 如何在具有圆形边界的QWidget上应用QLinearGradient

efzxgjgh  于 2024-01-09  发布在  其他
关注(0)|答案(2)|浏览(188)

我尝试在QPushButton边框上使用样式表和QLinearGradient来动画计时器进度。
我是这么做的

  1. #include <QApplication>
  2. #include <QPushButton>
  3. #include <QTimer>
  4. int main(int argc, char *argv[])
  5. {
  6. QApplication a(argc, argv);
  7. QPushButton button("Animation Button");
  8. float greenPosition = 0.99;
  9. float whitePosition = 0.01;
  10. QTimer timer;
  11. enum Border {Top = 1, Left = 2, Bottom = 3, Right = 4};
  12. int border = 1;
  13. button.connect(&timer, &QTimer::timeout, [&button, &greenPosition, &whitePosition, &border]()
  14. {
  15. //Left or Bottom
  16. if(border == 2 || border == 3)
  17. {
  18. if(whitePosition + 0.01 > 1)
  19. {
  20. whitePosition = 0;
  21. border = border++ % 4 + 1;
  22. }
  23. whitePosition += 0.01;
  24. }
  25. else
  26. {
  27. if(greenPosition - 0.01 < 0.01)
  28. {
  29. greenPosition = 1;
  30. border = border % 4 + 1;
  31. }
  32. greenPosition -= 0.01;
  33. }
  34. switch (border)
  35. {
  36. case Top:
  37. button.setStyleSheet(QString("border: 2px solid white;"
  38. //"border-radius: 5px;"
  39. "border-top: 2px solid qlineargradient(x0:0, x2:1,"
  40. "stop: 0 green,"
  41. "stop: %1 green,"
  42. "stop: %2 white,"
  43. "stop: 1 white);").arg(greenPosition).arg(greenPosition + 0.01));
  44. break;
  45. case Left:
  46. button.setStyleSheet(QString("border: 2px solid white;"
  47. //"border-radius: 5px;"
  48. "border-left: 2px solid qlineargradient(y0:0, y2:1,"
  49. "stop: 0 white,"
  50. "stop: %1 white,"
  51. "stop: %2 green,"
  52. "stop: 1 green);").arg(whitePosition).arg(whitePosition + 0.01));
  53. break;
  54. case Bottom:
  55. button.setStyleSheet(QString("border: 2px solid white;"
  56. //"border-radius: 5px;"
  57. "border-bottom: 2px solid qlineargradient(x0:0, x2:1,"
  58. "stop: 0 white,"
  59. "stop: %1 white,"
  60. "stop: %2 green,"
  61. "stop: 1 green);").arg(whitePosition).arg(whitePosition + 0.01));
  62. break;
  63. case Right:
  64. button.setStyleSheet(QString("border: 2px solid white;"
  65. //"border-radius: 5px;"
  66. "border-right: 2px solid qlineargradient(y0:0, y2:1,"
  67. "stop: 0 green,"
  68. "stop: %1 green,"
  69. "stop: %2 white,"
  70. "stop: 1 white);").arg(greenPosition).arg(greenPosition + 0.01));
  71. break;
  72. }
  73. });
  74. timer.start(50);
  75. button.show();
  76. return a.exec();
  77. }

字符串
这是我想出的逻辑,来创建这个动画:
greenPositionwhitePosition是控制QLinearGradient中的绿色和白色范围的值,绿色是进度,白色是实际边框颜色。
基本的想法是,我让白色后退,绿色前进,反之亦然。
它们的值之间有一小部分是为了避免梯度效应,因此我添加了0.01。如果greenPositionwhitePosition达到[1.00 - 0.00]范围的限制,它们将重置为默认值。
border是一个变量,它允许我在交换机的情况下遍历4边界,只是一个简单的循环计数器。
所有这些循环都使用QTimer
结果如下:
x1c 0d1x的数据
我需要圆形边框,但当我使用它们时,它看起来像这样:



边框似乎自己形成了按钮的另一面,就像圆形边框一样,按钮现在有8个边。
这是因为圆形边框上的动画似乎与当前正在设置动画的边框同步,而不是在动画到达它们时才设置动画。这看起来也像是一种镜像效果。

**注:**这只是一个观察,以解释它看起来如何,而不是实际发生了什么。

下面是在使用圆形边框时应用不带QLinearGradient的绿色颜色的效果:



如何以与非圆形边界相同的方式设置圆形边界的动画?

flvtvl50

flvtvl501#

由于使用样式表设置边框半径会产生不必要的效果,因此您可以在没有样式表的情况下将小部件边框设置为圆形,并使用paintEvent;方法如下:
你可以画一个圆角矩形,颜色和小部件的父背景一样,这就好像它隐藏了那些尖角,让它们看起来是圆的。
这种方法的一个缺点是它限制了角的圆度,因为如果画家画了一个太圆的矩形,它会掩盖小部件本身或导致尖锐的边缘。
可以通过增加边框大小来稍微解决这个问题,以获得更多的空间,因此,在使用绘图器时可以增加边框半径,而不会破坏小部件边缘。
使用这种方法有一个好处,它可以防止窗口小部件的背景突出边框。
下面是一个从QPushButton派生的子类的例子,它带有一个自定义的paintEvent

  1. class button : public QPushButton
  2. {
  3. Q_OBJECT
  4. public:
  5. button (QWidget *parent = nullptr) : QPushButton(parent) {}
  6. protected:
  7. void paintEvent(QPaintEvent *event) override
  8. {
  9. QPushButton::paintEvent(event);
  10. QRectF r = rect();
  11. r.adjust(-1,-1,+1,+1);
  12. QPainter p(this);
  13. QColor color = parentWidget()->palette().brush(QPalette::Window).color();
  14. p.setPen(QPen(color,2));
  15. p.setRenderHint(QPainter::Antialiasing);
  16. p.drawRoundedRect(r, 6, 6);
  17. }
  18. };

字符串
下面是结果,底部按钮是一个普通的QPushButton,没有边界半径,只是为了增加差异的可见性:
x1c 0d1x的数据

展开查看全部
gajydyqb

gajydyqb2#

对于这些类型的功能,QML提供了一个非常灵活的工具集。
我已经实现了我认为你在QML中寻找的东西:

  1. Canvas {
  2. id: border_animation
  3. property real progress: 0
  4. onProgressChanged: {
  5. border_animation.requestPaint()
  6. }
  7. anchors.centerIn: parent
  8. height: parent.height*0.10
  9. width: parent.width*0.65
  10. z: 2
  11. Text {
  12. text: "start timer"
  13. color: "white"
  14. font.bold: true
  15. font.pointSize: 15
  16. anchors.centerIn: parent
  17. }
  18. NumberAnimation on progress {
  19. id: startTimer
  20. from: 0
  21. to: 1
  22. running: false
  23. duration: 1000
  24. onFinished: {
  25. startTimer.start()
  26. }
  27. }
  28. onPaint: {
  29. var ctx = border_animation.getContext('2d')
  30. ctx.strokeStyle = "green"
  31. ctx.fillStyle = "black"
  32. ctx.lineWidth = 2
  33. ctx.beginPath()
  34. ctx.rect(0,0,width,height)
  35. ctx.fill()
  36. var Lcenterx = width*0.25
  37. var Lcentery = height*0.50
  38. var Rcenterx = width*0.75
  39. var Rcentery = height*0.50
  40. var radius = height*0.40
  41. //each section is 25% of the border so we break it up that way
  42. if(progress<=0.25){
  43. var topProgress = progress/0.25
  44. var rightProgress = 0
  45. var bottomProgress = 0
  46. var leftProgress = 0
  47. }else if(progress<=0.50){
  48. topProgress = 1
  49. rightProgress = (progress-0.25)/0.25
  50. bottomProgress = 0
  51. leftProgress = 0
  52. }else if(progress<=0.75){
  53. topProgress = 1
  54. rightProgress = 1
  55. bottomProgress = (progress-0.50)/0.25
  56. leftProgress = 0
  57. }else{
  58. topProgress = 1
  59. rightProgress = 1
  60. bottomProgress = 1
  61. leftProgress = (progress-0.75)/0.25
  62. }
  63. //top line
  64. ctx.strokeStyle = "orange"
  65. ctx.beginPath();
  66. ctx.moveTo(Lcenterx, Lcentery-radius);
  67. ctx.lineTo(Lcenterx + (Rcenterx - Lcenterx)*topProgress, Rcentery-radius);
  68. ctx.stroke();
  69. ctx.strokeStyle = "yellow"
  70. ctx.beginPath();
  71. ctx.arc(Rcenterx, Rcentery, radius, 1.5*Math.PI, 1.5*Math.PI + Math.PI * rightProgress);
  72. ctx.stroke();
  73. //bottom line
  74. ctx.strokeStyle = "cyan"
  75. ctx.beginPath();
  76. ctx.moveTo(Rcenterx, Lcentery+radius);
  77. ctx.lineTo(Rcenterx - (Rcenterx - Lcenterx)*bottomProgress, Rcentery+radius);
  78. ctx.stroke();
  79. ctx.strokeStyle = "green"
  80. ctx.beginPath();
  81. ctx.arc(Lcenterx, Lcentery, radius, 0.5*Math.PI, 0.5*Math.PI + Math.PI * leftProgress);
  82. ctx.stroke();
  83. }
  84. MouseArea {
  85. anchors.fill: parent
  86. onClicked: {
  87. startTimer.start()
  88. }
  89. }
  90. }

字符串


的数据


展开查看全部

相关问题