├── .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
--------------------------------------------------------------------------------