效果预览
工程目录树如下
.
|
|---Headers
| |---mainwindow.h
| |---panel.h
| |---plot.h
| |---settings.h
|
|---Sources
| |---main.cpp
| |---mainwindow.cpp
| |---panel.cpp
| |---plot.cpp
这里一共有4个.h文件,4个.c文件,涉及到4个主要类:MainWindow、Panel、Plot、Settings。下面逐个浏览这些类
MainWindow类
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow( QWidget *parent = 0 );
private Q_SLOTS:
void updatePlot();
void exportPlot();
private:
Plot *d_plot;
Panel *d_panel;
};
MainWindow继承自QMainWindow,两个槽函数,两个私有属性。
构造函数MainWindow实现
MainWindow::MainWindow( QWidget *parent ): QMainWindow( parent )
{
d_plot = new Plot();
//新建一个Plot
Settings settings;
//新建一个Settings,用来存储配置信息
settings.legend.isEnabled = true;
//使能图例
settings.legend.position = QwtPlot::BottomLegend;
//图例位置
settings.legendItem.isEnabled = false;
//失能图例Item
settings.legendItem.numColumns = 1;
//设置图例Item列数
settings.legendItem.alignment = Qt::AlignRight | Qt::AlignVCenter;
//设置图例Item对齐方式
settings.legendItem.backgroundMode = 0;
//设置图例Item背景模式
settings.legendItem.size = d_plot->canvas()->font().pointSize();
//设置图例Item尺寸
//这里来区分一下legend和legendItem,前者是plot自带的图例,后者是一个专门的图例类。
settings.curve.numCurves = 4;
//设置曲线数量
settings.curve.title = "Curve";
//设置曲线名称
d_panel = new Panel();
//新建控制面板
d_panel->setSettings( settings );
//用之前初始化号的settings来初始化面板
QWidget *box = new QWidget( this );
//新建一个Widget
QHBoxLayout *layout = new QHBoxLayout( box );
//新建一个水平布局,父对象为box
layout->addWidget( d_plot, 10 );
//向布局中添加plot
layout->addWidget( d_panel );
//向布局中添加panel
setCentralWidget( box );
//将包含水平布局的box设置为MainWindow的核心控件
QToolBar *toolBar = new QToolBar( this );
//新建一个工具栏
QToolButton *btnExport = new QToolButton( toolBar );
//以工具栏为父对象新建一个工具按钮
btnExport->setText( "Export" );
//为工具按钮设置文字标识
toolBar->addWidget( btnExport );
//将工具按钮添加到工具栏
addToolBar( toolBar );
//将工具栏添加到MainWindow
updatePlot();
//更新画板
connect( d_panel, SIGNAL( edited() ), SLOT( updatePlot() ) );
connect( btnExport, SIGNAL( clicked() ), SLOT( exportPlot() ) );
//两个槽函数,一个用来检查面板参数是否发生变动,一个用来将图像导出
}
下面是两个槽函数
void MainWindow::updatePlot()
{
d_plot->applySettings( d_panel->settings() );
}
//一个槽函数,当面板上的信息发生改变时,面板对象会发出一个edited信号,MainWindow会接收到
void MainWindow::exportPlot()
{
QwtPlotRenderer renderer;
renderer.exportTo( d_plot, "legends.pdf" );
}
//一个槽函数,绑定在一个按钮上,用来将图像导出
Panel类
#include "settings.h"
#include <qwidget.h>
class QCheckBox;
class QComboBox;
class QSpinBox;
class QLineEdit;
class Panel: public QWidget
{
Q_OBJECT
public:
Panel( QWidget *parent = NULL );
void setSettings( const Settings &);
Settings settings() const;
Q_SIGNALS:
void edited();
private:
struct
{
QCheckBox *checkBox;
QComboBox *positionBox;
} d_legend;
struct
{
QCheckBox *checkBox;
QSpinBox *numColumnsBox;
QComboBox *hAlignmentBox;
QComboBox *vAlignmentBox;
QComboBox *backgroundBox;
QSpinBox *sizeBox;
} d_legendItem;
struct
{
QSpinBox *numCurves;
QLineEdit *title;
} d_curve;
};
构造函数Panel实现
Panel::Panel( QWidget *parent ):
QWidget( parent )
{
// create widgets
d_legend.checkBox = new QCheckBox( "Enabled" );
d_legend.positionBox = new QComboBox();
d_legend.positionBox->addItem( "Left", QwtPlot::LeftLegend );
d_legend.positionBox->addItem( "Right", QwtPlot::RightLegend );
d_legend.positionBox->addItem( "Bottom", QwtPlot::BottomLegend );
d_legend.positionBox->addItem( "Top", QwtPlot::TopLegend );
d_legend.positionBox->addItem( "External", QwtPlot::TopLegend + 1 );
d_legendItem.checkBox = new QCheckBox( "Enabled" );
d_legendItem.numColumnsBox = new QSpinBox();
d_legendItem.numColumnsBox->setRange( 0, 10 );
d_legendItem.numColumnsBox->setSpecialValueText( "Unlimited" );
d_legendItem.hAlignmentBox = new QComboBox();
d_legendItem.hAlignmentBox->addItem( "Left", Qt::AlignLeft );
d_legendItem.hAlignmentBox->addItem( "Centered", Qt::AlignHCenter );
d_legendItem.hAlignmentBox->addItem( "Right", Qt::AlignRight );
d_legendItem.vAlignmentBox = new QComboBox();
d_legendItem.vAlignmentBox->addItem( "Top", Qt::AlignTop );
d_legendItem.vAlignmentBox->addItem( "Centered", Qt::AlignVCenter );
d_legendItem.vAlignmentBox->addItem( "Bottom", Qt::AlignBottom );
d_legendItem.backgroundBox = new QComboBox();
d_legendItem.backgroundBox->addItem( "Legend",
QwtPlotLegendItem::LegendBackground );
d_legendItem.backgroundBox->addItem( "Items",
QwtPlotLegendItem::ItemBackground );
d_legendItem.sizeBox = new QSpinBox();
d_legendItem.sizeBox->setRange( 8, 22 );
d_curve.numCurves = new QSpinBox();
d_curve.numCurves->setRange( 0, 99 );
d_curve.title = new QLineEdit();
// layout
QGroupBox *legendBox = new QGroupBox( "Legend" );
QGridLayout *legendBoxLayout = new QGridLayout( legendBox );
int row = 0;
legendBoxLayout->addWidget( d_legend.checkBox, row, 0, 1, -1 );
row++;
legendBoxLayout->addWidget( new QLabel( "Position" ), row, 0 );
legendBoxLayout->addWidget( d_legend.positionBox, row, 1 );
QGroupBox *legendItemBox = new QGroupBox( "Legend Item" );
QGridLayout *legendItemBoxLayout = new QGridLayout( legendItemBox );
row = 0;
legendItemBoxLayout->addWidget( d_legendItem.checkBox, row, 0, 1, -1 );
row++;
legendItemBoxLayout->addWidget( new QLabel( "Columns" ), row, 0 );
legendItemBoxLayout->addWidget( d_legendItem.numColumnsBox, row, 1 );
row++;
legendItemBoxLayout->addWidget( new QLabel( "Horizontal" ), row, 0 );
legendItemBoxLayout->addWidget( d_legendItem.hAlignmentBox, row, 1 );
row++;
legendItemBoxLayout->addWidget( new QLabel( "Vertical" ), row, 0 );
legendItemBoxLayout->addWidget( d_legendItem.vAlignmentBox, row, 1 );
row++;
legendItemBoxLayout->addWidget( new QLabel( "Background" ), row, 0 );
legendItemBoxLayout->addWidget( d_legendItem.backgroundBox, row, 1 );
row++;
legendItemBoxLayout->addWidget( new QLabel( "Size" ), row, 0 );
legendItemBoxLayout->addWidget( d_legendItem.sizeBox, row, 1 );
QGroupBox *curveBox = new QGroupBox( "Curves" );
QGridLayout *curveBoxLayout = new QGridLayout( curveBox );
row = 0;
curveBoxLayout->addWidget( new QLabel( "Number" ), row, 0 );
curveBoxLayout->addWidget( d_curve.numCurves, row, 1 );
row++;
curveBoxLayout->addWidget( new QLabel( "Title" ), row, 0 );
curveBoxLayout->addWidget( d_curve.title, row, 1 );
QVBoxLayout *layout = new QVBoxLayout( this );
layout->addWidget( legendBox );
layout->addWidget( legendItemBox );
layout->addWidget( curveBox );
layout->addStretch( 10 );
connect( d_legend.checkBox,
SIGNAL( stateChanged( int ) ), SIGNAL( edited() ) );
connect( d_legend.positionBox,
SIGNAL( currentIndexChanged( int ) ), SIGNAL( edited() ) );
connect( d_legendItem.checkBox,
SIGNAL( stateChanged( int ) ), SIGNAL( edited() ) );
connect( d_legendItem.numColumnsBox,
SIGNAL( valueChanged( int ) ), SIGNAL( edited() ) );
connect( d_legendItem.hAlignmentBox,
SIGNAL( currentIndexChanged( int ) ), SIGNAL( edited() ) );
connect( d_legendItem.vAlignmentBox,
SIGNAL( currentIndexChanged( int ) ), SIGNAL( edited() ) );
connect( d_legendItem.backgroundBox,
SIGNAL( currentIndexChanged( int ) ), SIGNAL( edited() ) );
connect( d_curve.numCurves,
SIGNAL( valueChanged( int ) ), SIGNAL( edited() ) );
connect( d_legendItem.sizeBox,
SIGNAL( valueChanged( int ) ), SIGNAL( edited() ) );
connect( d_curve.title,
SIGNAL( textEdited( const QString & ) ), SIGNAL( edited() ) );
}
重点理解QT中的信号到信号的连接,进一步熟悉QT中布局类的使用
setSettings实现,用于设置控制面板
void Panel::setSettings( const Settings &settings)
{
blockSignals( true );
d_legend.checkBox->setCheckState(
settings.legend.isEnabled ? Qt::Checked : Qt::Unchecked );
d_legend.positionBox->setCurrentIndex( settings.legend.position );
d_legendItem.checkBox->setCheckState(
settings.legendItem.isEnabled ? Qt::Checked : Qt::Unchecked );
d_legendItem.numColumnsBox->setValue( settings.legendItem.numColumns );
int align = settings.legendItem.alignment;
if ( align & Qt::AlignLeft )
d_legendItem.hAlignmentBox->setCurrentIndex( 0 );
else if ( align & Qt::AlignRight )
d_legendItem.hAlignmentBox->setCurrentIndex( 2 );
else
d_legendItem.hAlignmentBox->setCurrentIndex( 1 );
if ( align & Qt::AlignTop )
d_legendItem.vAlignmentBox->setCurrentIndex( 0 );
else if ( align & Qt::AlignBottom )
d_legendItem.vAlignmentBox->setCurrentIndex( 2 );
else
d_legendItem.vAlignmentBox->setCurrentIndex( 1 );
d_legendItem.backgroundBox->setCurrentIndex(
settings.legendItem.backgroundMode );
d_legendItem.sizeBox->setValue( settings.legendItem.size );
d_curve.numCurves->setValue( settings.curve.numCurves );
d_curve.title->setText( settings.curve.title );
blockSignals( false );
}
settings实现,用于获取当前控制面板的设置信息
Settings Panel::settings() const
{
Settings s;
s.legend.isEnabled =
d_legend.checkBox->checkState() == Qt::Checked;
s.legend.position = d_legend.positionBox->currentIndex();
s.legendItem.isEnabled =
d_legendItem.checkBox->checkState() == Qt::Checked;
s.legendItem.numColumns = d_legendItem.numColumnsBox->value();
int align = 0;
int hIndex = d_legendItem.hAlignmentBox->currentIndex();
if ( hIndex == 0 )
align |= Qt::AlignLeft;
else if ( hIndex == 2 )
align |= Qt::AlignRight;
else
align |= Qt::AlignHCenter;
int vIndex = d_legendItem.vAlignmentBox->currentIndex();
if ( vIndex == 0 )
align |= Qt::AlignTop;
else if ( vIndex == 2 )
align |= Qt::AlignBottom;
else
align |= Qt::AlignVCenter;
s.legendItem.alignment = align;
s.legendItem.backgroundMode =
d_legendItem.backgroundBox->currentIndex();
s.legendItem.size = d_legendItem.sizeBox->value();
s.curve.numCurves = d_curve.numCurves->value();
s.curve.title = d_curve.title->text();
return s;
}
Plot类,继承自QwtPlot,一个画板类
#include <qwt_plot.h>
class Settings;
class LegendItem;
class QwtLegend;
class Plot: public QwtPlot
{
Q_OBJECT
public:
Plot( QWidget *parent = NULL );
virtual ~Plot();
public Q_SLOTS:
void applySettings( const Settings & );
public:
virtual void replot();
private:
void insertCurve();
QwtLegend *d_externalLegend;
LegendItem *d_legendItem;
bool d_isDirty;
};
构造函数Plot
Plot::Plot( QWidget *parent ):
QwtPlot( parent ),
d_externalLegend( NULL ),
d_legendItem( NULL ),
d_isDirty( false )
{
QwtPlotCanvas *canvas = new QwtPlotCanvas();
//新建一张画布
canvas->setFocusIndicator( QwtPlotCanvas::CanvasFocusIndicator );
canvas->setFocusPolicy( Qt::StrongFocus );
canvas->setPalette( Qt::black );
//设置一些画布属性,感兴趣的可以去查文档,或者上网看看别人的理解
setCanvas( canvas );
//为画板设置画布
setAutoReplot( false );
//禁止自动重绘
setTitle( "Legend Test" );
setFooter( "Footer" );
// grid
QwtPlotGrid *grid = new QwtPlotGrid;
grid->enableXMin( true );
grid->setMajorPen( Qt::gray, 0, Qt::DotLine );
grid->setMinorPen( Qt::darkGray, 0, Qt::DotLine );
grid->attach( this );
// axis
setAxisScale( QwtPlot::yLeft, 0.0, 1000.0 );
setAxisScale( QwtPlot::xBottom, 0.0, 1000.0 );
}
applySettings实现,被外部调用,用于在画板上绘制曲线
void Plot::applySettings( const Settings &settings )
{
d_isDirty = false;
setAutoReplot( true );
if ( settings.legend.isEnabled )
{
if ( settings.legend.position > QwtPlot::TopLegend )
{
if ( legend() )
{
// remove legend controlled by the plot
insertLegend( NULL );
}
if ( d_externalLegend == NULL )
{
d_externalLegend = new QwtLegend();
d_externalLegend->setWindowTitle("Plot Legend");
connect(
this,
SIGNAL( legendDataChanged( const QVariant &,
const QList<QwtLegendData> & ) ),
d_externalLegend,
SLOT( updateLegend( const QVariant &,
const QList<QwtLegendData> & ) ) );
d_externalLegend->show();
// populate the new legend
updateLegend();
}
}
else
{
delete d_externalLegend;
d_externalLegend = NULL;
if ( legend() == NULL ||
plotLayout()->legendPosition() != settings.legend.position )
{
insertLegend( new QwtLegend(),
QwtPlot::LegendPosition( settings.legend.position ) );
}
}
}
else
{
insertLegend( NULL );
delete d_externalLegend;
d_externalLegend = NULL;
}
if ( settings.legendItem.isEnabled )
{
if ( d_legendItem == NULL )
{
d_legendItem = new LegendItem();
d_legendItem->attach( this );
}
d_legendItem->setMaxColumns( settings.legendItem.numColumns );
d_legendItem->setAlignment( Qt::Alignment( settings.legendItem.alignment ) );
d_legendItem->setBackgroundMode(
QwtPlotLegendItem::BackgroundMode( settings.legendItem.backgroundMode ) );
if ( settings.legendItem.backgroundMode ==
QwtPlotLegendItem::ItemBackground )
{
d_legendItem->setBorderRadius( 4 );
d_legendItem->setMargin( 0 );
d_legendItem->setSpacing( 4 );
d_legendItem->setItemMargin( 2 );
}
else
{
d_legendItem->setBorderRadius( 8 );
d_legendItem->setMargin( 4 );
d_legendItem->setSpacing( 2 );
d_legendItem->setItemMargin( 0 );
}
QFont font = d_legendItem->font();
font.setPointSize( settings.legendItem.size );
d_legendItem->setFont( font );
}
else
{
delete d_legendItem;
d_legendItem = NULL;
}
QwtPlotItemList curveList = itemList( QwtPlotItem::Rtti_PlotCurve );
if ( curveList.size() != settings.curve.numCurves )
{
while ( curveList.size() > settings.curve.numCurves )
{
QwtPlotItem* curve = curveList.takeFirst();
delete curve;
}
for ( int i = curveList.size(); i < settings.curve.numCurves; i++ )
insertCurve();
}
curveList = itemList( QwtPlotItem::Rtti_PlotCurve );
for ( int i = 0; i < curveList.count(); i++ )
{
Curve* curve = static_cast<Curve*>( curveList[i] );
curve->setCurveTitle( settings.curve.title );
int sz = 0.5 * settings.legendItem.size;
curve->setLegendIconSize( QSize( sz, sz ) );
}
setAutoReplot( false );
if ( d_isDirty )
{
d_isDirty = false;
replot();
}
}
要点总结:
- 进一步熟悉与理解模块化编程
- 掌握QwtPlotLegendItem的使用方法