原文: http://zetcode.com/gui/rubyqt/customwidget/

在 Ruby Qt 编程教程的这一部分中,我们将创建一个自定义窗口小部件。

工具箱通常仅提供最常见的窗口小部件,例如按钮,文本窗口小部件,滑块等。没有工具箱可以提供所有可能的窗口小部件。 程序员必须自己创建此类小部件。 他们使用工具箱提供的绘图工具来完成此任务。 有两种可能性。 程序员可以修改或增强现有的小部件。 或者,他可以从头开始创建自定义窗口小部件。

刻录小部件

在下一个示例中,我们将创建一个自定义刻录小部件。 可以在 Nero 或 K3B 之类的应用中看到此小部件。 该小部件将从头开始创建。

  1. #!/usr/bin/ruby
  2. # ZetCode Ruby Qt tutorial
  3. # In this program, we create
  4. # a custom widget
  5. #
  6. # @author jan bodnar
  7. # website zetcode.com
  8. # last modified July 2009
  9. require 'Qt'
  10. PANEL_HEIGHT = 30
  11. DISTANCE = 19
  12. LINE_WIDTH = 5
  13. DIVISIONS = 10
  14. FULL_CAPACITY = 700
  15. MAX_CAPACITY = 750
  16. class Burning < Qt::Widget
  17. def initialize(parent)
  18. super(parent)
  19. @num = [ "75", "150", "225", "300",
  20. "375", "450", "525", "600", "675" ]
  21. @redColor = Qt::Color.new 255, 175, 175
  22. @yellowColor = Qt::Color.new 255, 255, 184
  23. @parent = parent
  24. setMinimumHeight PANEL_HEIGHT
  25. end
  26. def paintEvent event
  27. painter = Qt::Painter.new self
  28. drawWidget painter
  29. painter.end
  30. end
  31. def drawWidget painter
  32. w = width.to_f
  33. slid_width = @parent.getCurrentWidth
  34. step = (w / DIVISIONS).round.to_f
  35. till = ((w / MAX_CAPACITY) * slid_width).to_f
  36. full = ((w / MAX_CAPACITY) * FULL_CAPACITY).to_f
  37. if slid_width > FULL_CAPACITY
  38. painter.setPen @yellowColor
  39. painter.setBrush Qt::Brush.new @yellowColor
  40. painter.drawRect Qt::RectF.new 0, 0, full, PANEL_HEIGHT
  41. painter.setPen @redColor
  42. painter.setBrush Qt::Brush.new @redColor
  43. painter.drawRect Qt::RectF.new full+1, 0, till-full, PANEL_HEIGHT
  44. else
  45. if slid_width > 0
  46. painter.setPen @yellowColor
  47. painter.setBrush Qt::Brush.new @yellowColor
  48. painter.drawRect Qt::RectF.new 0, 0, till, PANEL_HEIGHT
  49. end
  50. end
  51. painter.setPen Qt::Color.new 90, 90, 90
  52. painter.setBrush Qt::NoBrush
  53. painter.drawRect 0, 0, w-1, PANEL_HEIGHT-1
  54. newFont = font
  55. newFont.setPointSize 7
  56. painter.setFont newFont
  57. for i in (1..@num.length)
  58. painter.drawLine Qt::LineF.new i*step, 1, i*step, LINE_WIDTH
  59. metrics = Qt::FontMetrics.new newFont
  60. w = metrics.width @num[i-1]
  61. painter.drawText(Qt::PointF.new(i*step-w/2, DISTANCE), @num[i-1])
  62. end
  63. end
  64. end
  65. class QtApp < Qt::Widget
  66. slots 'onChanged(int)'
  67. def initialize
  68. super
  69. setWindowTitle "The Burning Widget"
  70. initUI
  71. resize 370, 200
  72. move 300, 300
  73. show
  74. end
  75. def initUI
  76. @cur_width = 0
  77. @slider = Qt::Slider.new Qt::Horizontal , self
  78. @slider.setMaximum MAX_CAPACITY
  79. @slider.setGeometry 50, 50, 130, 30
  80. connect(@slider, SIGNAL("valueChanged(int)"), self, SLOT("onChanged(int)"))
  81. vbox = Qt::VBoxLayout.new self
  82. hbox = Qt::HBoxLayout.new
  83. vbox.addStretch 1
  84. @widget = Burning.new self
  85. hbox.addWidget @widget, 0
  86. vbox.addLayout hbox
  87. setLayout vbox
  88. end
  89. def onChanged val
  90. @cur_width = val
  91. @widget.repaint
  92. end
  93. def getCurrentWidth
  94. return @cur_width
  95. end
  96. end
  97. app = Qt::Application.new ARGV
  98. QtApp.new
  99. app.exec

在这个文件中,我们创建了刻录小部件。

  1. class Burning < Qt::Widget

自定义窗口小部件基于Widget小部件。

  1. PANEL_HEIGHT = 30
  2. DISTANCE = 19
  3. LINE_WIDTH = 5
  4. DIVISIONS = 10
  5. FULL_CAPACITY = 700
  6. MAX_CAPACITY = 750

这些是重要的常数。 PANEL_HEIGHT定义自定义窗口小部件的高度。 DISTANCE是比例尺上的数字与其父边框顶部之间的距离。 LINE_WIDTH是垂直线的宽度。 DIVISIONS是秤的数量。 FULL_CAPACITY是媒体的最大容量。 达到目标后,就会发生过度刻录。 这通过红色可视化。 MAX_CAPACITY是介质的最大容量。

  1. @num = [ "75", "150", "225", "300",
  2. "375", "450", "525", "600", "675" ]

我们使用这些数字来构建Burning小部件的比例。

  1. def paintEvent event
  2. painter = Qt::Painter.new self
  3. drawWidget painter
  4. painter.end
  5. end

自定义窗口小部件的图形委托给drawWidget方法。

  1. slid_width = @parent.getCurrentWidth

我们使用它来获取当前选定的滑块值。

  1. w = width.to_f

我们得到小部件的宽度。 自定义窗口小部件的宽度是动态的。 用户可以调整大小。

  1. till = ((w / MAX_CAPACITY) * slid_width).to_f
  2. full = ((w / MAX_CAPACITY) * FULL_CAPACITY).to_f

我们使用w变量进行转换。 在比例尺值和自定义小部件的度量之间。 请注意,我们使用浮点值。 我们在绘图中获得了更高的精度。

  1. painter.setPen @redColor
  2. painter.setBrush Qt::Brush.new @redColor
  3. painter.drawRect Qt::RectF.new full+1, 0, till-full, PANEL_HEIGHT

这三行画出红色矩形,表示过度燃烧。

  1. painter.drawRect 0, 0, w-1, PANEL_HEIGHT-1

这是小部件的外围,即外部矩形。

  1. painter.drawLine Qt::LineF.new i*step, 1, i*step, LINE_WIDTH

在这里,我们画出小的垂直线。

  1. w = metrics.width @num[i-1]
  2. painter.drawText(Qt::PointF.new(i*step-w/2, DISTANCE), @num[i-1])

在这里,我们绘制刻度的数字。 为了精确定位数字,我们必须获得字符串的宽度。

  1. @widget = Burning.new self
  2. hbox.addWidget @widget, 0

我们创建Burning小部件的实例并将其添加到水平框中。

  1. def onChanged val
  2. @cur_width = val
  3. @widget.repaint
  4. end

当滑块的值更改时,我们将其存储在@cur_width变量中,然后重新绘制自定义窗口小部件。

  1. def getCurrentWidth
  2. return @cur_width
  3. end

定制小部件调用此方法以获取实际的滑块值。

Ruby Qt 中的自定义小部件 - 图1

图:刻录小部件

在 Ruby Qt 教程的这一部分中,我们已经演示了如何创建自定义窗口小部件。