QT控件大全 三十三 QRoundProgressBar

来源:互联网 发布:php时间戳转换年月日 编辑:程序博客网 时间:2024/06/09 23:50

效果如图:


核心代码:

#ifndef QROUNDPROGRESSBAR_H#define QROUNDPROGRESSBAR_H#include <QWidget>/** * @brief The QRoundProgressBar class represents a circular progress bar and maintains its API * similar to the *QProgressBar*. * * ### Styles * QRoundProgressBar currently supports Donut, Pie, Expand and Line styles. See setBarStyle() for more details. * * ### Colors * Generally QRoundProgressBar uses its palette and font attributes to define how it will look. * * The following \a QPalette members are considered: * - *QPalette::Window*   background of the whole widget (normally should be set to Qt::NoBrush) * - *QPalette::Base*     background of the non-filled progress bar area (should be set to Qt::NoBrush to make it transparent) * - *QPalette::AlternateBase*  background of the central circle where the text is shown (for \a Donut style) * - *QPalette::Shadow*         foreground of the non-filled progress bar area (i.e. border color) * - *QPalette::Highlight*      background of the filled progress bar area * - *QPalette::Text*           color of the text shown in the center * * Create a \a QPalette with given attributes and apply it via `setPalette()`. * * ### Color gradient * \a Donut, \a Expand and \a Pie styles allow to use color gradient for currernt value area instead of plain brush fill. * See setDataColors() for more details. * * ### Value text * Value text is generally drawn inside the QRoundProgressBar using its `font()` and \a QPalette::Text role from its `palette()`. * * To define pattern of the text, use setFormat() function (see Qt's \a QProgressBar for more details). * * To define number of decimals to be shown, use setDecimals() function. * * ### Font * To use own font for value text, apply it via `setFont()`. * * By default, font size will be adjusted automatically to fit the inner circle of the widget. */class QRoundProgressBar : public QWidget{    Q_OBJECTpublic:        explicit QRoundProgressBar(QWidget *parent = 0);    static const int PositionLeft = 180;    static const int PositionTop = 90;    static const int PositionRight = 0;    static const int PositionBottom = -90;    /**     * @brief Return position (in degrees) of minimum value.     * \sa setNullPosition     */    double nullPosition() const { return m_nullPosition; }    /**     * @brief Defines position of minimum value.     * @param position position on the circle (in degrees) of minimum value     * \sa nullPosition     */    void setNullPosition(double position);    /**     * @brief The BarStyle enum defines general look of the progress bar.     */    enum BarStyle    {        /// Donut style (filled torus around the text)        StyleDonut,        /// Pie style (filled pie segment with the text in center)        StylePie,        /// Line style (thin round line around the text)        StyleLine,        /// Expand style (circle filled from inside to outline)        StyleExpand    };    /**     * @brief Sets visual style of the widget.     * \sa barStyle     */    void setBarStyle(BarStyle style);    /**     * @brief Returns current progree bar style.     * \sa setBarStyle     */    BarStyle barStyle() const { return m_barStyle; }    /**     * @brief Sets width of the outline circle pen.     * @param penWidth width of the outline circle pen (in pixels)     */    void setOutlinePenWidth(double penWidth);    /**     * @brief Returns width of the outline circle pen.     */    double outlinePenWidth() const { return m_outlinePenWidth; }    /**     * @brief Sets width of the data circle pen.     * @param penWidth width of the data circle pen (in pixels)     */    void setDataPenWidth(double penWidth);    /**     * @brief Returns width of the data circle pen.     */    double dataPenWidth() const { return m_dataPenWidth; }    /**     * @brief Sets colors of the visible data and makes gradient brush from them.     * Gradient colors can be set for \a Donut and \a Pie styles (see setBarStyle() function).     *     * *Warning*: this function will override widget's `palette()` to set dynamically created gradient brush.     *     * @param stopPoints List of colors (should have at least 2 values, see Qt's \a QGradientStops for more details).     * Color value at point 0 corresponds to the minimum() value, while color value at point 1     * corresponds to the maximum(). Other colors will be distributed accordingly to the defined ranges (see setRange()).     */    void setDataColors(const QGradientStops& stopPoints);    /**     * @brief Defines the string used to generate the current text.     * If no format is set, no text will be shown.     * @param format see \a QProgressBar's format description     * \sa setDecimals     */    void setFormat(const QString& format);    /**     * @brief Sets format string to empty string. No text will be shown therefore.     * See setFormat() for more information.     */    void resetFormat();    /**     * @brief Returns the string used to generate the current text.     */    QStringformat() const { return m_format; }    /**     * @brief Sets number of decimals to show after the comma (default is 1).     * \sa setFormat     */    void setDecimals(int count);    /**     * @brief Returns number of decimals to show after the comma (default is 1).     * \sa setFormat, setDecimals     */    int decimals() const { return m_decimals; }    /**     * @brief Returns current value shown on the widget.     * \sa setValue()     */    double value() const { return m_value; }    /**     * @brief Returns minimum of the allowed value range.     * \sa setMinimum, setRange     */    double minimum() const { return m_min; }    /**     * @brief Returns maximum of the allowed value range.    * \sa setMaximum, setRange     */    double maximum() const { return m_max; }public Q_SLOTS:    /**     * @brief Defines minimum und maximum of the allowed value range.     * If the current value does not fit into the range, it will be automatically adjusted.     * @param min minimum of the allowed value range     * @param max maximum of the allowed value range     */    void setRange(double min, double max);    /**     * @brief Defines minimum of the allowed value range.     * If the current value does not fit into the range, it will be automatically adjusted.     * @param min minimum of the allowed value range     * \sa setRange     */    void setMinimum(double min);    /**     * @brief Defines maximum of the allowed value range.     * If the current value does not fit into the range, it will be automatically adjusted.     * @param max maximum of the allowed value range     * \sa setRange     */    void setMaximum(double max);    /**     * @brief Sets a value which will be shown on the widget.     * @param val must be between minimum() and maximum()     */    void setValue(double val);    /**     * @brief Integer version of the previous slot.     * @param val must be between minimum() and maximum()     */    void setValue(int val);protected:    virtual void paintEvent(QPaintEvent *event);    virtual void drawBackground(QPainter& p, const QRectF& baseRect);    virtual void drawBase(QPainter& p, const QRectF& baseRect);    virtual void drawValue(QPainter& p, const QRectF& baseRect, double value, double delta);    virtual void calculateInnerRect(const QRectF& baseRect, double outerRadius, QRectF& innerRect, double& innerRadius);    virtual void drawInnerBackground(QPainter& p, const QRectF& innerRect);    virtual void drawText(QPainter& p, const QRectF& innerRect, double innerRadius, double value);    virtual QString valueToText(double value) const;    virtual void valueFormatChanged();    virtual QSize minimumSizeHint() const { return QSize(32,32); }    virtual bool hasHeightForWidth() const { return true; }    virtual int heightForWidth(int w) const { return w; }    void rebuildDataBrushIfNeeded();    double m_min, m_max;    double m_value;    double m_nullPosition;    BarStyle m_barStyle;    double m_outlinePenWidth, m_dataPenWidth;    QGradientStops m_gradientData;    bool m_rebuildBrush;    QString m_format;    int m_decimals;    static const int UF_VALUE = 1;    static const int UF_PERCENT = 2;    static const int UF_MAX = 4;    int m_updateFlags;};#endif // QROUNDPROGRESSBAR_H
#include "QRoundProgressBar.h"#include <QtGui/QPainter>QRoundProgressBar::QRoundProgressBar(QWidget *parent) :    QWidget(parent),    m_min(0), m_max(100),    m_value(25),    m_nullPosition(PositionTop),    m_barStyle(StyleDonut),    m_outlinePenWidth(1),    m_dataPenWidth(1),    m_rebuildBrush(false),    m_format("%p%"),    m_decimals(1),    m_updateFlags(UF_PERCENT){}void QRoundProgressBar::setRange(double min, double max){    m_min = min;    m_max = max;    if (m_max < m_min)        qSwap(m_max, m_min);    if (m_value < m_min)        m_value = m_min;    else if (m_value > m_max)        m_value = m_max;    m_rebuildBrush = true;    update();}void QRoundProgressBar::setMinimum(double min){    setRange(min, m_max);}void QRoundProgressBar::setMaximum(double max){    setRange(m_min, max);}void QRoundProgressBar::setValue(double val){    if (m_value != val)    {        if (val < m_min)            m_value = m_min;        else if (val > m_max)            m_value = m_max;        else            m_value = val;        update();    }}void QRoundProgressBar::setValue(int val){    setValue(double(val));}void QRoundProgressBar::setNullPosition(double position){    if (position != m_nullPosition)    {        m_nullPosition = position;        m_rebuildBrush = true;        update();    }}void QRoundProgressBar::setBarStyle(QRoundProgressBar::BarStyle style){    if (style != m_barStyle)    {        m_barStyle = style;        m_rebuildBrush = true;        update();    }}void QRoundProgressBar::setOutlinePenWidth(double penWidth){    if (penWidth != m_outlinePenWidth)    {        m_outlinePenWidth = penWidth;        update();    }}void QRoundProgressBar::setDataPenWidth(double penWidth){    if (penWidth != m_dataPenWidth)    {        m_dataPenWidth = penWidth;        update();    }}void QRoundProgressBar::setDataColors(const QGradientStops &stopPoints){    if (stopPoints != m_gradientData)    {        m_gradientData = stopPoints;        m_rebuildBrush = true;        update();    }}void QRoundProgressBar::setFormat(const QString &format){    if (format != m_format)    {        m_format = format;        valueFormatChanged();    }}void QRoundProgressBar::resetFormat(){    m_format = QString::null;    valueFormatChanged();}void QRoundProgressBar::setDecimals(int count){    if (count >= 0 && count != m_decimals)    {        m_decimals = count;        valueFormatChanged();    }}void QRoundProgressBar::paintEvent(QPaintEvent* /*event*/){    double outerRadius = qMin(width(), height());    QRectF baseRect(1, 1, outerRadius-2, outerRadius-2);    QImage buffer(outerRadius, outerRadius, QImage::Format_ARGB32_Premultiplied);    QPainter p(&buffer);    p.setRenderHint(QPainter::Antialiasing);    // data brush    rebuildDataBrushIfNeeded();    // background    drawBackground(p, buffer.rect());    // base circle    drawBase(p, baseRect);    // data circle    double delta = (m_max - m_min) / (m_value - m_min);    drawValue(p, baseRect, m_value, delta);    // center circle    double innerRadius(0);    QRectF innerRect;    calculateInnerRect(baseRect, outerRadius, innerRect, innerRadius);    drawInnerBackground(p, innerRect);    // text    drawText(p, innerRect, innerRadius, m_value);    // finally draw the bar    p.end();    QPainter painter(this);    painter.fillRect(baseRect, palette().background());    painter.drawImage(0,0, buffer);}void QRoundProgressBar::drawBackground(QPainter &p, const QRectF &baseRect){    p.fillRect(baseRect, palette().background());}void QRoundProgressBar::drawBase(QPainter &p, const QRectF &baseRect){    switch (m_barStyle)    {    case StyleDonut:        p.setPen(QPen(palette().shadow().color(), m_outlinePenWidth));        p.setBrush(palette().base());        p.drawEllipse(baseRect);        break;    case StylePie:    case StyleExpand:        p.setPen(QPen(palette().base().color(), m_outlinePenWidth));        p.setBrush(palette().base());        p.drawEllipse(baseRect);        break;    case StyleLine:        p.setPen(QPen(palette().base().color(), m_outlinePenWidth));        p.setBrush(Qt::NoBrush);        p.drawEllipse(baseRect.adjusted(m_outlinePenWidth/2, m_outlinePenWidth/2, -m_outlinePenWidth/2, -m_outlinePenWidth/2));        break;    default:;    }}void QRoundProgressBar::drawValue(QPainter &p, const QRectF &baseRect, double value, double delta){    // nothing to draw    if (value == m_min)        return;    // for Expand style    if (m_barStyle == StyleExpand)    {        p.setBrush(palette().highlight());        p.setPen(QPen(palette().shadow().color(), m_dataPenWidth));        double radius = (baseRect.height() / 2) / delta;        p.drawEllipse(baseRect.center(), radius, radius);        return;    }    // for Line style    if (m_barStyle == StyleLine)    {        p.setPen(QPen(palette().highlight().color(), m_dataPenWidth));        p.setBrush(Qt::NoBrush);        if (value == m_max)        {            p.drawEllipse(                baseRect.adjusted(m_outlinePenWidth/2, m_outlinePenWidth/2, -m_outlinePenWidth/2, -m_outlinePenWidth/2));        }        else        {            double arcLength = 360.0 / delta;            p.drawArc(                baseRect.adjusted(m_outlinePenWidth/2, m_outlinePenWidth/2, -m_outlinePenWidth/2, -m_outlinePenWidth/2),                m_nullPosition * 16,                -arcLength * 16);        }        return;    }    // for Pie and Donut styles    QPainterPath dataPath;    dataPath.setFillRule(Qt::WindingFill);    // pie segment outer    if (value == m_max)    {        dataPath.addEllipse(baseRect);    }    else    {        double arcLength = 360.0 / delta;        dataPath.moveTo(baseRect.center());        dataPath.arcTo(baseRect, m_nullPosition, -arcLength);        dataPath.lineTo(baseRect.center());    }    p.setBrush(palette().highlight());    p.setPen(QPen(palette().shadow().color(), m_dataPenWidth));    p.drawPath(dataPath);}void QRoundProgressBar::calculateInnerRect(const QRectF &/*baseRect*/, double outerRadius, QRectF &innerRect, double &innerRadius){    // for Line and Expand styles    if (m_barStyle == StyleLine || m_barStyle == StyleExpand)    {        innerRadius = outerRadius - m_outlinePenWidth;    }    else    // for Pie and Donut styles    {        innerRadius = outerRadius * 0.75;    }    double delta = (outerRadius - innerRadius) / 2;    innerRect = QRectF(delta, delta, innerRadius, innerRadius);}void QRoundProgressBar::drawInnerBackground(QPainter &p, const QRectF &innerRect){    if (m_barStyle == StyleDonut)    {        p.setBrush(palette().alternateBase());        p.drawEllipse(innerRect);    }}void QRoundProgressBar::drawText(QPainter &p, const QRectF &innerRect, double innerRadius, double value){    if (m_format.isEmpty())        return;    // !!! to revise    QFont f(font());    f.setPixelSize(10);    QFontMetricsF fm(f);    double maxWidth = fm.width(valueToText(m_max));    double delta = innerRadius / maxWidth;    double fontSize = f.pixelSize() * delta * 0.75;    f.setPixelSize(fontSize);    //f.setPixelSize(innerRadius * qMax(0.05, (0.5 - (double)m_decimals * 0.2)));    p.setFont(f);    QRectF textRect(innerRect);    p.setPen(palette().text().color());    p.drawText(textRect, Qt::AlignCenter, valueToText(value));}QString QRoundProgressBar::valueToText(double value) const{    QString textToDraw(m_format);    if (m_updateFlags & UF_VALUE)        textToDraw.replace("%v", QString::number(value, 'f', m_decimals));    if (m_updateFlags & UF_PERCENT)    {        double procent = (value - m_min) / (m_max - m_min) * 100.0;        textToDraw.replace("%p", QString::number(procent, 'f', m_decimals));    }    if (m_updateFlags & UF_MAX)        textToDraw.replace("%m", QString::number(m_max - m_min + 1, 'f', m_decimals));    return textToDraw;}void QRoundProgressBar::valueFormatChanged(){    m_updateFlags = 0;    if (m_format.contains("%v"))        m_updateFlags |= UF_VALUE;    if (m_format.contains("%p"))        m_updateFlags |= UF_PERCENT;    if (m_format.contains("%m"))        m_updateFlags |= UF_MAX;    update();}void QRoundProgressBar::rebuildDataBrushIfNeeded(){    if (!m_rebuildBrush)        return;    if (m_gradientData.isEmpty())        return;    if (m_barStyle == StyleLine)        return;    m_rebuildBrush = false;    QPalette p(palette());    if (m_barStyle == StyleExpand)    {        QRadialGradient dataBrush(0.5,0.5, 0.5, 0.5,0.5);        dataBrush.setCoordinateMode(QGradient::StretchToDeviceMode);        // set colors        for (int i = 0; i < m_gradientData.count(); i++)            dataBrush.setColorAt(m_gradientData.at(i).first, m_gradientData.at(i).second);        p.setBrush(QPalette::Highlight, dataBrush);    }    else    {        QConicalGradient dataBrush(QPointF(0.5,0.5), m_nullPosition);        dataBrush.setCoordinateMode(QGradient::StretchToDeviceMode);        // invert colors        for (int i = 0; i < m_gradientData.count(); i++)            dataBrush.setColorAt(1.0 - m_gradientData.at(i).first, m_gradientData.at(i).second);        p.setBrush(QPalette::Highlight, dataBrush);    }    setPalette(p);}

源码工程:qq:609162385





原创粉丝点击