# QtJambi 中的自定义小部件

> 原文： [http://zetcode.com/gui/qtjambi/customwidget/](http://zetcode.com/gui/qtjambi/customwidget/)

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

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

## 刻录小部件

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

`Burning.java`

```java
package com.zetcode;

import com.trolltech.qt.core.QPointF;
import com.trolltech.qt.core.QRectF;
import com.trolltech.qt.gui.QBrush;
import com.trolltech.qt.gui.QColor;
import com.trolltech.qt.gui.QFont;
import com.trolltech.qt.gui.QFontMetrics;
import com.trolltech.qt.gui.QLineF;
import com.trolltech.qt.gui.QPaintEvent;
import com.trolltech.qt.gui.QPainter;
import com.trolltech.qt.gui.QWidget;

public class Burning extends QWidget {

    private final int PANEL_HEIGHT = 30;
    private final int DISTANCE = 19;
    private final int LINE_WIDTH = 5;
    private final int DIVISIONS = 10;
    private final float FULL_CAPACITY = 700f;
    private final float MAX_CAPACITY = 750f;
    private final QColor redColor = new QColor(255, 175, 175);
    private final QColor yellowColor = new QColor(255, 255, 184);

    private QWidget parent;
    private String num[] = {
        "75", "150", "225", "300",
        "375", "450", "525", "600",
        "675"
    };

    public Burning(QWidget parent) {
        super(parent);

        this.parent = parent;
        setMinimumHeight(PANEL_HEIGHT);
    }

    @Override
    protected void paintEvent(QPaintEvent event) {

        QPainter painter = new QPainter(this);

        drawWidget(painter);
        painter.end();
    }

    protected void drawWidget(QPainter painter) {

        JambiApp burn = (JambiApp) parent;

        float width = size().width();        
        float slid_width = burn.getCurrentWidth();
        float step = width / DIVISIONS;

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

        if (slid_width > FULL_CAPACITY) {

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

        } else {
            if (slid_width > 0) {
               painter.setPen(yellowColor);
               painter.setBrush(yellowColor);
               painter.drawRect(new QRectF(0, 0, till, PANEL_HEIGHT));
            }
        }

        painter.setPen(new QColor(90, 90, 90));
        painter.setBrush(QBrush.NoBrush);
        painter.drawRect(0, 0, size().width()-1, PANEL_HEIGHT-1);

        QFont newFont = font();
        newFont.setPointSize(7);
        painter.setFont(newFont);

        for (int i = 1; i <= num.length; i++) {
            painter.drawLine(new QLineF(i*step, 1, i*step, LINE_WIDTH));

            QFontMetrics metrics = new QFontMetrics(newFont);

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

        }        
    }
}

```

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

```java
public class Burning extends QWidget {

```

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

```java
private final int PANEL_HEIGHT = 30;
private final int DISTANCE = 19;
private final int LINE_WIDTH = 5;
private final int DIVISIONS = 10;
private final float FULL_CAPACITY = 700f;
private final float MAX_CAPACITY = 750f;

```

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

```java
private String num[] = {
    "75", "150", "225", "300",
    "375", "450", "525", "600",
    "675"
};

```

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

```java
@Override
protected void paintEvent(QPaintEvent event) {

    QPainter painter = new QPainter(this);

    drawWidget(painter);
    painter.end();
}

```

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

```java
JambiApp burn = (JambiApp) parent;

```

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

```java
float slid_width = burn.getCurrentWidth();

```

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

```java
float width = size().width();

```

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

```java
float till = (width / MAX_CAPACITY) * slid_width;
float full = (width / MAX_CAPACITY) * FULL_CAPACITY;

```

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

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

```

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

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

```

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

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

```

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

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

```

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

`JambiApp.java`

```java
package com.zetcode;

import com.trolltech.qt.core.Qt;
import com.trolltech.qt.gui.QApplication;
import com.trolltech.qt.gui.QFrame;
import com.trolltech.qt.gui.QHBoxLayout;
import com.trolltech.qt.gui.QSlider;
import com.trolltech.qt.gui.QVBoxLayout;
import com.trolltech.qt.gui.QWidget;

/**
 * ZetCode QtJambi tutorial
 *
 * In this program, we create
 * a custom widget
 *
 * @author jan bodnar
 * website zetcode.com
 * last modified March 2009
 */

public class JambiApp extends QFrame {

    private final int MAX_CAPACITY = 750;

    QSlider slider;
    QWidget widget;
    int cur_width;

    public JambiApp() {
        setWindowTitle("The Burning Widget");

        initUI();

        resize(370, 200);
        move(300, 300);
        show();
    }

    private void initUI() {

       slider = new QSlider(Qt.Orientation.Horizontal , this);
       slider.setMaximum(MAX_CAPACITY);
       slider.setGeometry(50, 50, 130, 30);

       slider.valueChanged.connect(this, "valueChanged(int)");

       QVBoxLayout vbox = new QVBoxLayout(this);
       QHBoxLayout hbox = new QHBoxLayout();

       vbox.addStretch(1);

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

       vbox.addLayout(hbox);

       setLayout(vbox);
    }

    public void valueChanged(int val) {
        cur_width = val;
        widget.repaint();
    }

    public int getCurrentWidth() {
      return cur_width;
    }

    public static void main(String[] args) {
        QApplication.initialize(args);
        new JambiApp();
        QApplication.exec();
    }
}

```

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

```java
widget = new Burning(this);
hbox.addWidget(widget, 0);

```

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

```java
public void valueChanged(int val) {
    cur_width = val;
    widget.repaint();
}

```

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

```java
public int getCurrentWidth() {
  return cur_width;
}

```

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

![The Burning widget](img/d59ddf85ead4b941bf957c570a19309c.jpg)

图：刻录小部件

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