Add files from zip
This commit is contained in:
104
examples/oscilloscope/Knob.cpp
Normal file
104
examples/oscilloscope/Knob.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
/*****************************************************************************
|
||||
* Qwt Examples - Copyright (C) 2002 Uwe Rathmann
|
||||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#include "Knob.h"
|
||||
|
||||
#include <QwtMath>
|
||||
#include <QwtKnob>
|
||||
#include <QwtRoundScaleDraw>
|
||||
#include <QwtScaleEngine>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QResizeEvent>
|
||||
#include <qmath.h>
|
||||
|
||||
Knob::Knob( const QString& title, double min, double max, QWidget* parent )
|
||||
: QWidget( parent )
|
||||
{
|
||||
QFont font( "Helvetica", 10 );
|
||||
|
||||
m_knob = new QwtKnob( this );
|
||||
m_knob->setFont( font );
|
||||
|
||||
QwtScaleDiv scaleDiv =
|
||||
m_knob->scaleEngine()->divideScale( min, max, 5, 3 );
|
||||
|
||||
QList< double > ticks = scaleDiv.ticks( QwtScaleDiv::MajorTick );
|
||||
if ( ticks.size() > 0 && ticks[0] > min )
|
||||
{
|
||||
if ( ticks.first() > min )
|
||||
ticks.prepend( min );
|
||||
if ( ticks.last() < max )
|
||||
ticks.append( max );
|
||||
}
|
||||
scaleDiv.setTicks( QwtScaleDiv::MajorTick, ticks );
|
||||
m_knob->setScale( scaleDiv );
|
||||
|
||||
m_knob->setKnobWidth( 50 );
|
||||
|
||||
font.setBold( true );
|
||||
m_label = new QLabel( title, this );
|
||||
m_label->setFont( font );
|
||||
m_label->setAlignment( Qt::AlignTop | Qt::AlignHCenter );
|
||||
|
||||
setSizePolicy( QSizePolicy::MinimumExpanding,
|
||||
QSizePolicy::MinimumExpanding );
|
||||
|
||||
connect( m_knob, SIGNAL(valueChanged(double)),
|
||||
this, SIGNAL(valueChanged(double)) );
|
||||
}
|
||||
|
||||
QSize Knob::sizeHint() const
|
||||
{
|
||||
QSize sz1 = m_knob->sizeHint();
|
||||
QSize sz2 = m_label->sizeHint();
|
||||
|
||||
const int w = qMax( sz1.width(), sz2.width() );
|
||||
const int h = sz1.height() + sz2.height();
|
||||
|
||||
int off = qCeil( m_knob->scaleDraw()->extent( m_knob->font() ) );
|
||||
off -= 15; // spacing
|
||||
|
||||
return QSize( w, h - off );
|
||||
}
|
||||
|
||||
void Knob::setValue( double value )
|
||||
{
|
||||
m_knob->setValue( value );
|
||||
}
|
||||
|
||||
double Knob::value() const
|
||||
{
|
||||
return m_knob->value();
|
||||
}
|
||||
|
||||
void Knob::setTheme( const QColor& color )
|
||||
{
|
||||
m_knob->setPalette( color );
|
||||
}
|
||||
|
||||
QColor Knob::theme() const
|
||||
{
|
||||
return m_knob->palette().color( QPalette::Window );
|
||||
}
|
||||
|
||||
void Knob::resizeEvent( QResizeEvent* event )
|
||||
{
|
||||
const QSize sz = event->size();
|
||||
const QSize hint = m_label->sizeHint();
|
||||
|
||||
m_label->setGeometry( 0, sz.height() - hint.height(),
|
||||
sz.width(), hint.height() );
|
||||
|
||||
const int knobHeight = m_knob->sizeHint().height();
|
||||
|
||||
int off = qCeil( m_knob->scaleDraw()->extent( m_knob->font() ) );
|
||||
off -= 15; // spacing
|
||||
|
||||
m_knob->setGeometry( 0, m_label->pos().y() - knobHeight + off,
|
||||
sz.width(), knobHeight );
|
||||
}
|
||||
|
||||
#include "moc_Knob.cpp"
|
||||
41
examples/oscilloscope/Knob.h
Normal file
41
examples/oscilloscope/Knob.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*****************************************************************************
|
||||
* Qwt Examples - Copyright (C) 2002 Uwe Rathmann
|
||||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QwtGlobal>
|
||||
#include <QWidget>
|
||||
|
||||
class QwtKnob;
|
||||
class QLabel;
|
||||
|
||||
class Knob : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY( QColor theme READ theme WRITE setTheme )
|
||||
|
||||
public:
|
||||
Knob( const QString& title,
|
||||
double min, double max, QWidget* parent = NULL );
|
||||
|
||||
virtual QSize sizeHint() const QWT_OVERRIDE;
|
||||
|
||||
void setValue( double value );
|
||||
double value() const;
|
||||
|
||||
void setTheme( const QColor& );
|
||||
QColor theme() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
double valueChanged( double );
|
||||
|
||||
protected:
|
||||
virtual void resizeEvent( QResizeEvent* ) QWT_OVERRIDE;
|
||||
|
||||
private:
|
||||
QwtKnob* m_knob;
|
||||
QLabel* m_label;
|
||||
};
|
||||
77
examples/oscilloscope/MainWindow.cpp
Normal file
77
examples/oscilloscope/MainWindow.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/*****************************************************************************
|
||||
* Qwt Examples - Copyright (C) 2002 Uwe Rathmann
|
||||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "Plot.h"
|
||||
#include "Knob.h"
|
||||
#include "WheelBox.h"
|
||||
|
||||
#include <QLayout>
|
||||
|
||||
MainWindow::MainWindow( QWidget* parent )
|
||||
: QWidget( parent )
|
||||
{
|
||||
const double intervalLength = 10.0; // seconds
|
||||
|
||||
m_plot = new Plot();
|
||||
m_plot->setIntervalLength( intervalLength );
|
||||
|
||||
m_amplitudeKnob = new Knob( "Amplitude", 0.0, 200.0 );
|
||||
m_amplitudeKnob->setValue( 160.0 );
|
||||
|
||||
m_frequencyKnob = new Knob( "Frequency [Hz]", 0.1, 20.0 );
|
||||
m_frequencyKnob->setValue( 17.8 );
|
||||
|
||||
m_intervalWheel = new WheelBox( "Displayed [s]", 1.0, 100.0, 1.0 );
|
||||
m_intervalWheel->setValue( intervalLength );
|
||||
|
||||
m_timerWheel = new WheelBox( "Sample Interval [ms]", 0.0, 20.0, 0.1 );
|
||||
m_timerWheel->setValue( 10.0 );
|
||||
|
||||
QVBoxLayout* vLayout1 = new QVBoxLayout();
|
||||
vLayout1->addWidget( m_intervalWheel );
|
||||
vLayout1->addWidget( m_timerWheel );
|
||||
vLayout1->addStretch( 10 );
|
||||
vLayout1->addWidget( m_amplitudeKnob );
|
||||
vLayout1->addWidget( m_frequencyKnob );
|
||||
|
||||
QHBoxLayout* layout = new QHBoxLayout( this );
|
||||
layout->addWidget( m_plot, 10 );
|
||||
layout->addLayout( vLayout1 );
|
||||
|
||||
connect( m_amplitudeKnob, SIGNAL(valueChanged(double)),
|
||||
SIGNAL(amplitudeChanged(double)) );
|
||||
|
||||
connect( m_frequencyKnob, SIGNAL(valueChanged(double)),
|
||||
SIGNAL(frequencyChanged(double)) );
|
||||
|
||||
connect( m_timerWheel, SIGNAL(valueChanged(double)),
|
||||
SIGNAL(signalIntervalChanged(double)) );
|
||||
|
||||
connect( m_intervalWheel, SIGNAL(valueChanged(double)),
|
||||
m_plot, SLOT(setIntervalLength(double)) );
|
||||
}
|
||||
|
||||
void MainWindow::start()
|
||||
{
|
||||
m_plot->start();
|
||||
}
|
||||
|
||||
double MainWindow::frequency() const
|
||||
{
|
||||
return m_frequencyKnob->value();
|
||||
}
|
||||
|
||||
double MainWindow::amplitude() const
|
||||
{
|
||||
return m_amplitudeKnob->value();
|
||||
}
|
||||
|
||||
double MainWindow::signalInterval() const
|
||||
{
|
||||
return m_timerWheel->value();
|
||||
}
|
||||
|
||||
#include "moc_MainWindow.cpp"
|
||||
39
examples/oscilloscope/MainWindow.h
Normal file
39
examples/oscilloscope/MainWindow.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*****************************************************************************
|
||||
* Qwt Examples - Copyright (C) 2002 Uwe Rathmann
|
||||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class Plot;
|
||||
class Knob;
|
||||
class WheelBox;
|
||||
|
||||
class MainWindow : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow( QWidget* = NULL );
|
||||
|
||||
void start();
|
||||
|
||||
double amplitude() const;
|
||||
double frequency() const;
|
||||
double signalInterval() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void amplitudeChanged( double );
|
||||
void frequencyChanged( double );
|
||||
void signalIntervalChanged( double );
|
||||
|
||||
private:
|
||||
Knob* m_frequencyKnob;
|
||||
Knob* m_amplitudeKnob;
|
||||
WheelBox* m_timerWheel;
|
||||
WheelBox* m_intervalWheel;
|
||||
|
||||
Plot* m_plot;
|
||||
};
|
||||
297
examples/oscilloscope/Plot.cpp
Normal file
297
examples/oscilloscope/Plot.cpp
Normal file
@@ -0,0 +1,297 @@
|
||||
/*****************************************************************************
|
||||
* Qwt Examples - Copyright (C) 2002 Uwe Rathmann
|
||||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#include "Plot.h"
|
||||
#include "SignalData.h"
|
||||
|
||||
#include <QwtPlotGrid>
|
||||
#include <QwtPlotLayout>
|
||||
#include <QwtPlotCanvas>
|
||||
#include <QwtPlotMarker>
|
||||
#include <QwtPlotCurve>
|
||||
#include <QwtScaleDiv>
|
||||
#include <QwtScaleMap>
|
||||
#include <QwtPlotDirectPainter>
|
||||
#include <QwtPainter>
|
||||
|
||||
#include <QEvent>
|
||||
|
||||
namespace
|
||||
{
|
||||
class Canvas : public QwtPlotCanvas
|
||||
{
|
||||
public:
|
||||
Canvas( QwtPlot* plot = NULL )
|
||||
: QwtPlotCanvas( plot )
|
||||
{
|
||||
/*
|
||||
The backing store is important, when working with widget
|
||||
overlays ( f.e rubberbands for zooming ).
|
||||
Here we don't have them and the internal
|
||||
backing store of QWidget is good enough.
|
||||
*/
|
||||
|
||||
setPaintAttribute( QwtPlotCanvas::BackingStore, false );
|
||||
setBorderRadius( 10 );
|
||||
|
||||
if ( QwtPainter::isX11GraphicsSystem() )
|
||||
{
|
||||
#if QT_VERSION < 0x050000
|
||||
/*
|
||||
Qt::WA_PaintOutsidePaintEvent works on X11 and has a
|
||||
nice effect on the performance.
|
||||
*/
|
||||
|
||||
setAttribute( Qt::WA_PaintOutsidePaintEvent, true );
|
||||
#endif
|
||||
|
||||
/*
|
||||
Disabling the backing store of Qt improves the performance
|
||||
for the direct painter even more, but the canvas becomes
|
||||
a native window of the window system, receiving paint events
|
||||
for resize and expose operations. Those might be expensive
|
||||
when there are many points and the backing store of
|
||||
the canvas is disabled. So in this application
|
||||
we better don't disable both backing stores.
|
||||
*/
|
||||
|
||||
if ( testPaintAttribute( QwtPlotCanvas::BackingStore ) )
|
||||
{
|
||||
setAttribute( Qt::WA_PaintOnScreen, true );
|
||||
setAttribute( Qt::WA_NoSystemBackground, true );
|
||||
}
|
||||
}
|
||||
|
||||
setupPalette();
|
||||
}
|
||||
|
||||
private:
|
||||
void setupPalette()
|
||||
{
|
||||
QPalette pal = palette();
|
||||
|
||||
QLinearGradient gradient;
|
||||
gradient.setCoordinateMode( QGradient::StretchToDeviceMode );
|
||||
gradient.setColorAt( 0.0, QColor( 0, 49, 110 ) );
|
||||
gradient.setColorAt( 1.0, QColor( 0, 87, 174 ) );
|
||||
|
||||
pal.setBrush( QPalette::Window, QBrush( gradient ) );
|
||||
|
||||
// QPalette::WindowText is used for the curve color
|
||||
pal.setColor( QPalette::WindowText, Qt::green );
|
||||
|
||||
setPalette( pal );
|
||||
}
|
||||
};
|
||||
|
||||
class CurveData : public QwtSeriesData< QPointF >
|
||||
{
|
||||
public:
|
||||
const SignalData& values() const
|
||||
{
|
||||
return SignalData::instance();
|
||||
}
|
||||
|
||||
SignalData& values()
|
||||
{
|
||||
return SignalData::instance();
|
||||
}
|
||||
|
||||
virtual QPointF sample( size_t index ) const QWT_OVERRIDE
|
||||
{
|
||||
return SignalData::instance().value( index );
|
||||
}
|
||||
|
||||
virtual size_t size() const QWT_OVERRIDE
|
||||
{
|
||||
return SignalData::instance().size();
|
||||
}
|
||||
|
||||
virtual QRectF boundingRect() const QWT_OVERRIDE
|
||||
{
|
||||
return SignalData::instance().boundingRect();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Plot::Plot( QWidget* parent )
|
||||
: QwtPlot( parent )
|
||||
, m_paintedPoints( 0 )
|
||||
, m_interval( 0.0, 10.0 )
|
||||
, m_timerId( -1 )
|
||||
{
|
||||
m_directPainter = new QwtPlotDirectPainter();
|
||||
|
||||
setAutoReplot( false );
|
||||
setCanvas( new Canvas() );
|
||||
|
||||
plotLayout()->setAlignCanvasToScales( true );
|
||||
|
||||
setAxisTitle( QwtAxis::XBottom, "Time [s]" );
|
||||
setAxisScale( QwtAxis::XBottom, m_interval.minValue(), m_interval.maxValue() );
|
||||
setAxisScale( QwtAxis::YLeft, -200.0, 200.0 );
|
||||
|
||||
QwtPlotGrid* grid = new QwtPlotGrid();
|
||||
grid->setPen( Qt::gray, 0.0, Qt::DotLine );
|
||||
grid->enableX( true );
|
||||
grid->enableXMin( true );
|
||||
grid->enableY( true );
|
||||
grid->enableYMin( false );
|
||||
grid->attach( this );
|
||||
|
||||
m_origin = new QwtPlotMarker();
|
||||
m_origin->setLineStyle( QwtPlotMarker::Cross );
|
||||
m_origin->setValue( m_interval.minValue() + m_interval.width() / 2.0, 0.0 );
|
||||
m_origin->setLinePen( Qt::gray, 0.0, Qt::DashLine );
|
||||
m_origin->attach( this );
|
||||
|
||||
m_curve = new QwtPlotCurve();
|
||||
m_curve->setStyle( QwtPlotCurve::Lines );
|
||||
m_curve->setPen( canvas()->palette().color( QPalette::WindowText ) );
|
||||
m_curve->setRenderHint( QwtPlotItem::RenderAntialiased, true );
|
||||
m_curve->setPaintAttribute( QwtPlotCurve::ClipPolygons, false );
|
||||
m_curve->setData( new CurveData() );
|
||||
m_curve->attach( this );
|
||||
}
|
||||
|
||||
Plot::~Plot()
|
||||
{
|
||||
delete m_directPainter;
|
||||
}
|
||||
|
||||
void Plot::start()
|
||||
{
|
||||
m_elapsedTimer.start();
|
||||
m_timerId = startTimer( 10 );
|
||||
}
|
||||
|
||||
void Plot::replot()
|
||||
{
|
||||
CurveData* curveData = static_cast< CurveData* >( m_curve->data() );
|
||||
curveData->values().lock();
|
||||
|
||||
QwtPlot::replot();
|
||||
m_paintedPoints = curveData->size();
|
||||
|
||||
curveData->values().unlock();
|
||||
}
|
||||
|
||||
void Plot::setIntervalLength( double interval )
|
||||
{
|
||||
if ( interval > 0.0 && interval != m_interval.width() )
|
||||
{
|
||||
m_interval.setMaxValue( m_interval.minValue() + interval );
|
||||
setAxisScale( QwtAxis::XBottom,
|
||||
m_interval.minValue(), m_interval.maxValue() );
|
||||
|
||||
replot();
|
||||
}
|
||||
}
|
||||
|
||||
void Plot::updateCurve()
|
||||
{
|
||||
CurveData* curveData = static_cast< CurveData* >( m_curve->data() );
|
||||
curveData->values().lock();
|
||||
|
||||
const int numPoints = curveData->size();
|
||||
if ( numPoints > m_paintedPoints )
|
||||
{
|
||||
const bool doClip = !canvas()->testAttribute( Qt::WA_PaintOnScreen );
|
||||
if ( doClip )
|
||||
{
|
||||
/*
|
||||
Depending on the platform setting a clip might be an important
|
||||
performance issue. F.e. for Qt Embedded this reduces the
|
||||
part of the backing store that has to be copied out - maybe
|
||||
to an unaccelerated frame buffer device.
|
||||
*/
|
||||
|
||||
const QwtScaleMap xMap = canvasMap( m_curve->xAxis() );
|
||||
const QwtScaleMap yMap = canvasMap( m_curve->yAxis() );
|
||||
|
||||
QRectF br = qwtBoundingRect( *curveData,
|
||||
m_paintedPoints - 1, numPoints - 1 );
|
||||
|
||||
const QRect clipRect = QwtScaleMap::transform( xMap, yMap, br ).toRect();
|
||||
m_directPainter->setClipRegion( clipRect );
|
||||
}
|
||||
|
||||
m_directPainter->drawSeries( m_curve,
|
||||
m_paintedPoints - 1, numPoints - 1 );
|
||||
m_paintedPoints = numPoints;
|
||||
}
|
||||
|
||||
curveData->values().unlock();
|
||||
}
|
||||
|
||||
void Plot::incrementInterval()
|
||||
{
|
||||
m_interval = QwtInterval( m_interval.maxValue(),
|
||||
m_interval.maxValue() + m_interval.width() );
|
||||
|
||||
CurveData* curveData = static_cast< CurveData* >( m_curve->data() );
|
||||
curveData->values().clearStaleValues( m_interval.minValue() );
|
||||
|
||||
// To avoid, that the grid is jumping, we disable
|
||||
// the autocalculation of the ticks and shift them
|
||||
// manually instead.
|
||||
|
||||
QwtScaleDiv scaleDiv = axisScaleDiv( QwtAxis::XBottom );
|
||||
scaleDiv.setInterval( m_interval );
|
||||
|
||||
for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
|
||||
{
|
||||
QList< double > ticks = scaleDiv.ticks( i );
|
||||
for ( int j = 0; j < ticks.size(); j++ )
|
||||
ticks[j] += m_interval.width();
|
||||
scaleDiv.setTicks( i, ticks );
|
||||
}
|
||||
setAxisScaleDiv( QwtAxis::XBottom, scaleDiv );
|
||||
|
||||
m_origin->setValue( m_interval.minValue() + m_interval.width() / 2.0, 0.0 );
|
||||
|
||||
m_paintedPoints = 0;
|
||||
replot();
|
||||
}
|
||||
|
||||
void Plot::timerEvent( QTimerEvent* event )
|
||||
{
|
||||
if ( event->timerId() == m_timerId )
|
||||
{
|
||||
updateCurve();
|
||||
|
||||
const double elapsed = m_elapsedTimer.elapsed() / 1e3;
|
||||
if ( elapsed > m_interval.maxValue() )
|
||||
incrementInterval();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
QwtPlot::timerEvent( event );
|
||||
}
|
||||
|
||||
void Plot::resizeEvent( QResizeEvent* event )
|
||||
{
|
||||
m_directPainter->reset();
|
||||
QwtPlot::resizeEvent( event );
|
||||
}
|
||||
|
||||
void Plot::showEvent( QShowEvent* )
|
||||
{
|
||||
replot();
|
||||
}
|
||||
|
||||
bool Plot::eventFilter( QObject* object, QEvent* event )
|
||||
{
|
||||
if ( object == canvas() &&
|
||||
event->type() == QEvent::PaletteChange )
|
||||
{
|
||||
m_curve->setPen( canvas()->palette().color( QPalette::WindowText ) );
|
||||
}
|
||||
|
||||
return QwtPlot::eventFilter( object, event );
|
||||
}
|
||||
|
||||
#include "moc_Plot.cpp"
|
||||
51
examples/oscilloscope/Plot.h
Normal file
51
examples/oscilloscope/Plot.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*****************************************************************************
|
||||
* Qwt Examples - Copyright (C) 2002 Uwe Rathmann
|
||||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QwtPlot>
|
||||
#include <QwtInterval>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
class QwtPlotCurve;
|
||||
class QwtPlotMarker;
|
||||
class QwtPlotDirectPainter;
|
||||
|
||||
class Plot : public QwtPlot
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Plot( QWidget* = NULL );
|
||||
virtual ~Plot();
|
||||
|
||||
void start();
|
||||
virtual void replot() QWT_OVERRIDE;
|
||||
|
||||
virtual bool eventFilter( QObject*, QEvent* ) QWT_OVERRIDE;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setIntervalLength( double );
|
||||
|
||||
protected:
|
||||
virtual void showEvent( QShowEvent* ) QWT_OVERRIDE;
|
||||
virtual void resizeEvent( QResizeEvent* ) QWT_OVERRIDE;
|
||||
virtual void timerEvent( QTimerEvent* ) QWT_OVERRIDE;
|
||||
|
||||
private:
|
||||
void updateCurve();
|
||||
void incrementInterval();
|
||||
|
||||
QwtPlotMarker* m_origin;
|
||||
QwtPlotCurve* m_curve;
|
||||
int m_paintedPoints;
|
||||
|
||||
QwtPlotDirectPainter* m_directPainter;
|
||||
|
||||
QwtInterval m_interval;
|
||||
int m_timerId;
|
||||
|
||||
QElapsedTimer m_elapsedTimer;
|
||||
};
|
||||
58
examples/oscilloscope/SamplingThread.cpp
Normal file
58
examples/oscilloscope/SamplingThread.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/*****************************************************************************
|
||||
* Qwt Examples - Copyright (C) 2002 Uwe Rathmann
|
||||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#include "SamplingThread.h"
|
||||
#include "SignalData.h"
|
||||
|
||||
#include <QwtMath>
|
||||
#include <qmath.h>
|
||||
|
||||
SamplingThread::SamplingThread( QObject* parent )
|
||||
: QwtSamplingThread( parent )
|
||||
, m_frequency( 5.0 )
|
||||
, m_amplitude( 20.0 )
|
||||
{
|
||||
}
|
||||
|
||||
void SamplingThread::setFrequency( double frequency )
|
||||
{
|
||||
m_frequency = frequency;
|
||||
}
|
||||
|
||||
double SamplingThread::frequency() const
|
||||
{
|
||||
return m_frequency;
|
||||
}
|
||||
|
||||
void SamplingThread::setAmplitude( double amplitude )
|
||||
{
|
||||
m_amplitude = amplitude;
|
||||
}
|
||||
|
||||
double SamplingThread::amplitude() const
|
||||
{
|
||||
return m_amplitude;
|
||||
}
|
||||
|
||||
void SamplingThread::sample( double elapsed )
|
||||
{
|
||||
if ( m_frequency > 0.0 )
|
||||
{
|
||||
const QPointF s( elapsed, value( elapsed ) );
|
||||
SignalData::instance().append( s );
|
||||
}
|
||||
}
|
||||
|
||||
double SamplingThread::value( double timeStamp ) const
|
||||
{
|
||||
const double period = 1.0 / m_frequency;
|
||||
|
||||
const double x = std::fmod( timeStamp, period );
|
||||
const double v = m_amplitude * qFastSin( x / period * 2 * M_PI );
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
#include "moc_SamplingThread.cpp"
|
||||
32
examples/oscilloscope/SamplingThread.h
Normal file
32
examples/oscilloscope/SamplingThread.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*****************************************************************************
|
||||
* Qwt Examples - Copyright (C) 2002 Uwe Rathmann
|
||||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QwtSamplingThread>
|
||||
|
||||
class SamplingThread : public QwtSamplingThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SamplingThread( QObject* parent = NULL );
|
||||
|
||||
double frequency() const;
|
||||
double amplitude() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setAmplitude( double );
|
||||
void setFrequency( double );
|
||||
|
||||
protected:
|
||||
virtual void sample( double elapsed ) QWT_OVERRIDE;
|
||||
|
||||
private:
|
||||
virtual double value( double timeStamp ) const;
|
||||
|
||||
double m_frequency;
|
||||
double m_amplitude;
|
||||
};
|
||||
139
examples/oscilloscope/SignalData.cpp
Normal file
139
examples/oscilloscope/SignalData.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
/*****************************************************************************
|
||||
* Qwt Examples - Copyright (C) 2002 Uwe Rathmann
|
||||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#include "SignalData.h"
|
||||
|
||||
#include <QVector>
|
||||
#include <QMutex>
|
||||
#include <QReadWriteLock>
|
||||
|
||||
class SignalData::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData()
|
||||
: boundingRect( 1.0, 1.0, -2.0, -2.0 ) // invalid
|
||||
{
|
||||
values.reserve( 1000 );
|
||||
}
|
||||
|
||||
inline void append( const QPointF& sample )
|
||||
{
|
||||
values.append( sample );
|
||||
|
||||
// adjust the bounding rectangle
|
||||
|
||||
if ( boundingRect.width() < 0 || boundingRect.height() < 0 )
|
||||
{
|
||||
boundingRect.setRect( sample.x(), sample.y(), 0.0, 0.0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
boundingRect.setRight( sample.x() );
|
||||
|
||||
if ( sample.y() > boundingRect.bottom() )
|
||||
boundingRect.setBottom( sample.y() );
|
||||
|
||||
if ( sample.y() < boundingRect.top() )
|
||||
boundingRect.setTop( sample.y() );
|
||||
}
|
||||
}
|
||||
|
||||
QReadWriteLock lock;
|
||||
|
||||
QVector< QPointF > values;
|
||||
QRectF boundingRect;
|
||||
|
||||
QMutex mutex; // protecting pendingValues
|
||||
QVector< QPointF > pendingValues;
|
||||
};
|
||||
|
||||
SignalData::SignalData()
|
||||
{
|
||||
m_data = new PrivateData();
|
||||
}
|
||||
|
||||
SignalData::~SignalData()
|
||||
{
|
||||
delete m_data;
|
||||
}
|
||||
|
||||
int SignalData::size() const
|
||||
{
|
||||
return m_data->values.size();
|
||||
}
|
||||
|
||||
QPointF SignalData::value( int index ) const
|
||||
{
|
||||
return m_data->values[index];
|
||||
}
|
||||
|
||||
QRectF SignalData::boundingRect() const
|
||||
{
|
||||
return m_data->boundingRect;
|
||||
}
|
||||
|
||||
void SignalData::lock()
|
||||
{
|
||||
m_data->lock.lockForRead();
|
||||
}
|
||||
|
||||
void SignalData::unlock()
|
||||
{
|
||||
m_data->lock.unlock();
|
||||
}
|
||||
|
||||
void SignalData::append( const QPointF& sample )
|
||||
{
|
||||
m_data->mutex.lock();
|
||||
m_data->pendingValues += sample;
|
||||
|
||||
const bool isLocked = m_data->lock.tryLockForWrite();
|
||||
if ( isLocked )
|
||||
{
|
||||
const int numValues = m_data->pendingValues.size();
|
||||
const QPointF* pendingValues = m_data->pendingValues.data();
|
||||
|
||||
for ( int i = 0; i < numValues; i++ )
|
||||
m_data->append( pendingValues[i] );
|
||||
|
||||
m_data->pendingValues.clear();
|
||||
|
||||
m_data->lock.unlock();
|
||||
}
|
||||
|
||||
m_data->mutex.unlock();
|
||||
}
|
||||
|
||||
void SignalData::clearStaleValues( double limit )
|
||||
{
|
||||
m_data->lock.lockForWrite();
|
||||
|
||||
m_data->boundingRect = QRectF( 1.0, 1.0, -2.0, -2.0 ); // invalid
|
||||
|
||||
const QVector< QPointF > values = m_data->values;
|
||||
m_data->values.clear();
|
||||
m_data->values.reserve( values.size() );
|
||||
|
||||
int index;
|
||||
for ( index = values.size() - 1; index >= 0; index-- )
|
||||
{
|
||||
if ( values[index].x() < limit )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( index > 0 )
|
||||
m_data->append( values[index++] );
|
||||
|
||||
while ( index < values.size() - 1 )
|
||||
m_data->append( values[index++] );
|
||||
|
||||
m_data->lock.unlock();
|
||||
}
|
||||
|
||||
SignalData& SignalData::instance()
|
||||
{
|
||||
static SignalData valueVector;
|
||||
return valueVector;
|
||||
}
|
||||
34
examples/oscilloscope/SignalData.h
Normal file
34
examples/oscilloscope/SignalData.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*****************************************************************************
|
||||
* Qwt Examples - Copyright (C) 2002 Uwe Rathmann
|
||||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QRect>
|
||||
|
||||
class SignalData
|
||||
{
|
||||
public:
|
||||
static SignalData& instance();
|
||||
|
||||
void append( const QPointF& pos );
|
||||
void clearStaleValues( double min );
|
||||
|
||||
int size() const;
|
||||
QPointF value( int index ) const;
|
||||
|
||||
QRectF boundingRect() const;
|
||||
|
||||
void lock();
|
||||
void unlock();
|
||||
|
||||
private:
|
||||
SignalData();
|
||||
~SignalData();
|
||||
|
||||
Q_DISABLE_COPY( SignalData )
|
||||
|
||||
class PrivateData;
|
||||
PrivateData* m_data;
|
||||
};
|
||||
131
examples/oscilloscope/WheelBox.cpp
Normal file
131
examples/oscilloscope/WheelBox.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
/*****************************************************************************
|
||||
* Qwt Examples - Copyright (C) 2002 Uwe Rathmann
|
||||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#include "WheelBox.h"
|
||||
|
||||
#include <QwtWheel>
|
||||
#include <QLabel>
|
||||
#include <QLCDNumber>
|
||||
#include <QLayout>
|
||||
#include <QWheelEvent>
|
||||
#include <QApplication>
|
||||
|
||||
namespace
|
||||
{
|
||||
class Wheel : public QwtWheel
|
||||
{
|
||||
public:
|
||||
Wheel( QWidget* parent )
|
||||
: QwtWheel( parent )
|
||||
, m_ignoreWheelEvent( false )
|
||||
{
|
||||
setFocusPolicy( Qt::WheelFocus );
|
||||
parent->installEventFilter( this );
|
||||
}
|
||||
|
||||
virtual bool eventFilter( QObject* object, QEvent* event ) QWT_OVERRIDE
|
||||
{
|
||||
if ( event->type() == QEvent::Wheel && !m_ignoreWheelEvent )
|
||||
{
|
||||
const QWheelEvent* we = static_cast< QWheelEvent* >( event );
|
||||
|
||||
const QPoint pos = wheelRect().center();
|
||||
|
||||
#if QT_VERSION >= 0x050c00
|
||||
QWheelEvent wheelEvent(
|
||||
pos, mapToGlobal( pos ),
|
||||
we->pixelDelta(), we->angleDelta(),
|
||||
we->buttons(), we->modifiers(),
|
||||
we->phase(), we->inverted() );
|
||||
#else
|
||||
QWheelEvent wheelEvent(
|
||||
pos, we->delta(),
|
||||
we->buttons(), we->modifiers(),
|
||||
we->orientation() );
|
||||
#endif
|
||||
|
||||
m_ignoreWheelEvent = true;
|
||||
QApplication::sendEvent( this, &wheelEvent );
|
||||
m_ignoreWheelEvent = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return QwtWheel::eventFilter( object, event );
|
||||
}
|
||||
private:
|
||||
bool m_ignoreWheelEvent;
|
||||
};
|
||||
}
|
||||
|
||||
WheelBox::WheelBox( const QString& title,
|
||||
double min, double max, double stepSize, QWidget* parent )
|
||||
: QWidget( parent )
|
||||
{
|
||||
m_number = new QLCDNumber();
|
||||
m_number->setSegmentStyle( QLCDNumber::Filled );
|
||||
m_number->setAutoFillBackground( true );
|
||||
m_number->setFixedHeight( m_number->sizeHint().height() * 2 );
|
||||
m_number->setFocusPolicy( Qt::WheelFocus );
|
||||
|
||||
QPalette pal( Qt::black );
|
||||
pal.setColor( QPalette::WindowText, Qt::green );
|
||||
m_number->setPalette( pal );
|
||||
|
||||
m_wheel = new Wheel( this );
|
||||
m_wheel->setOrientation( Qt::Vertical );
|
||||
m_wheel->setInverted( true );
|
||||
m_wheel->setRange( min, max );
|
||||
m_wheel->setSingleStep( stepSize );
|
||||
m_wheel->setPageStepCount( 5 );
|
||||
m_wheel->setFixedHeight( m_number->height() );
|
||||
|
||||
m_number->setFocusProxy( m_wheel );
|
||||
|
||||
QFont font( "Helvetica", 10 );
|
||||
font.setBold( true );
|
||||
|
||||
m_label = new QLabel( title );
|
||||
m_label->setFont( font );
|
||||
|
||||
QHBoxLayout* hLayout = new QHBoxLayout;
|
||||
hLayout->setContentsMargins( 0, 0, 0, 0 );
|
||||
hLayout->setSpacing( 2 );
|
||||
hLayout->addWidget( m_number, 10 );
|
||||
hLayout->addWidget( m_wheel );
|
||||
|
||||
QVBoxLayout* vLayout = new QVBoxLayout( this );
|
||||
vLayout->addLayout( hLayout, 10 );
|
||||
vLayout->addWidget( m_label, 0, Qt::AlignTop | Qt::AlignHCenter );
|
||||
|
||||
connect( m_wheel, SIGNAL(valueChanged(double)),
|
||||
m_number, SLOT(display(double)) );
|
||||
|
||||
connect( m_wheel, SIGNAL(valueChanged(double)),
|
||||
this, SIGNAL(valueChanged(double)) );
|
||||
}
|
||||
|
||||
void WheelBox::setTheme( const QColor& color )
|
||||
{
|
||||
m_wheel->setPalette( color );
|
||||
}
|
||||
|
||||
QColor WheelBox::theme() const
|
||||
{
|
||||
return m_wheel->palette().color( QPalette::Window );
|
||||
}
|
||||
|
||||
void WheelBox::setValue( double value )
|
||||
{
|
||||
m_wheel->setValue( value );
|
||||
m_number->display( value );
|
||||
}
|
||||
|
||||
double WheelBox::value() const
|
||||
{
|
||||
return m_wheel->value();
|
||||
}
|
||||
|
||||
#include "moc_WheelBox.cpp"
|
||||
42
examples/oscilloscope/WheelBox.h
Normal file
42
examples/oscilloscope/WheelBox.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*****************************************************************************
|
||||
* Qwt Examples - Copyright (C) 2002 Uwe Rathmann
|
||||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QwtWheel;
|
||||
class QLabel;
|
||||
class QLCDNumber;
|
||||
|
||||
class WheelBox : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY( QColor theme READ theme WRITE setTheme )
|
||||
|
||||
public:
|
||||
WheelBox( const QString& title,
|
||||
double min, double max, double stepSize,
|
||||
QWidget* parent = NULL );
|
||||
|
||||
void setTheme( const QColor& );
|
||||
QColor theme() const;
|
||||
|
||||
void setUnit( const QString& );
|
||||
QString unit() const;
|
||||
|
||||
void setValue( double value );
|
||||
double value() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
double valueChanged( double );
|
||||
|
||||
private:
|
||||
QLCDNumber* m_number;
|
||||
QwtWheel* m_wheel;
|
||||
QLabel* m_label;
|
||||
|
||||
QString m_unit;
|
||||
};
|
||||
44
examples/oscilloscope/main.cpp
Normal file
44
examples/oscilloscope/main.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/*****************************************************************************
|
||||
* Qwt Examples - Copyright (C) 2002 Uwe Rathmann
|
||||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "SamplingThread.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
QApplication app( argc, argv );
|
||||
app.setPalette( Qt::darkGray );
|
||||
|
||||
MainWindow window;
|
||||
window.resize( 800, 400 );
|
||||
|
||||
SamplingThread samplingThread;
|
||||
samplingThread.setFrequency( window.frequency() );
|
||||
samplingThread.setAmplitude( window.amplitude() );
|
||||
samplingThread.setInterval( window.signalInterval() );
|
||||
|
||||
window.connect( &window, SIGNAL(frequencyChanged(double)),
|
||||
&samplingThread, SLOT(setFrequency(double)) );
|
||||
|
||||
window.connect( &window, SIGNAL(amplitudeChanged(double)),
|
||||
&samplingThread, SLOT(setAmplitude(double)) );
|
||||
|
||||
window.connect( &window, SIGNAL(signalIntervalChanged(double)),
|
||||
&samplingThread, SLOT(setInterval(double)) );
|
||||
|
||||
window.show();
|
||||
|
||||
samplingThread.start();
|
||||
window.start();
|
||||
|
||||
const bool ok = app.exec();
|
||||
|
||||
samplingThread.stop();
|
||||
samplingThread.wait( 1000 );
|
||||
|
||||
return ok;
|
||||
}
|
||||
55
examples/oscilloscope/osci.css
Normal file
55
examples/oscilloscope/osci.css
Normal file
@@ -0,0 +1,55 @@
|
||||
MainWindow
|
||||
{
|
||||
border: 1px solid white;
|
||||
border-radius: 20px;
|
||||
padding: 10px;
|
||||
background-color: qlineargradient( x1: 0, y1: 0, x2: 1, y2: 1,
|
||||
stop: 0 #31312C, stop: 0.5 #808080 stop: 1 #31312C );
|
||||
}
|
||||
|
||||
QwtPlotCanvas
|
||||
{
|
||||
border: 1px solid White;
|
||||
border-radius: 10px;
|
||||
background-color: #101010;
|
||||
color: yellow; /* used as curve color */
|
||||
}
|
||||
|
||||
QwtScaleWidget
|
||||
{
|
||||
color: white;
|
||||
}
|
||||
|
||||
WheelBox
|
||||
{
|
||||
qproperty-theme: #878787;
|
||||
}
|
||||
|
||||
QwtWheel
|
||||
{
|
||||
/* background-color: yellow; */
|
||||
qproperty-mass: 0.0;
|
||||
qproperty-tickCount: 5;
|
||||
qproperty-wheelWidth: 15;
|
||||
qproperty-borderWidth: 2;
|
||||
qproperty-wheelBorderWidth: 2;
|
||||
qproperty-wrapping: true;
|
||||
}
|
||||
|
||||
Knob
|
||||
{
|
||||
qproperty-theme: #606060;
|
||||
}
|
||||
|
||||
QwtKnob
|
||||
{
|
||||
qproperty-knobStyle: Sunken;
|
||||
qproperty-markerStyle: Nub;
|
||||
qproperty-markerSize: 8;
|
||||
qproperty-borderWidth: 2;
|
||||
}
|
||||
|
||||
QLCDNumber
|
||||
{
|
||||
color: yellow;
|
||||
}
|
||||
25
examples/oscilloscope/oscilloscope.pro
Normal file
25
examples/oscilloscope/oscilloscope.pro
Normal file
@@ -0,0 +1,25 @@
|
||||
######################################################################
|
||||
# Qwt Examples - Copyright (C) 2002 Uwe Rathmann
|
||||
# This file may be used under the terms of the 3-clause BSD License
|
||||
######################################################################
|
||||
|
||||
include( $${PWD}/../examples.pri )
|
||||
|
||||
TARGET = oscilloscope
|
||||
|
||||
HEADERS = \
|
||||
SignalData.h \
|
||||
Plot.h \
|
||||
Knob.h \
|
||||
WheelBox.h \
|
||||
SamplingThread.h \
|
||||
MainWindow.h
|
||||
|
||||
SOURCES = \
|
||||
SignalData.cpp \
|
||||
Plot.cpp \
|
||||
Knob.cpp \
|
||||
WheelBox.cpp \
|
||||
SamplingThread.cpp \
|
||||
MainWindow.cpp \
|
||||
main.cpp
|
||||
Reference in New Issue
Block a user