├── .gitignore ├── README.md ├── VirsualOscilloscope.pro ├── VirsualOscilloscope.pro.user ├── curvedata.cpp ├── curvedata.h ├── knob.cpp ├── knob.h ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── osci.css ├── plot.cpp ├── plot.h ├── qwt.prf ├── qwtconfig.pri ├── qwtfunctions.pri ├── samplingthread.cpp ├── samplingthread.h ├── signaldata.cpp ├── signaldata.h ├── wheelbox.cpp ├── wheelbox.h └── 虚拟示波器分析.vsdx /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VirtualOscilloscope_Qt 2 | 基于Qt的虚拟示波器 3 | -------------------------------------------------------------------------------- /VirsualOscilloscope.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2016-08-11T19:52:52 4 | # 5 | #------------------------------------------------- 6 | include ( ${PWD}/../qwt.prf ) 7 | 8 | INCLUDEPATH += X:\Qt\Qt5.7.0.MinGW530\5.7\mingw53_32\include\Qwt 9 | 10 | QT += core gui 11 | 12 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 13 | 14 | TARGET = VirsualOscilloscope 15 | TEMPLATE = app 16 | 17 | HEADERS = \ 18 | signaldata.h \ 19 | plot.h \ 20 | knob.h \ 21 | wheelbox.h \ 22 | samplingthread.h \ 23 | curvedata.h \ 24 | mainwindow.h 25 | 26 | SOURCES = \ 27 | signaldata.cpp \ 28 | plot.cpp \ 29 | knob.cpp \ 30 | wheelbox.cpp \ 31 | samplingthread.cpp \ 32 | curvedata.cpp \ 33 | mainwindow.cpp \ 34 | main.cpp 35 | -------------------------------------------------------------------------------- /VirsualOscilloscope.pro.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {b668c7ee-9c8a-46a6-b73e-742172d4ec89} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 0 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | CppGlobal 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | true 45 | 0 46 | 8 47 | true 48 | 1 49 | true 50 | true 51 | true 52 | false 53 | 54 | 55 | 56 | ProjectExplorer.Project.PluginSettings 57 | 58 | 59 | 60 | ProjectExplorer.Project.Target.0 61 | 62 | Desktop Qt 5.7.0 MinGW 32bit 63 | Desktop Qt 5.7.0 MinGW 32bit 64 | qt.57.win32_mingw53_kit 65 | 0 66 | 0 67 | 0 68 | 69 | D:/QtProject/VirsualScilloscope/build-VirsualOscilloscope-Desktop_Qt_5_7_0_MinGW_32bit-Debug 70 | 71 | 72 | true 73 | qmake 74 | 75 | QtProjectManager.QMakeBuildStep 76 | true 77 | 78 | false 79 | false 80 | false 81 | 82 | 83 | true 84 | Make 85 | 86 | Qt4ProjectManager.MakeStep 87 | 88 | false 89 | -j 90 | 91 | 92 | 2 93 | 构建 94 | 95 | ProjectExplorer.BuildSteps.Build 96 | 97 | 98 | 99 | true 100 | Make 101 | 102 | Qt4ProjectManager.MakeStep 103 | 104 | true 105 | clean 106 | 107 | 108 | 1 109 | 清理 110 | 111 | ProjectExplorer.BuildSteps.Clean 112 | 113 | 2 114 | false 115 | 116 | Debug 117 | 118 | Qt4ProjectManager.Qt4BuildConfiguration 119 | 2 120 | true 121 | 122 | 123 | D:/QtProject/VirsualScilloscope/build-VirsualOscilloscope-Desktop_Qt_5_7_0_MinGW_32bit-Release 124 | 125 | 126 | true 127 | qmake 128 | 129 | QtProjectManager.QMakeBuildStep 130 | false 131 | 132 | false 133 | false 134 | false 135 | 136 | 137 | true 138 | Make 139 | 140 | Qt4ProjectManager.MakeStep 141 | 142 | false 143 | -j 144 | 145 | 146 | 2 147 | 构建 148 | 149 | ProjectExplorer.BuildSteps.Build 150 | 151 | 152 | 153 | true 154 | Make 155 | 156 | Qt4ProjectManager.MakeStep 157 | 158 | true 159 | clean 160 | 161 | 162 | 1 163 | 清理 164 | 165 | ProjectExplorer.BuildSteps.Clean 166 | 167 | 2 168 | false 169 | 170 | Release 171 | 172 | Qt4ProjectManager.Qt4BuildConfiguration 173 | 0 174 | true 175 | 176 | 177 | D:/QtProject/VirsualScilloscope/build-VirsualOscilloscope-Desktop_Qt_5_7_0_MinGW_32bit-Profile 178 | 179 | 180 | true 181 | qmake 182 | 183 | QtProjectManager.QMakeBuildStep 184 | true 185 | 186 | false 187 | true 188 | false 189 | 190 | 191 | true 192 | Make 193 | 194 | Qt4ProjectManager.MakeStep 195 | 196 | false 197 | 198 | 199 | 200 | 2 201 | 构建 202 | 203 | ProjectExplorer.BuildSteps.Build 204 | 205 | 206 | 207 | true 208 | Make 209 | 210 | Qt4ProjectManager.MakeStep 211 | 212 | true 213 | clean 214 | 215 | 216 | 1 217 | 清理 218 | 219 | ProjectExplorer.BuildSteps.Clean 220 | 221 | 2 222 | false 223 | 224 | Profile 225 | 226 | Qt4ProjectManager.Qt4BuildConfiguration 227 | 0 228 | true 229 | 230 | 3 231 | 232 | 233 | 0 234 | 部署 235 | 236 | ProjectExplorer.BuildSteps.Deploy 237 | 238 | 1 239 | 在本地部署 240 | 241 | ProjectExplorer.DefaultDeployConfiguration 242 | 243 | 1 244 | 245 | 246 | false 247 | false 248 | 1000 249 | 250 | true 251 | 252 | false 253 | false 254 | false 255 | false 256 | true 257 | 0.01 258 | 10 259 | true 260 | 1 261 | 25 262 | 263 | 1 264 | true 265 | false 266 | true 267 | valgrind 268 | 269 | 0 270 | 1 271 | 2 272 | 3 273 | 4 274 | 5 275 | 6 276 | 7 277 | 8 278 | 9 279 | 10 280 | 11 281 | 12 282 | 13 283 | 14 284 | 285 | 2 286 | 287 | VirsualOscilloscope 288 | VirsualOscilloscope2 289 | Qt4ProjectManager.Qt4RunConfiguration:D:/QtProject/VirsualScilloscope/VirtualOscilloscope_Qt/VirsualOscilloscope.pro 290 | true 291 | 292 | VirsualOscilloscope.pro 293 | false 294 | 295 | D:/QtProject/VirsualScilloscope/build-VirsualOscilloscope-Desktop_Qt_5_7_0_MinGW_32bit-Debug 296 | 3768 297 | false 298 | true 299 | false 300 | false 301 | true 302 | 303 | 1 304 | 305 | 306 | 307 | ProjectExplorer.Project.TargetCount 308 | 1 309 | 310 | 311 | ProjectExplorer.Project.Updater.FileVersion 312 | 18 313 | 314 | 315 | Version 316 | 18 317 | 318 | 319 | -------------------------------------------------------------------------------- /curvedata.cpp: -------------------------------------------------------------------------------- 1 | #include "curvedata.h" 2 | #include "signaldata.h" 3 | 4 | const SignalData &CurveData::values() const 5 | { 6 | return SignalData::instance(); 7 | } 8 | 9 | SignalData &CurveData::values() 10 | { 11 | return SignalData::instance(); 12 | } 13 | 14 | QPointF CurveData::sample( size_t i ) const 15 | { 16 | return SignalData::instance().value( i ); 17 | } 18 | 19 | size_t CurveData::size() const 20 | { 21 | return SignalData::instance().size(); 22 | } 23 | 24 | QRectF CurveData::boundingRect() const 25 | { 26 | return SignalData::instance().boundingRect(); 27 | } 28 | -------------------------------------------------------------------------------- /curvedata.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class SignalData; 5 | 6 | class CurveData: public QwtSeriesData 7 | { 8 | public: 9 | const SignalData &values() const; 10 | SignalData &values(); 11 | 12 | virtual QPointF sample( size_t i ) const; 13 | virtual size_t size() const; 14 | 15 | virtual QRectF boundingRect() const; 16 | }; 17 | -------------------------------------------------------------------------------- /knob.cpp: -------------------------------------------------------------------------------- 1 | #include "knob.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | Knob::Knob( const QString &title, double min, double max, QWidget *parent ): 11 | QWidget( parent ) 12 | { 13 | QFont font( "Helvetica", 10 ); 14 | 15 | d_knob = new QwtKnob( this ); 16 | d_knob->setFont( font ); 17 | 18 | QwtScaleDiv scaleDiv = 19 | d_knob->scaleEngine()->divideScale( min, max, 5, 3 ); 20 | 21 | QList ticks = scaleDiv.ticks( QwtScaleDiv::MajorTick ); 22 | if ( ticks.size() > 0 && ticks[0] > min ) 23 | { 24 | if ( ticks.first() > min ) 25 | ticks.prepend( min ); 26 | if ( ticks.last() < max ) 27 | ticks.append( max ); 28 | } 29 | scaleDiv.setTicks( QwtScaleDiv::MajorTick, ticks ); 30 | d_knob->setScale( scaleDiv ); 31 | 32 | d_knob->setKnobWidth( 50 ); 33 | 34 | font.setBold( true ); 35 | d_label = new QLabel( title, this ); 36 | d_label->setFont( font ); 37 | d_label->setAlignment( Qt::AlignTop | Qt::AlignHCenter ); 38 | 39 | setSizePolicy( QSizePolicy::MinimumExpanding, 40 | QSizePolicy::MinimumExpanding ); 41 | 42 | connect( d_knob, SIGNAL( valueChanged( double ) ), 43 | this, SIGNAL( valueChanged( double ) ) ); 44 | } 45 | 46 | QSize Knob::sizeHint() const 47 | { 48 | QSize sz1 = d_knob->sizeHint(); 49 | QSize sz2 = d_label->sizeHint(); 50 | 51 | const int w = qMax( sz1.width(), sz2.width() ); 52 | const int h = sz1.height() + sz2.height(); 53 | 54 | int off = qCeil( d_knob->scaleDraw()->extent( d_knob->font() ) ); 55 | off -= 15; // spacing 56 | 57 | return QSize( w, h - off ); 58 | } 59 | 60 | void Knob::setValue( double value ) 61 | { 62 | d_knob->setValue( value ); 63 | } 64 | 65 | double Knob::value() const 66 | { 67 | return d_knob->value(); 68 | } 69 | 70 | void Knob::setTheme( const QColor &color ) 71 | { 72 | d_knob->setPalette( color ); 73 | } 74 | 75 | QColor Knob::theme() const 76 | { 77 | return d_knob->palette().color( QPalette::Window ); 78 | } 79 | 80 | void Knob::resizeEvent( QResizeEvent *event ) 81 | { 82 | const QSize sz = event->size(); 83 | const QSize hint = d_label->sizeHint(); 84 | 85 | d_label->setGeometry( 0, sz.height() - hint.height(), 86 | sz.width(), hint.height() ); 87 | 88 | const int knobHeight = d_knob->sizeHint().height(); 89 | 90 | int off = qCeil( d_knob->scaleDraw()->extent( d_knob->font() ) ); 91 | off -= 15; // spacing 92 | 93 | d_knob->setGeometry( 0, d_label->pos().y() - knobHeight + off, 94 | sz.width(), knobHeight ); 95 | } 96 | -------------------------------------------------------------------------------- /knob.h: -------------------------------------------------------------------------------- 1 | #ifndef _KNOB_H_ 2 | #define _KNOB_H_ 3 | 4 | #include 5 | 6 | class QwtKnob; 7 | class QLabel; 8 | 9 | class Knob: public QWidget //继承自QWidget的旋钮类 10 | { 11 | Q_OBJECT 12 | 13 | Q_PROPERTY( QColor theme READ theme WRITE setTheme ) 14 | 15 | public: 16 | Knob( const QString &title, 17 | double min, double max, QWidget *parent = NULL ); 18 | 19 | virtual QSize sizeHint() const; 20 | 21 | void setValue( double value ); 22 | double value() const; 23 | 24 | void setTheme( const QColor & ); 25 | QColor theme() const; 26 | 27 | Q_SIGNALS: 28 | double valueChanged( double ); 29 | 30 | protected: 31 | virtual void resizeEvent( QResizeEvent * ); 32 | 33 | //将一个QwtKnob(旋钮类)和一个QLabel(标签类)组合成一个Knob类 34 | private: 35 | QwtKnob *d_knob; 36 | QLabel *d_label; 37 | }; 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "mainwindow.h" 3 | #include "samplingthread.h" 4 | #include 5 | 6 | int main( int argc, char **argv ) 7 | { 8 | QApplication app( argc, argv ); 9 | 10 | app.setPalette( Qt::cyan ); //用调色板设置应用程序的背景颜色 11 | 12 | MainWindow window; //实例化一个MainWindow类对象 13 | window.resize( 800, 400 ); //重新定义主窗口尺寸 14 | 15 | //继承关系:class SamplingThread: public QwtSamplingThread 16 | //继承关系:class QWT_EXPORT QwtSamplingThread: public QThread 17 | SamplingThread samplingThread; //实例化一个采样线程对象 18 | samplingThread.setFrequency( window.frequency() ); //设置频率 19 | samplingThread.setAmplitude( window.amplitude() ); //设置振幅 20 | samplingThread.setInterval( window.signalInterval() ); //信号采样间隔 21 | 22 | /* 连接主窗口旋钮变化信号和采样进程的相应槽函数 */ 23 | window.connect( &window, SIGNAL( frequencyChanged( double ) ), 24 | &samplingThread, SLOT( setFrequency( double ) ) ); 25 | window.connect( &window, SIGNAL( amplitudeChanged( double ) ), 26 | &samplingThread, SLOT( setAmplitude( double ) ) ); 27 | window.connect( &window, SIGNAL( signalIntervalChanged( double ) ), 28 | &samplingThread, SLOT( setInterval( double ) ) ); 29 | 30 | window.show(); //显示mainwindow 31 | 32 | samplingThread.start(); //启动采样线程 33 | window.start(); //开始window 34 | 35 | bool ok = app.exec(); //进入主事件循环,直道退出程序,结束循环,才能执行下面的程序 36 | 37 | samplingThread.stop(); //停止采样线程 38 | samplingThread.wait( 1000 ); 39 | 40 | return ok; 41 | } 42 | -------------------------------------------------------------------------------- /mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "plot.h" 3 | #include "knob.h" 4 | #include "wheelbox.h" 5 | #include 6 | #include 7 | #include 8 | 9 | MainWindow::MainWindow( QWidget *parent ): 10 | QWidget( parent ) 11 | { 12 | const double intervalLength = 1.0; // seconds 13 | 14 | /* 实例化主窗口的各种控件 */ 15 | d_plot = new Plot( this ); 16 | d_plot->setIntervalLength( intervalLength ); 17 | 18 | d_amplitudeKnob = new Knob( "Amplitude", 0.0, 200.0, this ); 19 | d_amplitudeKnob->setValue( 100.0 ); 20 | 21 | d_frequencyKnob = new Knob( "Frequency [Hz]", 0.1, 20.0, this ); 22 | d_frequencyKnob->setValue( 10.0 ); 23 | 24 | d_intervalWheel = new WheelBox( "Displayed [s]", 1.0, 100.0, 1.0, this ); 25 | d_intervalWheel->setValue( intervalLength ); 26 | 27 | d_timerWheel = new WheelBox( "Sample Interval [ms]", 0.0, 20.0, 0.1, this ); 28 | d_timerWheel->setValue( 1.0 ); 29 | 30 | 31 | //主窗口布局 32 | QVBoxLayout* vLayout1 = new QVBoxLayout(); 33 | vLayout1->addWidget( d_intervalWheel ); 34 | vLayout1->addWidget( d_timerWheel ); 35 | vLayout1->addStretch( 10 ); 36 | vLayout1->addWidget( d_amplitudeKnob ); 37 | vLayout1->addWidget( d_frequencyKnob ); 38 | 39 | //主窗口布局 40 | QHBoxLayout *layout = new QHBoxLayout( this ); 41 | layout->addWidget( d_plot, 10 ); 42 | layout->addLayout( vLayout1 ); 43 | 44 | /* 一个信号可以连接到另一个信号,用来传递一个信号 */ 45 | connect( d_amplitudeKnob, SIGNAL( valueChanged( double ) ), 46 | SIGNAL( amplitudeChanged( double ) ) ); 47 | connect( d_frequencyKnob, SIGNAL( valueChanged( double ) ), 48 | SIGNAL( frequencyChanged( double ) ) ); 49 | connect( d_timerWheel, SIGNAL( valueChanged( double ) ), 50 | SIGNAL( signalIntervalChanged( double ) ) ); 51 | 52 | /* 53 | * 连接采样间隔调节齿轮箱的valueChanged信号与画波形控件 54 | * d_plot的槽函数setIntervalLength用来设置采样间隔长度 55 | */ 56 | connect( d_intervalWheel, SIGNAL( valueChanged( double ) ), 57 | d_plot, SLOT( setIntervalLength( double ) ) ); 58 | } 59 | 60 | void MainWindow::start() 61 | { 62 | d_plot->start(); 63 | } 64 | 65 | double MainWindow::frequency() const 66 | { 67 | return d_frequencyKnob->value(); 68 | } 69 | 70 | double MainWindow::amplitude() const 71 | { 72 | return d_amplitudeKnob->value(); 73 | } 74 | 75 | double MainWindow::signalInterval() const 76 | { 77 | return d_timerWheel->value(); 78 | } 79 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Plot; 4 | class Knob; 5 | class WheelBox; 6 | 7 | class MainWindow : public QWidget 8 | { 9 | Q_OBJECT 10 | 11 | public: 12 | MainWindow( QWidget * = NULL ); //构造函数 13 | 14 | void start(); //调用d_plot控件的start()函数 15 | 16 | double amplitude() const; //返回振幅旋钮的值 17 | double frequency() const; //返回频率旋钮的值 18 | double signalInterval() const; //返回显示时间齿轮箱的值 19 | 20 | Q_SIGNALS: 21 | void amplitudeChanged( double ); 22 | void frequencyChanged( double ); 23 | void signalIntervalChanged( double ); 24 | 25 | private: 26 | Knob *d_frequencyKnob; //信号频率调节旋钮 27 | Knob *d_amplitudeKnob; //信号振幅调节旋钮 28 | WheelBox *d_timerWheel; //显示时间调节齿轮箱 29 | WheelBox *d_intervalWheel; //采样间隔调节齿轮箱 30 | 31 | Plot *d_plot; //画波形控件 32 | }; 33 | -------------------------------------------------------------------------------- /osci.css: -------------------------------------------------------------------------------- 1 | MainWindow 2 | { 3 | border: 1px solid white; 4 | border-radius: 20px; 5 | padding: 10px; 6 | background-color: qlineargradient( x1: 0, y1: 0, x2: 1, y2: 1, 7 | stop: 0 #31312C, stop: 0.5 #808080 stop: 1 #31312C ); 8 | } 9 | 10 | QwtPlotCanvas 11 | { 12 | border: 1px solid White; 13 | border-radius: 10px; 14 | background-color: #101010; 15 | color: yellow; /* used as curve color */ 16 | } 17 | 18 | QwtScaleWidget 19 | { 20 | color: white; 21 | } 22 | 23 | WheelBox 24 | { 25 | qproperty-theme: #878787; 26 | } 27 | 28 | QwtWheel 29 | { 30 | /* background-color: yellow; */ 31 | qproperty-mass: 0.0; 32 | qproperty-tickCount: 5; 33 | qproperty-wheelWidth: 15; 34 | qproperty-borderWidth: 2; 35 | qproperty-wheelBorderWidth: 2; 36 | qproperty-wrapping: true; 37 | } 38 | 39 | Knob 40 | { 41 | qproperty-theme: #606060; 42 | } 43 | 44 | QwtKnob 45 | { 46 | qproperty-knobStyle: Sunken; 47 | qproperty-markerStyle: Nub; 48 | qproperty-markerSize: 8; 49 | qproperty-borderWidth: 2; 50 | } 51 | 52 | QLCDNumber 53 | { 54 | color: yellow; 55 | } 56 | -------------------------------------------------------------------------------- /plot.cpp: -------------------------------------------------------------------------------- 1 | #include "plot.h" 2 | #include "curvedata.h" 3 | #include "signaldata.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class Canvas: public QwtPlotCanvas //定义Canvas画布类 15 | { 16 | public: 17 | Canvas( QwtPlot *plot = NULL ): 18 | QwtPlotCanvas( plot ) 19 | { 20 | // The backing store is important, when working with widget 21 | // overlays ( f.e rubberbands for zooming ). 22 | // Here we don't have them and the internal 23 | // backing store of QWidget is good enough. 24 | 25 | setPaintAttribute( QwtPlotCanvas::BackingStore, false ); 26 | setBorderRadius( 10 ); 27 | 28 | if ( QwtPainter::isX11GraphicsSystem() ) 29 | { 30 | #if QT_VERSION < 0x050000 31 | // Even if not liked by the Qt development, Qt::WA_PaintOutsidePaintEvent 32 | // works on X11. This has a nice effect on the performance. 33 | 34 | setAttribute( Qt::WA_PaintOutsidePaintEvent, true ); 35 | #endif 36 | 37 | // Disabling the backing store of Qt improves the performance 38 | // for the direct painter even more, but the canvas becomes 39 | // a native window of the window system, receiving paint events 40 | // for resize and expose operations. Those might be expensive 41 | // when there are many points and the backing store of 42 | // the canvas is disabled. So in this application 43 | // we better don't disable both backing stores. 44 | 45 | if ( testPaintAttribute( QwtPlotCanvas::BackingStore ) ) 46 | { 47 | setAttribute( Qt::WA_PaintOnScreen, true ); 48 | setAttribute( Qt::WA_NoSystemBackground, true ); 49 | } 50 | } 51 | 52 | setupPalette(); 53 | } 54 | 55 | private: 56 | void setupPalette() 57 | { 58 | QPalette pal = palette(); 59 | 60 | #if QT_VERSION >= 0x040400 61 | QLinearGradient gradient; 62 | gradient.setCoordinateMode( QGradient::StretchToDeviceMode ); 63 | gradient.setColorAt( 0.0, QColor( 0, 49, 110 ) ); 64 | gradient.setColorAt( 1.0, QColor( 0, 87, 174 ) ); 65 | 66 | pal.setBrush( QPalette::Window, QBrush( gradient ) ); 67 | #else 68 | pal.setBrush( QPalette::Window, QBrush( color ) ); 69 | #endif 70 | 71 | // QPalette::WindowText is used for the curve color 72 | // 设置曲线的颜色 73 | pal.setColor( QPalette::WindowText, Qt::yellow ); 74 | 75 | setPalette( pal ); 76 | } 77 | }; 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | Plot::Plot( QWidget *parent ): //定义Plot类的构造函数 93 | QwtPlot( parent ), 94 | d_paintedPoints( 0 ), //初始化Plot类的部分数据成员 95 | d_interval( 0.0, 10.0 ), 96 | d_timerId( -1 ) 97 | { 98 | d_directPainter = new QwtPlotDirectPainter(); 99 | 100 | setAutoReplot( false ); 101 | setCanvas( new Canvas() ); 102 | 103 | plotLayout()->setAlignCanvasToScales( true ); 104 | 105 | setAxisTitle( QwtPlot::xBottom, "Time [s]" ); 106 | setAxisScale( QwtPlot::xBottom, d_interval.minValue(), d_interval.maxValue() ); 107 | setAxisScale( QwtPlot::yLeft, -200.0, 200.0 ); 108 | 109 | /* 画网格 */ 110 | QwtPlotGrid *grid = new QwtPlotGrid(); 111 | grid->setPen( Qt::gray, 0.0, Qt::DotLine ); 112 | grid->enableX( true ); 113 | grid->enableXMin( true ); 114 | grid->enableY( true ); 115 | grid->enableYMin( false ); 116 | grid->attach( this ); 117 | 118 | /* 画X-Y轴直线*/ 119 | d_origin = new QwtPlotMarker(); 120 | d_origin->setLineStyle( QwtPlotMarker::Cross ); //Crosshair十字光标 121 | d_origin->setValue( d_interval.minValue() + d_interval.width() / 2.0, 0.0 ); 122 | d_origin->setLinePen( Qt::gray, 0.0, Qt::DashLine ); 123 | d_origin->attach( this ); 124 | 125 | /* 新建绘制曲线PlotCurve类对象 */ 126 | d_curve = new QwtPlotCurve(); 127 | d_curve->setStyle( QwtPlotCurve::Lines ); 128 | d_curve->setPen( canvas()->palette().color( QPalette::WindowText ) ); 129 | d_curve->setRenderHint( QwtPlotItem::RenderAntialiased, true ); 130 | d_curve->setPaintAttribute( QwtPlotCurve::ClipPolygons, false ); 131 | d_curve->setData( new CurveData() ); //实例化一个曲线数据CurveData类对象,并将其设置为绘制曲线对象的数据 132 | d_curve->attach( this ); 133 | } 134 | 135 | Plot::~Plot() 136 | { 137 | delete d_directPainter; 138 | } 139 | 140 | void Plot::start() 141 | { 142 | //为定时器提供更高精度的clock 143 | d_clock.start(); 144 | 145 | //启动定时器,设置定时器事件产生的间隔为10mS 146 | d_timerId = startTimer( 10 ); 147 | } 148 | 149 | /* 重绘 */ 150 | void Plot::replot() 151 | { 152 | //用法:static_cast < type-id > ( expression ) 153 | //该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。 154 | //将QwtSeriesData指针类型显示强制转换为CurveData指针类型 155 | //CurveData类继承自QwtSeriesData类 156 | CurveData *data = static_cast( d_curve->data() ); 157 | data->values().lock(); 158 | 159 | QwtPlot::replot(); 160 | 161 | /* d_paintedPoints变量记录了,已经绘制的容器中点的个数 */ 162 | d_paintedPoints = data->size(); 163 | 164 | data->values().unlock(); 165 | } 166 | 167 | /* 设置显示区间的长度,单位:秒,并重绘 */ 168 | void Plot::setIntervalLength( double interval ) 169 | { 170 | if ( interval > 0.0 && interval != d_interval.width() ) 171 | { 172 | //设置区间的最大值 173 | d_interval.setMaxValue( d_interval.minValue() + interval ); 174 | 175 | //设置X轴的比例 176 | setAxisScale( QwtPlot::xBottom, d_interval.minValue(), d_interval.maxValue() ); 177 | 178 | //重绘 179 | replot(); 180 | } 181 | } 182 | 183 | /* 更新曲线,在定时器事件中周期性调用 */ 184 | void Plot::updateCurve() 185 | { 186 | CurveData *data = static_cast( d_curve->data() ); 187 | data->values().lock(); 188 | 189 | const int numPoints = data->size(); 190 | if ( numPoints > d_paintedPoints ) 191 | { 192 | /* WA_PaintOnScreen属性,指示窗口部件想要直接画在屏幕上 */ 193 | const bool doClip = !canvas()->testAttribute( Qt::WA_PaintOnScreen ); 194 | 195 | if ( doClip ) //如果窗口部件不是要直接画在屏幕上 196 | { 197 | /* 198 | Depending on the platform setting a clip might be an important 199 | performance issue. F.e. for Qt Embedded this reduces the 200 | part of the backing store that has to be copied out - maybe 201 | to an unaccelerated frame buffer device. 202 | */ 203 | 204 | const QwtScaleMap xMap = canvasMap( d_curve->xAxis() ); 205 | const QwtScaleMap yMap = canvasMap( d_curve->yAxis() ); 206 | 207 | QRectF br = qwtBoundingRect( *data, 208 | d_paintedPoints - 1, numPoints - 1 ); 209 | 210 | const QRect clipRect = QwtScaleMap::transform( xMap, yMap, br ).toRect(); 211 | 212 | /* 设置增量式画家的剪切区域 */ 213 | d_directPainter->setClipRegion( clipRect ); 214 | } 215 | 216 | /* 使用增量式画家,绘制一系列点 */ 217 | /* 218 | * 由此可以看出,如果没有缩放绘图比例,紧紧增加了一系列点,则不会调用replot函数,而是 219 | * 调用增量式绘图函数,这样可以更高效 220 | */ 221 | d_directPainter->drawSeries( d_curve, d_paintedPoints - 1, numPoints - 1 ); 222 | 223 | /* 224 | * 变量d_paintedPoints记录了,上次容器中的元素数量, 225 | * 再次绘制时,从上次的最后一个元素+1的地方开始增量式绘制 226 | */ 227 | d_paintedPoints = numPoints; 228 | } 229 | 230 | data->values().unlock(); 231 | } 232 | 233 | 234 | /* 增加区间,并重绘:当一屏数据显示完成,需要重头显示的时候调用 */ 235 | void Plot::incrementInterval() 236 | { 237 | /* 设置区间 */ 238 | d_interval = QwtInterval( d_interval.maxValue(), 239 | d_interval.maxValue() + d_interval.width() ); 240 | 241 | CurveData *data = static_cast( d_curve->data() ); 242 | 243 | /* 清除x轴坐标小于区间最小值的点,这种做法,可能会清除一部分还没有绘制的点 */ 244 | data->values().clearStaleValues( d_interval.minValue() ); 245 | 246 | // To avoid, that the grid is jumping, we disable 247 | // the autocalculation of the ticks and shift them 248 | // manually instead. 249 | 250 | /* 设置x轴刻度 */ 251 | QwtScaleDiv scaleDiv = axisScaleDiv( QwtPlot::xBottom ); 252 | scaleDiv.setInterval( d_interval ); 253 | 254 | for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ ) 255 | { 256 | QList ticks = scaleDiv.ticks( i ); 257 | for ( int j = 0; j < ticks.size(); j++ ) 258 | ticks[j] += d_interval.width(); 259 | scaleDiv.setTicks( i, ticks ); 260 | } 261 | setAxisScaleDiv( QwtPlot::xBottom, scaleDiv ); 262 | 263 | /* 设置十字交叉线的位置 */ 264 | d_origin->setValue( d_interval.minValue() + d_interval.width() / 2.0, 0.0 ); 265 | 266 | d_paintedPoints = 0; 267 | replot(); 268 | } 269 | 270 | void Plot::timerEvent( QTimerEvent *event ) //定时器事件 271 | { 272 | if ( event->timerId() == d_timerId ) 273 | { 274 | updateCurve(); //更新曲线 275 | 276 | const double elapsed = d_clock.elapsed() / 1000.0; //Plot对象启动定时器以来,经过了多少秒 277 | if ( elapsed > d_interval.maxValue() ) //如果已经过去的时间大于区间的最大值,则更新区间 278 | incrementInterval(); //增加区间 279 | 280 | return; 281 | } 282 | 283 | QwtPlot::timerEvent( event ); 284 | } 285 | 286 | void Plot::resizeEvent( QResizeEvent *event ) //改变尺寸事件 287 | { 288 | d_directPainter->reset(); //窗口尺寸发生改变,复位直接画家对象 289 | QwtPlot::resizeEvent( event ); 290 | } 291 | 292 | void Plot::showEvent( QShowEvent * ) //显示事件 293 | { 294 | replot(); 295 | } 296 | 297 | bool Plot::eventFilter( QObject *object, QEvent *event ) //事件滤波器 298 | { 299 | if ( object == canvas() && 300 | event->type() == QEvent::PaletteChange ) 301 | { 302 | d_curve->setPen( canvas()->palette().color( QPalette::WindowText ) ); 303 | } 304 | 305 | return QwtPlot::eventFilter( object, event ); 306 | } 307 | -------------------------------------------------------------------------------- /plot.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class QwtPlotCurve; 6 | class QwtPlotMarker; 7 | class QwtPlotDirectPainter; 8 | 9 | class Plot: public QwtPlot 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | Plot( QWidget * = NULL ); 15 | virtual ~Plot(); 16 | 17 | void start(); 18 | virtual void replot(); //重绘 19 | 20 | virtual bool eventFilter( QObject *, QEvent * ); //事件滤波器 21 | 22 | public Q_SLOTS: 23 | void setIntervalLength( double ); //设置区间长度 24 | 25 | protected: 26 | virtual void showEvent( QShowEvent * ); //显示事件 27 | virtual void resizeEvent( QResizeEvent * ); //重定义大小事件 28 | virtual void timerEvent( QTimerEvent * ); //定时器事件,覆盖QObject类的timerEvent()函数 29 | 30 | private: 31 | void updateCurve(); //更新曲线 32 | void incrementInterval(); //增加区间 33 | 34 | /* 35 | * 一个Marker可以是一条水平线、一条垂直线、一个符号、一个标签或他们的任何组合, 36 | * 它可以画在一个中心点的周围,也可以画在一个边界矩形内部。 37 | */ 38 | QwtPlotMarker *d_origin; //定义一个Qwt标识类对象指针,标识坐标原点 39 | 40 | /* 41 | * QwtPlotCurve:一个绘图项,表示一系列的点。 42 | * 曲线是在X-Y平面上的一系列点的表示。它支持不同的显示风格,插值(铁条)和符号。 43 | */ 44 | QwtPlotCurve *d_curve; //定义一个Qwt曲线类对象指针 45 | 46 | int d_paintedPoints; //已经画了的点 47 | 48 | /* 49 | * 增量式Painter对象 50 | * qwtplotdirectpainter提供了一个API paint子集(f.e补充点),无需擦除/重绘图的画布。 51 | */ 52 | QwtPlotDirectPainter *d_directPainter; 53 | 54 | /* 区间由两个double类型的数表示,分别代表上下限 */ 55 | QwtInterval d_interval; //实例化一个Qwt区间类对象 56 | int d_timerId; //定时器ID 57 | 58 | /* 59 | * QwtSystemClock提供一个高分辨率时钟 60 | * 有时候QTime(毫秒分辨率)提供的分辨率对进行时间测量不够精确。 61 | * QwtSystemClock提供了QTime功能的子集,使用更好分辨率的定时器(在允许的情况下) 62 | */ 63 | QwtSystemClock d_clock; //实例化一个系统时钟对象 64 | }; 65 | -------------------------------------------------------------------------------- /qwt.prf: -------------------------------------------------------------------------------- 1 | ################################################################ 2 | # Qwt Widget Library 3 | # Copyright (C) 1997 Josef Wilgen 4 | # Copyright (C) 2002 Uwe Rathmann 5 | # 6 | # This library is free software; you can redistribute it and/or 7 | # modify it under the terms of the Qwt License, Version 1.0 8 | ################################################################ 9 | 10 | include ( ./qwtconfig.pri ) 11 | include ( ./qwtfunctions.pri ) 12 | 13 | contains(QWT_CONFIG, QwtDll) { 14 | 15 | DEFINES *= QWT_DLL 16 | } 17 | 18 | contains(QWT_CONFIG, QwtSvg) { 19 | 20 | QT *= svg 21 | } 22 | else { 23 | 24 | DEFINES *= QWT_NO_SVG 25 | } 26 | 27 | contains(QWT_CONFIG, QwtFramework) { 28 | 29 | INCLUDEPATH *= $${QWT_INSTALL_LIBS}/qwt.framework/Headers 30 | } 31 | else { 32 | 33 | INCLUDEPATH *= $${QWT_INSTALL_HEADERS} 34 | } 35 | 36 | # QMAKE_RPATHDIR *= $${QWT_INSTALL_LIBS} 37 | qwtAddLibrary($${QWT_INSTALL_LIBS}, qwt) 38 | -------------------------------------------------------------------------------- /qwtconfig.pri: -------------------------------------------------------------------------------- 1 | ################################################################ 2 | # Qwt Widget Library 3 | # Copyright (C) 1997 Josef Wilgen 4 | # Copyright (C) 2002 Uwe Rathmann 5 | # 6 | # This library is free software; you can redistribute it and/or 7 | # modify it under the terms of the Qwt License, Version 1.0 8 | ################################################################ 9 | 10 | QWT_VER_MAJ = 6 11 | QWT_VER_MIN = 1 12 | QWT_VER_PAT = 3 13 | QWT_VERSION = $${QWT_VER_MAJ}.$${QWT_VER_MIN}.$${QWT_VER_PAT} 14 | 15 | ###################################################################### 16 | # Install paths 17 | ###################################################################### 18 | 19 | QWT_INSTALL_PREFIX = $$[QT_INSTALL_PREFIX] 20 | 21 | unix { 22 | QWT_INSTALL_PREFIX = /usr/local/qwt-$$QWT_VERSION 23 | # QWT_INSTALL_PREFIX = /usr/local/qwt-$$QWT_VERSION-qt-$$QT_VERSION 24 | } 25 | 26 | win32 { 27 | QWT_INSTALL_PREFIX = C:/Qwt-$$QWT_VERSION 28 | # QWT_INSTALL_PREFIX = C:/Qwt-$$QWT_VERSION-qt-$$QT_VERSION 29 | } 30 | 31 | QWT_INSTALL_DOCS = $${QWT_INSTALL_PREFIX}/doc 32 | QWT_INSTALL_HEADERS = $${QWT_INSTALL_PREFIX}/include 33 | QWT_INSTALL_LIBS = $${QWT_INSTALL_PREFIX}/lib 34 | 35 | ###################################################################### 36 | # Designer plugin 37 | # creator/designer load designer plugins from certain default 38 | # directories ( f.e the path below QT_INSTALL_PREFIX ) and the 39 | # directories listed in the QT_PLUGIN_PATH environment variable. 40 | # When using the path below QWT_INSTALL_PREFIX you need to 41 | # add $${QWT_INSTALL_PREFIX}/plugins to QT_PLUGIN_PATH in the 42 | # runtime environment of designer/creator. 43 | ###################################################################### 44 | 45 | QWT_INSTALL_PLUGINS = $${QWT_INSTALL_PREFIX}/plugins/designer 46 | 47 | # linux distributors often organize the Qt installation 48 | # their way and QT_INSTALL_PREFIX doesn't offer a good 49 | # path. Also QT_INSTALL_PREFIX is only one of the default 50 | # search paths of the designer - not the Qt creator 51 | 52 | #QWT_INSTALL_PLUGINS = $$[QT_INSTALL_PREFIX]/plugins/designer 53 | 54 | ###################################################################### 55 | # Features 56 | # When building a Qwt application with qmake you might want to load 57 | # the compiler/linker flags, that are required to build a Qwt application 58 | # from qwt.prf. Therefore all you need to do is to add "CONFIG += qwt" 59 | # to your project file and take care, that qwt.prf can be found by qmake. 60 | # ( see http://doc.trolltech.com/4.7/qmake-advanced-usage.html#adding-new-configuration-features ) 61 | # I recommend not to install the Qwt features together with the 62 | # Qt features, because you will have to reinstall the Qwt features, 63 | # with every Qt upgrade. 64 | ###################################################################### 65 | 66 | QWT_INSTALL_FEATURES = $${QWT_INSTALL_PREFIX}/features 67 | # QWT_INSTALL_FEATURES = $$[QT_INSTALL_PREFIX]/features 68 | 69 | ###################################################################### 70 | # Build the static/shared libraries. 71 | # If QwtDll is enabled, a shared library is built, otherwise 72 | # it will be a static library. 73 | ###################################################################### 74 | 75 | QWT_CONFIG += QwtDll 76 | 77 | ###################################################################### 78 | # QwtPlot enables all classes, that are needed to use the QwtPlot 79 | # widget. 80 | ###################################################################### 81 | 82 | QWT_CONFIG += QwtPlot 83 | 84 | ###################################################################### 85 | # QwtWidgets enables all classes, that are needed to use the all other 86 | # widgets (sliders, dials, ...), beside QwtPlot. 87 | ###################################################################### 88 | 89 | QWT_CONFIG += QwtWidgets 90 | 91 | ###################################################################### 92 | # If you want to display svg images on the plot canvas, or 93 | # export a plot to a SVG document 94 | ###################################################################### 95 | 96 | QWT_CONFIG += QwtSvg 97 | 98 | ###################################################################### 99 | # If you want to use a OpenGL plot canvas 100 | ###################################################################### 101 | 102 | QWT_CONFIG += QwtOpenGL 103 | 104 | ###################################################################### 105 | # You can use the MathML renderer of the Qt solutions package to 106 | # enable MathML support in Qwt. Because of license implications 107 | # the ( modified ) code of the MML Widget solution is included and 108 | # linked together with the QwtMathMLTextEngine into an own library. 109 | # To use it you will have to add "CONFIG += qwtmathml" 110 | # to your qmake project file. 111 | ###################################################################### 112 | 113 | #QWT_CONFIG += QwtMathML 114 | 115 | ###################################################################### 116 | # If you want to build the Qwt designer plugin, 117 | # enable the line below. 118 | # Otherwise you have to build it from the designer directory. 119 | ###################################################################### 120 | 121 | QWT_CONFIG += QwtDesigner 122 | 123 | ###################################################################### 124 | # Compile all Qwt classes into the designer plugin instead 125 | # of linking it against the shared Qwt library. Has no effect 126 | # when QwtDesigner or QwtDll are not both enabled. 127 | # 128 | # On systems where rpath is supported ( all Unixoids ) the 129 | # location of the installed Qwt library is compiled into the plugin, 130 | # but on Windows it might be easier to have a self contained 131 | # plugin to avoid any hassle with configuring the runtime 132 | # environment of the designer/creator. 133 | ###################################################################### 134 | 135 | win32 { 136 | QWT_CONFIG += QwtDesignerSelfContained 137 | } 138 | 139 | ###################################################################### 140 | # If you want to auto build the examples, enable the line below 141 | # Otherwise you have to build them from the examples directory. 142 | ###################################################################### 143 | 144 | #QWT_CONFIG += QwtExamples 145 | 146 | ###################################################################### 147 | # The playground is primarily intended for the Qwt development 148 | # to explore and test new features. Nevertheless you might find 149 | # ideas or code snippets that help for application development 150 | # If you want to auto build the applications in playground, enable 151 | # the line below. 152 | # Otherwise you have to build them from the playground directory. 153 | ###################################################################### 154 | 155 | #QWT_CONFIG += QwtPlayground 156 | 157 | ###################################################################### 158 | # When Qt has been built as framework qmake wants 159 | # to link frameworks instead of regular libs 160 | ###################################################################### 161 | 162 | macx:!static:CONFIG(qt_framework, qt_framework|qt_no_framework) { 163 | 164 | QWT_CONFIG += QwtFramework 165 | } 166 | 167 | ###################################################################### 168 | # Create and install pc files for pkg-config 169 | # See http://www.freedesktop.org/wiki/Software/pkg-config/ 170 | ###################################################################### 171 | 172 | unix { 173 | 174 | #QWT_CONFIG += QwtPkgConfig 175 | } 176 | -------------------------------------------------------------------------------- /qwtfunctions.pri: -------------------------------------------------------------------------------- 1 | ################################################################ 2 | # Qwt Widget Library 3 | # Copyright (C) 1997 Josef Wilgen 4 | # Copyright (C) 2002 Uwe Rathmann 5 | # 6 | # This library is free software; you can redistribute it and/or 7 | # modify it under the terms of the Qwt License, Version 1.0 8 | ################################################################ 9 | 10 | # Copied and modified from qt_functions.prf 11 | 12 | defineReplace(qwtLibraryTarget) { 13 | 14 | unset(LIBRARY_NAME) 15 | LIBRARY_NAME = $$1 16 | 17 | mac:contains(QWT_CONFIG, QwtFramework) { 18 | 19 | QMAKE_FRAMEWORK_BUNDLE_NAME = $$LIBRARY_NAME 20 | export(QMAKE_FRAMEWORK_BUNDLE_NAME) 21 | } 22 | 23 | contains(TEMPLATE, .*lib):CONFIG(debug, debug|release) { 24 | 25 | !debug_and_release|build_pass { 26 | 27 | mac:RET = $$member(LIBRARY_NAME, 0)_debug 28 | win32:RET = $$member(LIBRARY_NAME, 0)d 29 | } 30 | } 31 | 32 | isEmpty(RET):RET = $$LIBRARY_NAME 33 | return($$RET) 34 | } 35 | 36 | defineTest(qwtAddLibrary) { 37 | 38 | LIB_PATH = $$1 39 | LIB_NAME = $$2 40 | 41 | mac:contains(QWT_CONFIG, QwtFramework) { 42 | 43 | LIBS *= -F$${LIB_PATH} 44 | } 45 | else { 46 | 47 | unix:lessThan(QT_MAJOR_VERSION, 5) { 48 | 49 | # Many Linux distributions install Qwt in the same directory 50 | # as the Qt libs and thus we need to prepend the path for the local build 51 | # to avoid conflicting with the installed version. 52 | # Qt5 qmake appends ( instead of prepending ) the path to the Qt libs 53 | # to LIBS, but for Qt4 we need to use the QMAKE_LIBDIR_FLAGS. 54 | 55 | QMAKE_LIBDIR_FLAGS *= -L$${LIB_PATH} 56 | } 57 | else { 58 | LIBS *= -L$${LIB_PATH} 59 | } 60 | } 61 | 62 | unset(LINKAGE) 63 | 64 | mac:contains(QWT_CONFIG, QwtFramework) { 65 | 66 | LINKAGE = -framework $${LIB_NAME} 67 | } 68 | 69 | isEmpty(LINKAGE) { 70 | 71 | if(!debug_and_release|build_pass):CONFIG(debug, debug|release) { 72 | 73 | mac:LINKAGE = -l$${LIB_NAME}_debug 74 | win32:LINKAGE = -l$${LIB_NAME}d 75 | } 76 | } 77 | 78 | isEmpty(LINKAGE) { 79 | 80 | LINKAGE = -l$${LIB_NAME} 81 | } 82 | 83 | !isEmpty(QMAKE_LSB) { 84 | 85 | QMAKE_LFLAGS *= --lsb-shared-libs=$${LIB_NAME} 86 | } 87 | 88 | LIBS += $$LINKAGE 89 | export(LIBS) 90 | export(QMAKE_LFLAGS) 91 | export(QMAKE_LIBDIR_FLAGS) 92 | 93 | return(true) 94 | } 95 | -------------------------------------------------------------------------------- /samplingthread.cpp: -------------------------------------------------------------------------------- 1 | #include "samplingthread.h" 2 | #include "signaldata.h" 3 | #include 4 | #include 5 | 6 | #if QT_VERSION < 0x040600 7 | #define qFastSin(x) ::sin(x) 8 | #endif 9 | 10 | SamplingThread::SamplingThread( QObject *parent ): 11 | QwtSamplingThread( parent ), 12 | d_frequency( 5.0 ), 13 | d_amplitude( 20.0 ) 14 | { 15 | } 16 | 17 | void SamplingThread::setFrequency( double frequency ) 18 | { 19 | d_frequency = frequency; 20 | } 21 | 22 | double SamplingThread::frequency() const 23 | { 24 | return d_frequency; 25 | } 26 | 27 | void SamplingThread::setAmplitude( double amplitude ) 28 | { 29 | d_amplitude = amplitude; 30 | } 31 | 32 | double SamplingThread::amplitude() const 33 | { 34 | return d_amplitude; 35 | } 36 | 37 | //elapsed代表时间的流逝,x轴即时间轴。 38 | void SamplingThread::sample( double elapsed ) 39 | { 40 | if ( d_frequency > 0.0 ) 41 | { 42 | //通过x的值,计算y轴的值。 43 | const QPointF s( elapsed, value( elapsed ) ); 44 | 45 | //将产生的采样点添加到静态局部类SignalData对象valueVector 46 | SignalData::instance().append( s ); 47 | } 48 | } 49 | 50 | //y轴与x轴的函数关系,此处为正弦函数y = Asin(wt) 51 | double SamplingThread::value( double timeStamp ) const 52 | { 53 | const double period = 1.0 / d_frequency; 54 | 55 | /* 56 | * 产生正弦波形的代码 57 | * fmod() 用来对浮点数进行取模(求余) 58 | */ 59 | const double x = ::fmod( timeStamp, period ); 60 | const double v = d_amplitude * qFastSin( x / period * 2 * M_PI ); 61 | return v; 62 | } 63 | 64 | /* 产生正切函数波形的代码 */ 65 | // const double x = ::fmod( timeStamp, period ); //fmod() 用来对浮点数进行取模(求余) 66 | // const double v = (qFastSin( x / period * 2 * M_PI )) / (qFastCos( x / period * 2 * M_PI )); 67 | 68 | /* 产生三角波的代码 */ 69 | // const double x = ::fmod( timeStamp, period ); //fmod() 用来对浮点数进行取模(求余) 70 | // double v = 0; 71 | // if(x<(period/2.0)) { 72 | // v = d_amplitude * (2.0*x/period) - d_amplitude/2.0; 73 | // } else { 74 | // v = d_amplitude * (-2.0*x/period + 2) - d_amplitude/2.0; 75 | // } 76 | 77 | /* 产生锯齿波的代码 */ 78 | // const double x = ::fmod( timeStamp, period ); //fmod() 用来对浮点数进行取模(求余) 79 | // const double v = d_amplitude * x/period - d_amplitude/2.0; 80 | -------------------------------------------------------------------------------- /samplingthread.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class SamplingThread: public QwtSamplingThread 4 | { 5 | Q_OBJECT 6 | 7 | public: 8 | SamplingThread( QObject *parent = NULL ); 9 | 10 | double frequency() const; 11 | double amplitude() const; 12 | 13 | public Q_SLOTS: 14 | void setAmplitude( double ); 15 | void setFrequency( double ); 16 | 17 | protected: 18 | 19 | //elapsed参数表示:线程开始以来经过的时间(以毫秒为单位) 20 | virtual void sample( double elapsed ); 21 | 22 | private: 23 | virtual double value( double timeStamp ) const; 24 | 25 | double d_frequency; //频率属性 26 | double d_amplitude; //振幅属性 27 | }; 28 | -------------------------------------------------------------------------------- /signaldata.cpp: -------------------------------------------------------------------------------- 1 | #include "signaldata.h" 2 | #include 3 | #include 4 | #include 5 | 6 | //PrivateData类,为SignalData的成员类 7 | class SignalData::PrivateData 8 | { 9 | public: 10 | PrivateData():boundingRect( 1.0, 1.0, -2.0, -2.0 ) // invalid无效的 11 | { 12 | values.reserve( 1000 ); //申请为values分配1000个元素内存空间 13 | } 14 | 15 | inline void append( const QPointF &sample ) 16 | { 17 | values.append( sample ); //在数组的末尾插入一个值 18 | 19 | // adjust the bounding rectangle 调节边界限制矩形 20 | if ( boundingRect.width() < 0 || boundingRect.height() < 0 ) 21 | { 22 | boundingRect.setRect( sample.x(), sample.y(), 0.0, 0.0 ); 23 | } 24 | else 25 | { 26 | boundingRect.setRight( sample.x() ); 27 | 28 | // 怀疑此处逻辑有误,用下面的代码代替例程的代码 29 | // if ( sample.y() > boundingRect.bottom() ) 30 | // boundingRect.setBottom( sample.y() ); 31 | 32 | // if ( sample.y() < boundingRect.top() ) 33 | // boundingRect.setTop( sample.y() ); 34 | 35 | 36 | if ( sample.y() < boundingRect.bottom() ) 37 | boundingRect.setBottom( sample.y() ); 38 | 39 | if ( sample.y() > boundingRect.top() ) 40 | boundingRect.setTop( sample.y() ); 41 | } 42 | } 43 | 44 | QReadWriteLock lock; //多线程同步工具 45 | QVector values; //使用QVector模板类定义一个浮点动态数组,值 46 | QRectF boundingRect; //实例化一个矩形类对象:边界限制矩形 47 | 48 | QMutex mutex; //实例化一个互斥量对象,protecting pendingValues 49 | // QVector pendingValues; //使用QVector模板类定义一个浮点动态数组,挂起值 50 | }; 51 | 52 | SignalData::SignalData() //SignalData构造函数 53 | { 54 | d_data = new PrivateData(); //实例化一个PrivateData对象 55 | } 56 | 57 | SignalData::~SignalData() //SignalData析构函数 58 | { 59 | delete d_data; 60 | } 61 | 62 | int SignalData::size() const //返回QVector values的大小 63 | { 64 | return d_data->values.size(); 65 | } 66 | 67 | QPointF SignalData::value( int index ) const //返回QVector values的某个元素值 68 | { 69 | return d_data->values[index]; 70 | } 71 | 72 | QRectF SignalData::boundingRect() const 73 | { 74 | return d_data->boundingRect; 75 | } 76 | 77 | void SignalData::lock() 78 | { 79 | d_data->lock.lockForRead(); 80 | } 81 | 82 | void SignalData::unlock() 83 | { 84 | d_data->lock.unlock(); 85 | } 86 | 87 | void SignalData::append( const QPointF &sample )//将pendingValues添加到values 88 | { 89 | d_data->mutex.lock(); 90 | // d_data->pendingValues += sample;//This is an overloaded function. Appends value to the vector. 91 | 92 | const bool isLocked = d_data->lock.tryLockForWrite(); 93 | if ( isLocked ) 94 | { 95 | 96 | /* 经过测试d_data->pendingValues每次只缓存了一个样本点,没有什么存在的意义,注释掉不影响程序功能 */ 97 | // const int numValues = d_data->pendingValues.size(); 98 | 99 | // //Returns a pointer to the data stored in the vector. 100 | // //The pointer can be used to access and modify the items in the vector. 101 | // const QPointF *pendingValues = d_data->pendingValues.data(); 102 | 103 | // for ( int i = 0; i < numValues; i++ ) 104 | // d_data->append( pendingValues[i] ); //将pendingValues添加到values 105 | 106 | // d_data->pendingValues.clear(); //清除挂起值数组 107 | 108 | d_data->append(sample); 109 | 110 | 111 | d_data->lock.unlock(); 112 | } 113 | 114 | d_data->mutex.unlock(); 115 | } 116 | 117 | /* 当一屏数据显示完成,需要重头显示的时需要清除上一屏幕的旧数据 */ 118 | /* 在函数void Plot::incrementInterval()中调用 */ 119 | void SignalData::clearStaleValues( double limit ) //清除values中的旧值 120 | { 121 | d_data->lock.lockForWrite(); 122 | 123 | d_data->boundingRect = QRectF( 1.0, 1.0, -2.0, -2.0 ); // invalid 124 | 125 | const QVector values = d_data->values; 126 | d_data->values.clear(); 127 | d_data->values.reserve( values.size() ); 128 | 129 | int index; 130 | for ( index = values.size() - 1; index >= 0; index-- ) 131 | { 132 | //X轴的值一直在增大,当一屏显示完成以后,小于这一屏最右边X坐标的数据将被清除。 133 | if ( values[index].x() < limit ) 134 | break; 135 | } 136 | 137 | // if ( index > 0 ) 138 | // d_data->append( values[index++] ); 139 | 140 | while ( index < values.size() - 1 ) 141 | d_data->append( values[index++] ); 142 | 143 | d_data->lock.unlock(); 144 | } 145 | 146 | //实例化一个SignalData对象并返回其引用 147 | SignalData &SignalData::instance() 148 | { 149 | //定义一个静态局部类对象,生命周期为整个程序 150 | static SignalData valueVector; 151 | return valueVector; 152 | } 153 | -------------------------------------------------------------------------------- /signaldata.h: -------------------------------------------------------------------------------- 1 | #ifndef _SIGNAL_DATA_H_ 2 | #define _SIGNAL_DATA_H_ 1 3 | 4 | #include 5 | 6 | class SignalData 7 | { 8 | public: 9 | //类的成员函数前加static,则无需实例化对象,就可调用此函数 10 | static SignalData &instance(); 11 | 12 | void append( const QPointF &pos ); 13 | void clearStaleValues( double min ); 14 | 15 | int size() const; 16 | QPointF value( int index ) const; 17 | 18 | QRectF boundingRect() const; 19 | 20 | void lock(); 21 | void unlock(); 22 | 23 | private: 24 | SignalData(); 25 | SignalData( const SignalData & ); 26 | SignalData &operator=( const SignalData & ); 27 | 28 | virtual ~SignalData(); 29 | 30 | class PrivateData; 31 | PrivateData *d_data; 32 | }; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /wheelbox.cpp: -------------------------------------------------------------------------------- 1 | #include "wheelbox.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | /* 此事件滤波对象的作用是想在整个WheelBox组件区域(包括LCD控件区域)滚动鼠标滚轮时,QwtWheel的值都能改变 */ 12 | class Wheel: public QwtWheel 13 | { 14 | public: 15 | Wheel( WheelBox *parent ): 16 | QwtWheel( parent ) 17 | { 18 | setFocusPolicy( Qt::WheelFocus ); 19 | parent->installEventFilter( this ); 20 | } 21 | 22 | virtual bool eventFilter( QObject *object, QEvent *event ) 23 | { 24 | if ( event->type() == QEvent::Wheel ) 25 | { 26 | const QWheelEvent *we = static_cast( event ); 27 | 28 | 29 | 30 | 31 | /* 32 | * void QwtWheel::wheelEvent( QWheelEvent *event ) 33 | * { 34 | * if ( !wheelRect().contains( event->pos() ) ) 35 | * { 36 | * event->ignore(); 37 | * return; 38 | * } 39 | * ……………… 40 | * } 41 | * 42 | * 以上代码是从QwtWheel里面摘抄出来的,可以看出有ignore的分支 43 | * 看看QPoint( 5, 5 )什么意思? 44 | */ 45 | QWheelEvent wheelEvent( QPoint( 5, 5 ), we->delta(), 46 | we->buttons(), we->modifiers(), 47 | we->orientation() ); 48 | 49 | /* 注释掉此行代码,在wheel上面滚动滚轮,程序就不会崩溃了 */ 50 | /* 51 | * 原因分析,若在Wheel的wheelEvent()函数中ignore了Event,则Event会继续向其父祖件WheelBox传播, 52 | * 而传向WheelBox的Event会首先进入此事件滤波函数,然后又会通过sendEvent()函数发送给Wheel,再被 53 | * ignore,再传给父祖件WheelBox……陷入死循环,从而程序崩溃。 54 | */ 55 | // QApplication::sendEvent( this, &wheelEvent ); 56 | 57 | /* WXLmjr于2016-12-11日屏蔽上一行代码,修改为下面这行代码,解决程序崩溃问题, 58 | * 但直接调用event()函数和调用sendEvent()函数有什么区别?导致了崩溃的问题? 59 | */ 60 | this->event(&wheelEvent); 61 | 62 | return true; 63 | } 64 | return QwtWheel::eventFilter( object, event ); 65 | } 66 | 67 | 68 | // virtual void wheelEvent( QWheelEvent *event) 69 | // { 70 | // static int i = 0; 71 | //// event->accept(); 72 | //// event->ignore(); 73 | 74 | // QwtWheel::wheelEvent(event); 75 | // qDebug() << i++; 76 | // } 77 | }; 78 | 79 | 80 | 81 | 82 | 83 | WheelBox::WheelBox( const QString &title, 84 | double min, double max, double stepSize, QWidget *parent ): 85 | QWidget( parent ) 86 | { 87 | 88 | d_number = new QLCDNumber( this ); 89 | d_number->setSegmentStyle( QLCDNumber::Filled ); 90 | d_number->setAutoFillBackground( true ); 91 | d_number->setFixedHeight( d_number->sizeHint().height() * 2 ); 92 | d_number->setFocusPolicy( Qt::WheelFocus ); 93 | 94 | QPalette pal( Qt::black ); 95 | pal.setColor( QPalette::WindowText, Qt::green ); 96 | d_number->setPalette( pal ); 97 | 98 | d_wheel = new Wheel( this ); 99 | d_wheel->setOrientation( Qt::Vertical ); 100 | d_wheel->setInverted( true ); 101 | d_wheel->setRange( min, max ); 102 | d_wheel->setSingleStep( stepSize ); 103 | d_wheel->setPageStepCount( 5 ); 104 | d_wheel->setFixedHeight( d_number->height() ); 105 | 106 | d_number->setFocusProxy( d_wheel ); 107 | 108 | QFont font( "Helvetica", 10 ); 109 | font.setBold( true ); 110 | 111 | d_label = new QLabel( title, this ); 112 | d_label->setFont( font ); 113 | 114 | QHBoxLayout *hLayout = new QHBoxLayout; 115 | hLayout->setContentsMargins( 0, 0, 0, 0 ); 116 | hLayout->setSpacing( 2 ); 117 | hLayout->addWidget( d_number, 10 ); 118 | hLayout->addWidget( d_wheel ); 119 | 120 | QVBoxLayout *vLayout = new QVBoxLayout( this ); 121 | vLayout->addLayout( hLayout, 10 ); 122 | vLayout->addWidget( d_label, 0, Qt::AlignTop | Qt::AlignHCenter ); 123 | 124 | connect( d_wheel, SIGNAL( valueChanged( double ) ), 125 | d_number, SLOT( display( double ) ) ); 126 | connect( d_wheel, SIGNAL( valueChanged( double ) ), 127 | this, SIGNAL( valueChanged( double ) ) ); 128 | } 129 | 130 | void WheelBox::setTheme( const QColor &color ) 131 | { 132 | d_wheel->setPalette( color ); 133 | } 134 | 135 | QColor WheelBox::theme() const 136 | { 137 | return d_wheel->palette().color( QPalette::Window ); 138 | } 139 | 140 | void WheelBox::setValue( double value ) 141 | { 142 | d_wheel->setValue( value ); 143 | d_number->display( value ); 144 | } 145 | 146 | double WheelBox::value() const 147 | { 148 | return d_wheel->value(); 149 | } 150 | 151 | 152 | //bool WheelBox::eventFilter( QObject *object, QEvent *event ) 153 | //{ 154 | // if ( event->type() == QEvent::Wheel ) 155 | // { 156 | // const QWheelEvent *we = static_cast( event ); 157 | 158 | // QWheelEvent wheelEvent( QPoint( 5, 5 ), we->delta(), 159 | // we->buttons(), we->modifiers(), 160 | // we->orientation() ); 161 | 162 | // /* 注释掉此行代码,在wheel上面滚动滚轮,程序就不会崩溃了 */ 163 | // QApplication::sendEvent( d_wheel, &wheelEvent ); 164 | // return true; 165 | // } 166 | // return QwtWheel::eventFilter( object, event ); 167 | //} 168 | -------------------------------------------------------------------------------- /wheelbox.h: -------------------------------------------------------------------------------- 1 | #ifndef _WHEELBOX_H_ 2 | #define _WHEELBOX_H_ 3 | 4 | #include 5 | 6 | class QwtWheel; 7 | class QLabel; 8 | class QLCDNumber; 9 | 10 | class WheelBox: public QWidget 11 | { 12 | Q_OBJECT 13 | Q_PROPERTY( QColor theme READ theme WRITE setTheme ) 14 | 15 | public: 16 | WheelBox( const QString &title, 17 | double min, double max, double stepSize, 18 | QWidget *parent = NULL ); 19 | 20 | void setTheme( const QColor & ); 21 | QColor theme() const; 22 | 23 | void setUnit( const QString & ); 24 | QString unit() const; 25 | 26 | void setValue( double value ); 27 | double value() const; 28 | 29 | // bool eventFilter(QObject *object, QEvent *event); 30 | Q_SIGNALS: 31 | double valueChanged( double ); 32 | 33 | //将一个QLCDNumber(数码管显示控件类),一个QwtWheel(滚轮类),一个QLable(标签类)组合成一个WeelBox类 34 | private: 35 | QLCDNumber *d_number; 36 | QwtWheel *d_wheel; 37 | QLabel *d_label; 38 | 39 | QString d_unit; 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /虚拟示波器分析.vsdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WXLmjr/VirtualOscilloscope_Qt/87852151b1c5aac1b5a69e33a79a24abacca1f00/虚拟示波器分析.vsdx --------------------------------------------------------------------------------