19 #include <QDragEnterEvent> 22 #include <QFileDialog> 23 #include <QFontMetrics> 25 #include <QTextStream> 28 #include <qwt/qwt_plot_canvas.h> 29 #include <qwt/qwt_plot_curve.h> 30 #include <qwt/qwt_plot_picker.h> 31 #include <qwt/qwt_plot_renderer.h> 32 #include <qwt/qwt_scale_widget.h> 33 #include <qwt/qwt_plot.h> 47 #include <ui_PlotWidget.h> 60 timer_(new QTimer(this)),
61 menuImportExport_(new QMenu(this)),
73 qRegisterMetaType<BoundingRectangle>(
"BoundingRectangle");
80 "rqt_multiplot").
append(
"/resource/16x16/run.png")));
82 "rqt_multiplot").
append(
"/resource/16x16/pause.png")));
84 "rqt_multiplot").
append(
"/resource/16x16/zoom_in.png")));
86 "rqt_multiplot").
append(
"/resource/16x16/zoom_out.png")));
89 ui_->pushButtonClear->setIcon(
91 append(
"/resource/16x16/clear.png"))));
92 ui_->pushButtonImportExport->setIcon(
94 append(
"/resource/16x16/eject.png"))));
95 ui_->pushButtonSetup->setIcon(
97 append(
"/resource/16x16/setup.png"))));
100 ui_->plot->setAutoReplot(
false);
101 static_cast<QFrame*
>(
ui_->plot->canvas())->setFrameStyle(QFrame::NoFrame);
103 ui_->plot->enableAxis(QwtPlot::xTop);
104 ui_->plot->enableAxis(QwtPlot::yRight);
106 ui_->plot->setAxisAutoScale(QwtPlot::yLeft,
false);
107 ui_->plot->setAxisAutoScale(QwtPlot::yRight,
false);
108 ui_->plot->setAxisAutoScale(QwtPlot::xTop,
false);
109 ui_->plot->setAxisAutoScale(QwtPlot::xBottom,
false);
111 ui_->plot->axisScaleDraw(QwtPlot::xTop)->enableComponent(
112 QwtAbstractScaleDraw::Labels,
false);
113 ui_->plot->axisScaleDraw(QwtPlot::yRight)->enableComponent(
114 QwtAbstractScaleDraw::Labels,
false);
116 ui_->horizontalSpacerRight->changeSize(
117 ui_->plot->axisWidget(QwtPlot::yRight)->width()-5, 20);
119 timer_->setInterval(1e3/30.0);
127 QwtPlotCanvas* canvas =
static_cast<QwtPlotCanvas*
>(
ui_->plot->canvas());
132 zoomer_->setTrackerMode(QwtPicker::AlwaysOff);
134 #if QWT_VERSION >= 0x060100 136 QwtPlot::xBottom).lowerBound());
138 QwtPlot::yLeft).lowerBound());
140 QwtPlot::xBottom).upperBound());
142 QwtPlot::yLeft).upperBound());
145 QwtPlot::xBottom)->lowerBound());
147 QwtPlot::yLeft)->lowerBound());
149 QwtPlot::xBottom)->upperBound());
151 QwtPlot::yLeft)->upperBound());
154 connect(
ui_->lineEditTitle, SIGNAL(textChanged(
const QString&)),
this,
156 connect(
ui_->lineEditTitle, SIGNAL(editingFinished()),
this,
159 connect(
ui_->pushButtonRunPause, SIGNAL(clicked()),
this,
161 connect(
ui_->pushButtonClear, SIGNAL(clicked()),
this,
163 connect(
ui_->pushButtonSetup, SIGNAL(clicked()),
this,
165 connect(
ui_->pushButtonImportExport, SIGNAL(clicked()),
this,
167 connect(
ui_->pushButtonState, SIGNAL(clicked()),
this,
170 connect(
ui_->plot->axisWidget(QwtPlot::xBottom),
172 connect(
ui_->plot->axisWidget(QwtPlot::yLeft),
177 ui_->plot->axisWidget(QwtPlot::yLeft)->installEventFilter(
this);
178 ui_->plot->axisWidget(QwtPlot::yRight)->installEventFilter(
this);
192 disconnect(
config_, SIGNAL(titleChanged(
const QString&)),
this,
194 disconnect(
config_, SIGNAL(curveAdded(
size_t)),
this,
196 disconnect(
config_, SIGNAL(curveRemoved(
size_t)),
this,
198 disconnect(
config_, SIGNAL(curvesCleared()),
this,
200 disconnect(
config_, SIGNAL(curveConfigChanged(
size_t)),
this,
208 disconnect(
config_, SIGNAL(plotRateChanged(
double)),
this,
217 connect(config, SIGNAL(titleChanged(
const QString&)),
this,
219 connect(config, SIGNAL(curveAdded(
size_t)),
this,
221 connect(config, SIGNAL(curveRemoved(
size_t)),
this,
223 connect(config, SIGNAL(curvesCleared()),
this,
225 connect(config, SIGNAL(curveConfigChanged(
size_t)),
this,
233 connect(config, SIGNAL(plotRateChanged(
double)),
this,
242 for (
size_t index = 0; index < config->
getNumCurves(); ++index)
256 for (
size_t index = 0; index <
curves_.count(); ++index)
272 for (
size_t index = 0; index <
curves_.count(); ++index)
281 ui_->plot->setAxisScale(QwtPlot::xBottom, bounds.
getMinimum().x() - 0.1,
284 ui_->plot->setAxisScale(QwtPlot::xBottom, bounds.
getMinimum().x(),
287 ui_->plot->setAxisScale(QwtPlot::yLeft, bounds.
getMinimum().y() - 0.1,
290 ui_->plot->setAxisScale(QwtPlot::yLeft, bounds.
getMinimum().y(),
329 ui_->pushButtonState->setEnabled(can);
333 return ui_->pushButtonState->isEnabled();
344 for (
size_t index = 0; index <
curves_.count(); ++index)
355 for (
size_t index = 0; index <
curves_.count(); ++index)
367 for (
size_t index = 0; index <
curves_.count(); ++index)
396 QRectF plotBounds = bounds;
398 if (plotBounds.isEmpty())
399 plotBounds = QRectF(0, 0, pixmap.width(), pixmap.height());
401 QwtPlotRenderer renderer;
403 renderer.setDiscardFlag(QwtPlotRenderer::DiscardBackground,
true);
404 renderer.setDiscardFlag(QwtPlotRenderer::DiscardCanvasBackground,
true);
406 QPainter painter(&pixmap);
407 size_t textHeight = 0;
410 textHeight = painter.fontMetrics().boundingRect(
config_->
411 getTitle()).height();
413 painter.drawText(QRectF(plotBounds.x(), plotBounds.y(),
414 plotBounds.width(), textHeight), Qt::AlignHCenter |
418 renderer.render(
ui_->plot, &painter, QRectF(plotBounds.x(),
419 plotBounds.y()+textHeight+10, plotBounds.width(), plotBounds.
420 height()-textHeight-10));
424 formattedData.clear();
426 for (
size_t index = 0; index <
curves_.count(); ++index) {
427 QStringList formattedX, formattedY;
429 curves_[index]->getData()->writeFormatted(formattedX, formattedY);
431 formattedData.append(formattedX);
432 formattedData.append(formattedY);
437 formattedAxisTitles) {
438 formattedAxisTitles.clear();
440 for (
size_t index = 0; index <
curves_.count(); ++index) {
446 QString xAxisTitle = xAxisConfig->
getTopic();
447 QString yAxisTitle = yAxisConfig->
getTopic();
450 xAxisTitle +=
"/"+xAxisConfig->
getField();
452 xAxisTitle +=
"/recceipt_time";
455 yAxisTitle +=
"/"+yAxisConfig->
getField();
457 yAxisTitle +=
"/recceipt_time";
459 formattedAxisTitles.append(xAxisTitle);
460 formattedAxisTitles.append(yAxisTitle);
465 QPixmap pixmap(1280, 1024);
467 pixmap.fill(Qt::transparent);
470 pixmap.save(fileName,
"PNG");
474 QFile file(fileName);
476 if (file.open(QIODevice::WriteOnly)) {
477 QStringList formattedAxisTitles;
478 QList<QStringList> formattedData;
483 QTextStream stream(&file);
485 stream <<
"# " << formattedAxisTitles.join(
", ") <<
"\n";
490 QStringList dataLineParts;
491 bool finished =
true;
493 for (
size_t column = 0; column < formattedData.count(); ++column) {
494 if (row < formattedData[column].count()) {
495 dataLineParts.append(formattedData[column][row]);
499 dataLineParts.append(QString());
503 stream << dataLineParts.join(
", ") <<
"\n";
515 event->acceptProposedAction();
524 QDataStream stream(&data, QIODevice::ReadOnly);
527 stream >> *curveConfig;
530 curveConfig->
setTitle(
"Copy of "+curveConfig->getTitle());
532 event->acceptProposedAction();
539 if ((
object ==
ui_->plot->axisWidget(QwtPlot::yLeft)) &&
540 (event->type() == QEvent::Resize)) {
541 ui_->horizontalSpacerLeft->changeSize(
542 ui_->plot->axisWidget(QwtPlot::yLeft)->width(), 20);
545 else if ((
object ==
ui_->plot->axisWidget(QwtPlot::yRight)) &&
546 (event->type() == QEvent::Resize)) {
547 ui_->horizontalSpacerRight->changeSize(
548 ui_->plot->axisWidget(QwtPlot::yRight)->width()-5, 20);
557 QwtPlot::yLeft : QwtPlot::xBottom;
566 QStringList titleParts;
570 getAxisConfig(curveAxis);
572 QString titlePart = curveAxisConfig->
getTopic();
574 titlePart +=
"/"+curveAxisConfig->
getField();
576 titlePart +=
"/receipt_time";
578 if (!titleParts.contains(titlePart))
579 titleParts.append(titlePart);
582 ui_->plot->setAxisTitle(plotAxis, QwtText(titleParts.join(
", ")));
585 ui_->plot->setAxisTitle(plotAxis, QwtText(plotAxisConfig->
589 ui_->plot->setAxisTitle(plotAxis, QwtText());
612 connect(curve, SIGNAL(replotRequested()),
this,
637 for (
size_t index = 0; index <
curves_.count(); ++index) {
667 ui_->plot->insertLegend(
legend_, QwtPlot::TopLegend);
670 ui_->plot->insertLegend(0);
676 timer_->setInterval(1e3/rate);
686 QFontMetrics fontMetrics(
ui_->lineEditTitle->font());
688 ui_->lineEditTitle->setMinimumWidth(
689 std::max(100, fontMetrics.width(text)+10));
717 if (dialog.exec() == QDialog::Accepted)
734 QFileDialog dialog(
this,
"Save Image File", QDir::homePath(),
735 "Portable Network Graphics (*.png)");
737 dialog.setAcceptMode(QFileDialog::AcceptSave);
738 dialog.setFileMode(QFileDialog::AnyFile);
739 dialog.selectFile(
"rqt_multiplot.png");
741 if (dialog.exec() == QDialog::Accepted)
746 QFileDialog dialog(
this,
"Save Text File", QDir::homePath(),
747 "Text file (*.txt)");
749 dialog.setAcceptMode(QFileDialog::AcceptSave);
750 dialog.setFileMode(QFileDialog::AnyFile);
751 dialog.selectFile(
"rqt_multiplot.txt");
753 if (dialog.exec() == QDialog::Accepted)
758 #if QWT_VERSION >= 0x060100 759 const QwtScaleDiv& scale =
ui_->plot->axisScaleDiv(QwtPlot::xBottom);
761 const QwtScaleDiv& scale = *
ui_->plot->axisScaleDiv(QwtPlot::xBottom);
764 ui_->plot->setAxisScaleDiv(QwtPlot::xTop, scale);
773 #if QWT_VERSION >= 0x060100 774 const QwtScaleDiv& scale =
ui_->plot->axisScaleDiv(QwtPlot::yLeft);
776 const QwtScaleDiv& scale = *
ui_->plot->axisScaleDiv(QwtPlot::yLeft);
779 ui_->plot->setAxisScaleDiv(QwtPlot::yRight, scale);
const QString & getTopic() const
static const QString MimeType
PlotAxesConfig * getAxesConfig() const
QVector< CurveConfig * > findCurves(const QString &title) const
PlotConfigWidget * getWidget() const
QRectF getRectangle() const
void attach(QwtPlot *plot)
TitleType getTitleType() const
void setBroker(MessageBroker *broker)
PlotLegendConfig * getLegendConfig() const
PlotAxisConfig * getAxisConfig(Axis axis) const
FieldType getFieldType() const
const QString & getTitle() const
const QString & getField() const
double getPlotRate() const
ROSLIB_DECL std::string getPath(const std::string &package_name)
CurveConfig * getCurveConfig(size_t index) const
size_t getNumCurves() const
void setTitle(const QString &title)
ROSCPP_DECL std::string append(const std::string &left, const std::string &right)
void setTitle(const QString &title)
void setConfig(CurveConfig *config)
bool isTitleVisible() const