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

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

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

刻录小部件

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

Burning.java

  1. package com.zetcode;
  2. import com.trolltech.qt.core.QPointF;
  3. import com.trolltech.qt.core.QRectF;
  4. import com.trolltech.qt.gui.QBrush;
  5. import com.trolltech.qt.gui.QColor;
  6. import com.trolltech.qt.gui.QFont;
  7. import com.trolltech.qt.gui.QFontMetrics;
  8. import com.trolltech.qt.gui.QLineF;
  9. import com.trolltech.qt.gui.QPaintEvent;
  10. import com.trolltech.qt.gui.QPainter;
  11. import com.trolltech.qt.gui.QWidget;
  12. public class Burning extends QWidget {
  13. private final int PANEL_HEIGHT = 30;
  14. private final int DISTANCE = 19;
  15. private final int LINE_WIDTH = 5;
  16. private final int DIVISIONS = 10;
  17. private final float FULL_CAPACITY = 700f;
  18. private final float MAX_CAPACITY = 750f;
  19. private final QColor redColor = new QColor(255, 175, 175);
  20. private final QColor yellowColor = new QColor(255, 255, 184);
  21. private QWidget parent;
  22. private String num[] = {
  23. "75", "150", "225", "300",
  24. "375", "450", "525", "600",
  25. "675"
  26. };
  27. public Burning(QWidget parent) {
  28. super(parent);
  29. this.parent = parent;
  30. setMinimumHeight(PANEL_HEIGHT);
  31. }
  32. @Override
  33. protected void paintEvent(QPaintEvent event) {
  34. QPainter painter = new QPainter(this);
  35. drawWidget(painter);
  36. painter.end();
  37. }
  38. protected void drawWidget(QPainter painter) {
  39. JambiApp burn = (JambiApp) parent;
  40. float width = size().width();
  41. float slid_width = burn.getCurrentWidth();
  42. float step = width / DIVISIONS;
  43. float till = (width / MAX_CAPACITY) * slid_width;
  44. float full = (width / MAX_CAPACITY) * FULL_CAPACITY;
  45. if (slid_width > FULL_CAPACITY) {
  46. painter.setPen(yellowColor);
  47. painter.setBrush(yellowColor);
  48. painter.drawRect(new QRectF(0, 0, full, PANEL_HEIGHT));
  49. painter.setPen(redColor);
  50. painter.setBrush(redColor);
  51. painter.drawRect(new QRectF(full+1, 0, till-full, PANEL_HEIGHT));
  52. } else {
  53. if (slid_width > 0) {
  54. painter.setPen(yellowColor);
  55. painter.setBrush(yellowColor);
  56. painter.drawRect(new QRectF(0, 0, till, PANEL_HEIGHT));
  57. }
  58. }
  59. painter.setPen(new QColor(90, 90, 90));
  60. painter.setBrush(QBrush.NoBrush);
  61. painter.drawRect(0, 0, size().width()-1, PANEL_HEIGHT-1);
  62. QFont newFont = font();
  63. newFont.setPointSize(7);
  64. painter.setFont(newFont);
  65. for (int i = 1; i <= num.length; i++) {
  66. painter.drawLine(new QLineF(i*step, 1, i*step, LINE_WIDTH));
  67. QFontMetrics metrics = new QFontMetrics(newFont);
  68. int w = metrics.width(num[i-1]);
  69. painter.drawText(new QPointF(i*step-w/2, DISTANCE), num[i-1]);
  70. }
  71. }
  72. }

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

  1. public class Burning extends QWidget {

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

  1. private final int PANEL_HEIGHT = 30;
  2. private final int DISTANCE = 19;
  3. private final int LINE_WIDTH = 5;
  4. private final int DIVISIONS = 10;
  5. private final float FULL_CAPACITY = 700f;
  6. private final float MAX_CAPACITY = 750f;

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

  1. private String num[] = {
  2. "75", "150", "225", "300",
  3. "375", "450", "525", "600",
  4. "675"
  5. };

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

  1. @Override
  2. protected void paintEvent(QPaintEvent event) {
  3. QPainter painter = new QPainter(this);
  4. drawWidget(painter);
  5. painter.end();
  6. }

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

  1. JambiApp burn = (JambiApp) parent;

我们检索对父窗口小部件的引用。

  1. float slid_width = burn.getCurrentWidth();

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

  1. float width = size().width();

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

  1. float till = (width / MAX_CAPACITY) * slid_width;
  2. float full = (width / MAX_CAPACITY) * FULL_CAPACITY;

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

  1. painter.setPen(redColor);
  2. painter.setBrush(redColor);
  3. painter.drawRect(new QRectF(full+1, 0, till-full, PANEL_HEIGHT));

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

  1. painter.drawRect(0, 0, size().width()-1, PANEL_HEIGHT-1);

这是小部件的周长。 外部矩形。

  1. painter.drawLine(new QLineF(i*step, 1, i*step, LINE_WIDTH));

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

  1. int w = metrics.width(num[i-1]);
  2. painter.drawText(new QPointF(i*step-w/2, 19), num[i-1]);

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

JambiApp.java

  1. package com.zetcode;
  2. import com.trolltech.qt.core.Qt;
  3. import com.trolltech.qt.gui.QApplication;
  4. import com.trolltech.qt.gui.QFrame;
  5. import com.trolltech.qt.gui.QHBoxLayout;
  6. import com.trolltech.qt.gui.QSlider;
  7. import com.trolltech.qt.gui.QVBoxLayout;
  8. import com.trolltech.qt.gui.QWidget;
  9. /**
  10. * ZetCode QtJambi tutorial
  11. *
  12. * In this program, we create
  13. * a custom widget
  14. *
  15. * @author jan bodnar
  16. * website zetcode.com
  17. * last modified March 2009
  18. */
  19. public class JambiApp extends QFrame {
  20. private final int MAX_CAPACITY = 750;
  21. QSlider slider;
  22. QWidget widget;
  23. int cur_width;
  24. public JambiApp() {
  25. setWindowTitle("The Burning Widget");
  26. initUI();
  27. resize(370, 200);
  28. move(300, 300);
  29. show();
  30. }
  31. private void initUI() {
  32. slider = new QSlider(Qt.Orientation.Horizontal , this);
  33. slider.setMaximum(MAX_CAPACITY);
  34. slider.setGeometry(50, 50, 130, 30);
  35. slider.valueChanged.connect(this, "valueChanged(int)");
  36. QVBoxLayout vbox = new QVBoxLayout(this);
  37. QHBoxLayout hbox = new QHBoxLayout();
  38. vbox.addStretch(1);
  39. widget = new Burning(this);
  40. hbox.addWidget(widget, 0);
  41. vbox.addLayout(hbox);
  42. setLayout(vbox);
  43. }
  44. public void valueChanged(int val) {
  45. cur_width = val;
  46. widget.repaint();
  47. }
  48. public int getCurrentWidth() {
  49. return cur_width;
  50. }
  51. public static void main(String[] args) {
  52. QApplication.initialize(args);
  53. new JambiApp();
  54. QApplication.exec();
  55. }
  56. }

这是主文件。 在这里,我们创建滑块小部件并使用我们的自定义小部件。

  1. widget = new Burning(this);
  2. hbox.addWidget(widget, 0);

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

  1. public void valueChanged(int val) {
  2. cur_width = val;
  3. widget.repaint();
  4. }

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

  1. public int getCurrentWidth() {
  2. return cur_width;
  3. }

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

QtJambi 中的自定义小部件 - 图1

图:刻录小部件

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