📄 qwt_dial.cpp
字号:
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/#include <math.h>#include <qpainter.h>#include <qpixmap.h>#include "qwt_math.h"#include "qwt_paint_buffer.h"#include "qwt_painter.h"#include "qwt_dial_needle.h"#include "qwt_dial.h"double QwtDial::d_previousDir = -1.0;/*! Constructor \param parent Parent dial widget*/QwtDialScaleDraw::QwtDialScaleDraw(QwtDial *parent): d_parent(parent), d_penWidth(1), d_visibleLabels(TRUE){}/*! En/disable labels If labels are disabled, QwtDialScaleDraw::label returns always QString::null. Otherwise it calls QwtDial::scaleLabel of the parent dial. \sa QwtDialScaleDraw::visibleLabels*/void QwtDialScaleDraw::showLabels(bool enable){ d_visibleLabels = enable;}/*! Return wether to display labels. \sa QwtDialScaleDraw::showLabels*/bool QwtDialScaleDraw::visibleLabels() const{ return d_visibleLabels;}/*! Set the pen width used for painting the scale \param penWidth Pen width \sa penWidth(), QwtDial::drawScale()*/ void QwtDialScaleDraw::setPenWidth(uint penWidth){ d_penWidth = penWidth;}/*! \return Pen width used for painting the scale \sa setPenWidth, QwtDial::drawScale()*/uint QwtDialScaleDraw::penWidth() const{ return d_penWidth;}/*! Call QwtDial::scaleLabel of the parent dial widget. \param value Value to display \sa QwtDial::scaleLabel*/ QString QwtDialScaleDraw::label(double value) const{ if ( !d_visibleLabels ) return NULL; if ( d_parent == NULL ) return QwtScaleDraw::label(value); return d_parent->scaleLabel(value);}/*! \brief Constructor \param parent Parent widget \param name Widget name Create a dial widget with no scale and no needle. The default origin is 90.0 with no valid value. It accepts mouse and keyboard inputs and has no step size. The default mode is QwtDial::RotateNeedle.*/ QwtDial::QwtDial(QWidget* parent, const char* name): QwtSliderBase(Qt::Horizontal, parent, name, WRepaintNoErase|WResizeNoErase), d_visibleBackground(FALSE), d_frameShadow(Sunken), d_lineWidth(0), d_mode(RotateNeedle), d_origin(90.0), d_minScaleArc(0.0), d_maxScaleArc(0.0), d_scaleDraw(0), d_maxMajIntv(36), d_maxMinIntv(10), d_scaleStep(0.0), d_needle(0){ setBackgroundMode(QWidget::NoBackground); setFocusPolicy(QWidget::TabFocus); QPalette p = palette(); for ( int i = 0; i < QPalette::NColorGroups; i++ ) { const QPalette::ColorGroup cg = (QPalette::ColorGroup)i; // Base: background color of the circle inside the frame. // Foreground: background color of the circle inside the scale p.setColor(cg, QColorGroup::Foreground, p.color(cg, QColorGroup::Base)); } setPalette(p); d_scaleDraw = new QwtDialScaleDraw(this); d_scaleDraw->setGeometry(0, 0, 0, QwtScaleDraw::Round); setScaleArc(0.0, 360.0); // scale as a full circle setRange(0.0, 360.0, 1.0, 10); // degrees as deafult}//! DestructorQwtDial::~QwtDial() { delete d_scaleDraw; delete d_needle;}/*! Show/Hide the area outside of the frame \param show Show if TRUE, hide if FALSE \sa QwtDial::hasVisibleBackground, QWidget::setMask \warning When QwtDial is a toplevel widget the window border might disappear too.*/void QwtDial::showBackground(bool show){ if ( d_visibleBackground != show ) { d_visibleBackground = show; if ( d_visibleBackground ) clearMask(); else setMask(QRegion(boundingRect(), QRegion::Ellipse)); update(); }}/*! TRUE when the area outside of the frame is visible \sa QwtDial::showBackground, QWidget::setMask*/bool QwtDial::hasVisibleBackground() const { return d_visibleBackground; }/*! Sets the frame shadow value from the frame style. \param shadow Frame shadow \sa QwtDial::setLineWidth, QFrame::setFrameShadow*/void QwtDial::setFrameShadow(Shadow shadow){ if ( shadow != d_frameShadow ) { d_frameShadow = shadow; if ( lineWidth() > 0 ) update(); }}/*! \return Frame shadow /sa QwtDial::setFrameShadow, QwtDial::lineWidth, QFrame::frameShadow*/QwtDial::Shadow QwtDial::frameShadow() const { return d_frameShadow; }/*! Sets the line width \param lineWidth Line width \sa QwtDial::setFrameShadow*/void QwtDial::setLineWidth(int lineWidth){ if ( lineWidth < 0 ) lineWidth = 0; if ( d_lineWidth != lineWidth ) { d_lineWidth = lineWidth; update(); }}/*! \return Line width of the frame \sa QwtDial::setLineWidth, QwtDial::frameShadow, QFrame::lineWidth*/int QwtDial::lineWidth() const { return d_lineWidth; }/*! \return bounding rect of the circle inside the frame \sa QwtDial::setLineWidth, QwtDial::scaleContentsRect, QwtDial::boundingRect*/QRect QwtDial::contentsRect() const{ const int lw = lineWidth(); QRect r = boundingRect(); if ( lw > 0 ) { r.setRect(r.x() + lw, r.y() + lw, r.width() - 2 * lw, r.height() - 2 * lw); } return r;}/*! \return bounding rect of the dial including the frame \sa QwtDial::setLineWidth, QwtDial::scaleContentsRect, QwtDial::contentsRect*/QRect QwtDial::boundingRect() const{ const int radius = QMIN(width(), height()) / 2; QRect r(0, 0, 2 * radius, 2 * radius); r.moveCenter(rect().center()); return r;}/*! \return rect inside the scale \sa setLineWidth, QwtDial::boundingRect, QwtDial::contentsRect*/QRect QwtDial::scaleContentsRect() const{ const QPen scalePen(colorGroup().text(), 0, NoPen); int scaleDist = 0; if ( d_scaleDraw ) { scaleDist = QMAX( d_scaleDraw->maxWidth(scalePen, fontMetrics()), d_scaleDraw->maxHeight(scalePen, fontMetrics())); scaleDist++; // margin } const QRect rect = contentsRect(); return QRect(rect.x() + scaleDist, rect.y() + scaleDist, rect.width() - 2 * scaleDist, rect.height() - 2 * scaleDist);}/*! \brief Change the mode of the meter. \param mode New mode The value of the meter is indicated by the difference between north of the scale and the direction of the needle. In case of QwtDial::RotateNeedle north is pointing to the origin() and the needle is rotating, in case of QwtDial::RotateScale, the needle points to origin() and the scale is rotating. The default mode is QwtDial::RotateNeedle. \sa QwtDial::mode, QwtDial::setValue, QwtDial::setOrigin*/ void QwtDial::setMode(Mode mode){ if ( mode != d_mode ) { d_mode = mode; update(); }} /*! \return mode of the dial. The value of the dial is indicated by the difference between the origin and the direction of the needle. In case of QwtDial::RotateNeedle the scale arc is fixed to the origin() and the needle is rotating, in case of QwtDial::RotateScale, the needle points to origin() and the scale is rotating. The default mode is QwtDial::RotateNeedle. \sa QwtDial::setMode, QwtDial::origin, QwtDial::setScaleArc, QwtDial::value*/QwtDial::Mode QwtDial::mode() const{ return d_mode;}/*! Sets whether it is possible to step the value from the highest value to the lowest value and vice versa to on. \param wrapping en/disables wrapping \sa QwtDial::wrapping, QwtDblRange::periodic \note The meaning of wrapping is like the wrapping property of QSpinBox, but not like it is used in QDial. */void QwtDial::setWrapping(bool wrapping){ setPeriodic(wrapping);} /*! wrapping() holds whether it is possible to step the value from the highest value to the lowest value and vice versa. \sa QwtDial::setWrapping, QwtDblRange::setPeriodic \note The meaning of wrapping is like the wrapping property of QSpinBox, but not like it is used in QDial. */ bool QwtDial::wrapping() const{ return periodic();}//! Resize the dial widgetvoid QwtDial::resizeEvent(QResizeEvent *e){ QWidget::resizeEvent(e); if ( !hasVisibleBackground() ) setMask(QRegion(boundingRect(), QRegion::Ellipse));}//! Repaint the dial void QwtDial::paintEvent(QPaintEvent *e){ const QRect &ur = e->rect(); if ( ur.isValid() ) { QwtPaintBuffer paintBuffer(this, ur); QPainter *painter = paintBuffer.painter(); drawContents(painter); drawFrame(painter); if ( hasFocus() ) drawFocusIndicator(painter); }}/*! Draw a dotted round circle, if !isReadOnly() \param painter Painter*/void QwtDial::drawFocusIndicator(QPainter *painter) const{ if ( !isReadOnly() ) { QRect focusRect = contentsRect(); const int margin = 2; focusRect.setRect( focusRect.x() + margin, focusRect.y() + margin, focusRect.width() - 2 * margin, focusRect.height() - 2 * margin); QColor color = colorGroup().color(QColorGroup::Base); if (color.isValid()) { int h, s, v; color.hsv(&h, &s, &v); color = (v > 128) ? Qt::gray.dark(120) : Qt::gray.light(120); } else color = Qt::darkGray; painter->save(); painter->setBrush(Qt::NoBrush); painter->setPen(QPen(color, 0, Qt::DotLine)); painter->drawEllipse(focusRect); painter->restore(); }}/*! Draw the frame around the dial \param painter Painter \sa QwtDial::lineWidth, QwtDial::frameShadow*/void QwtDial::drawFrame(QPainter *painter){ const int lw = lineWidth(); const int off = (lw + 1) % 2; QRect r = boundingRect(); r.setRect(r.x() + lw / 2 - off, r.y() + lw / 2 - off, r.width() - lw + off + 1, r.height() - lw + off + 1); if ( lw > 0 ) { switch(d_frameShadow) { case QwtDial::Raised: QwtPainter::drawRoundFrame(painter, r, lw, colorGroup(), FALSE); break; case QwtDial::Sunken: QwtPainter::drawRoundFrame(painter, r, lw, colorGroup(), TRUE); break; default: // Plain { painter->save(); painter->setPen(QPen(Qt::black, lw)); painter->setBrush(Qt::NoBrush); painter->drawEllipse(r); painter->restore(); } } }}/*! \brief Draw the contents inside the frame QColorGroup::Background is the background color outside of the frame. QColorGroup::Base is the background color inside the frame. QColorGroup::Foreground is the background color inside the scale. \param painter Painter \sa QwtDial::boundingRect, QwtDial::contentsRect, QwtDial::scaleContentsRect, QWidget::setPalette*/void QwtDial::drawContents(QPainter *painter) const{ if ( backgroundMode() == QWidget::NoBackground || colorGroup().brush(QColorGroup::Base) != colorGroup().brush(QColorGroup::Background) ) { // Don磘 use QPainter::drawEllipse. There are some pixels // different compared to the region in the mask, leaving // them in background color. painter->save(); painter->setPen(NoPen); painter->setBrush(colorGroup().brush(QColorGroup::Base)); // Even if we want to fill the contentsRect only, we fill the // complete boundingRect. The frame will be painted later // above, but we want to have the base color below it // because round objects doesn磘 cover all pixels. QRect br = boundingRect();#if QT_VERSION < 300#ifdef _WS_WIN32_ // Qt-230-NC draws ellipses not as nicely as Qt-2.3.x on X Windows br.setTop(br.top()-1); br.setLeft(br.left()-1); br.setBottom(br.bottom()+1); br.setRight(br.right()+1);#endif#endif painter->setClipRegion(QRegion(painter->xForm(br), QRegion::Ellipse)); painter->drawRect(br); painter->restore(); } const QRect insideScaleRect = scaleContentsRect(); if ( colorGroup().brush(QColorGroup::Foreground) != colorGroup().brush(QColorGroup::Base) ) { painter->save(); painter->setPen(NoPen); painter->setBrush(colorGroup().brush(QColorGroup::Foreground)); painter->setClipRegion( QRegion(painter->xForm(insideScaleRect), QRegion::Ellipse)); painter->drawRect(insideScaleRect); painter->restore(); } const QPoint center = insideScaleRect.center(); const int radius = insideScaleRect.width() / 2; painter->save(); drawScaleContents(painter, center, radius); painter->restore(); double direction = d_origin; if (isValid()) { direction = d_origin + d_minScaleArc; if ( maxValue() > minValue() && d_maxScaleArc > d_minScaleArc ) { const double ratio = (value() - minValue()) / (maxValue() - minValue()); direction += ratio * (d_maxScaleArc - d_minScaleArc); } if ( direction >= 360.0 ) direction -= 360.0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -