implemented panning the plot with the mouse

fixed: switchability of zoomByMouseWheel
fixed: 0 on axis sometimes shown as 10^{-17}...
This commit is contained in:
jkriege2 2019-01-26 22:22:46 +01:00
parent c74e87ad31
commit dabc061de9
6 changed files with 124 additions and 28 deletions

View File

@ -19,12 +19,14 @@ TestUserInteraction::TestUserInteraction(QWidget *parent) :
layout=new QGridLayout;
layForm=new QFormLayout;
layChk=new QHBoxLayout;
layChk2=new QHBoxLayout;
layout->addLayout(layChk,0,0);
layout->addLayout(layForm,1,0);
layout->addLayout(layChk2,1,0);
layout->addLayout(layForm,2,0);
// generate a JKQTPlotter and initialize some plot data
plot=new JKQTPlotter(this);
layout->addWidget(plot,2,0);
layout->addWidget(plot,3,0);
initPlot();
// add some of the default QActions from the JKQTPlotter to the window menu
@ -66,11 +68,40 @@ TestUserInteraction::TestUserInteraction(QWidget *parent) :
connect(chkGrid, SIGNAL(toggled(bool)), plot, SLOT(setGrid(bool)));
layChk->addWidget(chkGrid);
// add a checkbox to switch the grid on and off
chkLogX=new QCheckBox(tr("X log-scale"), this);
chkLogX->setChecked(false);
connect(chkLogX, SIGNAL(toggled(bool)), plot->getXAxis(), SLOT(setLogAxis(bool)));
layChk2->addWidget(chkLogX);
chkLogY=new QCheckBox(tr("Y log-scale"), this);
chkLogY->setChecked(false);
connect(chkLogY, SIGNAL(toggled(bool)), plot->getYAxis(), SLOT(setLogAxis(bool)));
layChk2->addWidget(chkLogY);
// add a spin box for plot magnification
cmbMagnification=new QComboBox(this);
cmbMagnification->addItem("25%", 0.25);
cmbMagnification->addItem("50%", 0.50);
cmbMagnification->addItem("75%", 0.75);
cmbMagnification->addItem("100%", 1);
cmbMagnification->addItem("150%", 1.5);
cmbMagnification->addItem("200%", 2);
layForm->addRow("plot magnification:", cmbMagnification);
connect(cmbMagnification, SIGNAL(currentIndexChanged(int)), this, SLOT(setPlotMagnification(int)));
cmbMagnification->setCurrentIndex(3);
// add a QComboBox that allows to set the left mouse button action for the JKQTPlotter
chkZoomByMouseWheel=new QCheckBox(this);
chkZoomByMouseWheel->setChecked(plot->getZoomByMouseWheel());
layForm->addRow("zoom by mouse wheel:", chkZoomByMouseWheel);
connect(chkZoomByMouseWheel, SIGNAL(toggled(bool)), plot, SLOT(setZoomByMouseWheel(bool)));
// add a QComboBox that allows to set the left mouse button action for the JKQTPlotter
cmbMouseAction=new QComboBox(this);
layForm->addRow("mouse action:", cmbMouseAction);
cmbMouseAction->addItem("NoMouseAction");
cmbMouseAction->addItem("PanPlot=DragPlotWindow");
cmbMouseAction->addItem("PanPlotOnMove");
cmbMouseAction->addItem("PanPlotOnRelease");
cmbMouseAction->addItem("ZoomRectangle");
cmbMouseAction->addItem("RectangleEvents");
cmbMouseAction->addItem("CircleEvents");
@ -110,6 +141,11 @@ void TestUserInteraction::setLeftMouseAction(int index)
plot->setMouseActionMode(static_cast<JKQTPlotter::MouseActionModes>(index));
}
void TestUserInteraction::setPlotMagnification(int index)
{
plot->setMagnification(cmbMagnification->itemData(index).toDouble());
}
void TestUserInteraction::plotMouseMove(double x, double y)
{
labMouseMoved->setText(QString("plotMouseMove(%1, %2)").arg(x).arg(y));

View File

@ -22,6 +22,7 @@ class TestUserInteraction : public QMainWindow
public slots:
void setLeftMouseAction(int index);
void setPlotMagnification(int index);
void plotMouseMove(double x, double y);
void plotMouseClicked(double x, double y, Qt::KeyboardModifiers modifiers, Qt::MouseButton button);
@ -40,15 +41,20 @@ class TestUserInteraction : public QMainWindow
JKQTPlotter* plot;
QGridLayout* layout;
QHBoxLayout* layChk;
QHBoxLayout* layChk2;
QFormLayout* layForm;
QCheckBox* chkPositionDisplay;
QCheckBox* chkShowToolbar;
QCheckBox* chkToolbarAlwaysOn;
QCheckBox* chkGrid;
QComboBox* cmbMouseAction;
QCheckBox* chkLogX;
QCheckBox* chkLogY;
QCheckBox* chkZoomByMouseWheel;
QLabel* labMouseAction;
QLabel* labMouseMoved;
QLabel* labMouseClicked;
QComboBox* cmbMagnification;
JKQTPXYLineGraph* graph1;
JKQTPXYLineGraph* graph2;

View File

@ -557,6 +557,11 @@ QString JKQTPCoordinateAxis::floattolabel(double data) {
QLocale loc=QLocale::system();
loc.setNumberOptions(QLocale::OmitGroupSeparator);
double belowIsZero=1e-300;
if (!getLogAxis()) {
belowIsZero=fabs(getMax()-getMin())*1e-6;
}
switch(labelType) {
case JKQTPCALTdefault: {
QString res=loc.toString(data, 'f', past_comma);
@ -569,7 +574,7 @@ QString JKQTPCoordinateAxis::floattolabel(double data) {
return res;
}; break;
case JKQTPCALTexponent: {
return QString(jkqtp_floattolatexstr(data, past_comma, remove_trail0, 1e-300, pow(10, -past_comma), pow(10, past_comma+1)).c_str());
return QString(jkqtp_floattolatexstr(data, past_comma, remove_trail0, belowIsZero, pow(10, -past_comma), pow(10, past_comma+1)).c_str());
}; break;
case JKQTPCALTexponentCharacter: {
return QString(jkqtp_floattounitstr(data, past_comma, remove_trail0).c_str());

View File

@ -1101,12 +1101,12 @@ class LIB_EXPORT JKQTBasePlotter: public QObject {
}
/** \brief return time coordinate coordinate from x-pixel */
inline double p2x(long x) const {
inline double p2x(double x) const {
return xAxis->p2x(x);
}
/** \brief return y coordinate coordinate from y-pixel */
inline double p2y(long y) const {
inline double p2y(double y) const {
return yAxis->p2x(y);
}

View File

@ -334,15 +334,22 @@ void JKQTPlotter::mouseMoveEvent ( QMouseEvent * event ) {
(mouseActionMode==JKQTPlotter::CircleEvents) ||
(mouseActionMode==JKQTPlotter::EllipseEvents) ||
(mouseActionMode==JKQTPlotter::ScribbleEvents) ||
(mouseActionMode==JKQTPlotter::PanPlotOnMove) ||
(mouseActionMode==JKQTPlotter::PanPlotOnRelease) ||
(mouseActionMode==JKQTPlotter::LineEvents) ) &&
mouseDragingRectangle && (event->buttons() & Qt::LeftButton))
{
if (mouseActionMode==JKQTPlotter::ScribbleEvents) {
if (mouseActionMode==JKQTPlotter::ScribbleEvents || mouseActionMode==JKQTPlotter::PanPlotOnMove) {
// start is last event position
mouseDragRectXStart=mouseDragRectXEnd;
mouseDragRectYStart=mouseDragRectYEnd;
mouseDragRectXStartPixel=mouseDragRectXEndPixel;
mouseDragRectYStartPixel=mouseDragRectYEndPixel;
}
mouseDragRectXEnd=plotter->p2x(event->x()/magnification);
mouseDragRectYEnd=plotter->p2y((event->y()-getPlotYOffset())/magnification);
mouseDragRectXEndPixel=event->x();
mouseDragRectYEndPixel=event->y();
paintUserAction();
event->accept();
//std::cout<<mouseZoomingTStart<<" -- "<<mouseZoomingTEnd<<std::endl;
@ -352,6 +359,17 @@ void JKQTPlotter::mouseMoveEvent ( QMouseEvent * event ) {
if ((mouseActionMode==JKQTPlotter::ScribbleEvents) && ((mouseDragRectXStart!=mouseDragRectXEnd) || (mouseDragRectYStart!=mouseDragRectYEnd)) ) {
emit userScribbleClick(mouseDragRectXEnd, mouseDragRectYEnd, event->modifiers(), false, false);
}
if ((mouseActionMode==JKQTPlotter::PanPlotOnMove) && ((mouseDragRectXStart!=mouseDragRectXEnd) || (mouseDragRectYStart!=mouseDragRectYEnd)) ) {
QRectF zoomRect= QRectF(QPointF(plotter->x2p(getXAxis()->getMin()),plotter->y2p(getYAxis()->getMax())), QPointF(plotter->x2p(getXAxis()->getMax()),plotter->y2p(getYAxis()->getMin())));
if ( (mouseLastClickX/magnification<plotter->getInternalPlotBorderLeft()) || (mouseLastClickX/magnification>plotter->getPlotWidth()+plotter->getInternalPlotBorderLeft()) ) {
zoomRect.translate(0, mouseDragRectYStartPixel-mouseDragRectYEndPixel);
} else if (((mouseLastClickY-getPlotYOffset())/magnification<plotter->getInternalPlotBorderTop()) || ((mouseLastClickY-getPlotYOffset())/magnification>plotter->getPlotHeight()+plotter->getInternalPlotBorderTop()) ) {
zoomRect.translate(mouseDragRectXStartPixel-mouseDragRectXEndPixel, 0);
} else {
zoomRect.translate(mouseDragRectXStartPixel-mouseDragRectXEndPixel, mouseDragRectYStartPixel-mouseDragRectYEndPixel);
}
setXY(plotter->p2x(zoomRect.left()), plotter->p2x(zoomRect.right()), plotter->p2y(zoomRect.bottom()), plotter->p2y(zoomRect.top()));
}
} else {
event->accept();
/*if (emitSignals)*/ //emit plotMouseMove(x, y);
@ -374,6 +392,8 @@ void JKQTPlotter::mousePressEvent ( QMouseEvent * event ){
{
mouseDragRectXStart=plotter->p2x(event->x()/magnification);
mouseDragRectYStart=plotter->p2y((event->y()-getPlotYOffset())/magnification);
mouseDragRectXEndPixel=mouseDragRectXStartPixel=event->x();
mouseDragRectYEndPixel=mouseDragRectYStartPixel=event->y();
mouseDragingRectangle=true;
oldImage=image;
event->accept();
@ -425,6 +445,8 @@ void JKQTPlotter::mouseReleaseEvent ( QMouseEvent * event ){
if (mouseDragingRectangle && event->button()==Qt::LeftButton) {
mouseDragRectXEnd=plotter->p2x(event->x()/magnification);
mouseDragRectYEnd=plotter->p2y((event->y()-getPlotYOffset())/magnification);
mouseDragRectXEndPixel=event->x();
mouseDragRectYEndPixel=event->y();
image=oldImage;
//update();
mouseDragingRectangle=false;
@ -445,6 +467,16 @@ void JKQTPlotter::mouseReleaseEvent ( QMouseEvent * event ){
emit zoomChangedLocally(xmin, xmax, ymin, ymax, this);
plotter->setXY(xmin, xmax, ymin, ymax);
} else if (mouseActionMode==JKQTPlotter::PanPlotOnRelease) {
QRectF zoomRect= QRectF(QPointF(plotter->x2p(getXAxis()->getMin()),plotter->y2p(getYAxis()->getMax())), QPointF(plotter->x2p(getXAxis()->getMax()),plotter->y2p(getYAxis()->getMin())));
if ( (mouseLastClickX/magnification<plotter->getInternalPlotBorderLeft()) || (mouseLastClickX/magnification>plotter->getPlotWidth()+plotter->getInternalPlotBorderLeft()) ) {
zoomRect.translate(0, mouseDragRectYStartPixel-mouseDragRectYEndPixel);
} else if (((mouseLastClickY-getPlotYOffset())/magnification<plotter->getInternalPlotBorderTop()) || ((mouseLastClickY-getPlotYOffset())/magnification>plotter->getPlotHeight()+plotter->getInternalPlotBorderTop()) ) {
zoomRect.translate(mouseDragRectXStartPixel-mouseDragRectXEndPixel, 0);
} else {
zoomRect.translate(mouseDragRectXStartPixel-mouseDragRectXEndPixel, mouseDragRectYStartPixel-mouseDragRectYEndPixel);
}
setXY(plotter->p2x(zoomRect.left()), plotter->p2x(zoomRect.right()), plotter->p2y(zoomRect.bottom()), plotter->p2y(zoomRect.top()));
} else if (mouseActionMode==JKQTPlotter::RectangleEvents) {
emit userRectangleFinished(x1, y1, x2-x1, y2-y1, event->modifiers());
} else if (mouseActionMode==JKQTPlotter::CircleEvents) {
@ -515,8 +547,8 @@ void JKQTPlotter::keyReleaseEvent(QKeyEvent *event) {
void JKQTPlotter::wheelEvent ( QWheelEvent * event ) {
// only react on wheel turns inside the widget, turning forward will zoom out and turning backwards will zoom in by a factor of 2
if ( (event->x()/magnification>=plotter->getInternalPlotBorderLeft()) && (event->x()/magnification<=plotter->getPlotWidth()+plotter->getInternalPlotBorderLeft()) &&
((event->y()-getPlotYOffset())/magnification>=plotter->getInternalPlotBorderTop()) && ((event->y()-getPlotYOffset())/magnification<=plotter->getPlotHeight()+plotter->getInternalPlotBorderTop()) ) {
if ( zoomByMouseWheel && ((event->x()/magnification>=plotter->getInternalPlotBorderLeft()) && (event->x()/magnification<=plotter->getPlotWidth()+plotter->getInternalPlotBorderLeft()) &&
((event->y()-getPlotYOffset())/magnification>=plotter->getInternalPlotBorderTop()) && ((event->y()-getPlotYOffset())/magnification<=plotter->getPlotHeight()+plotter->getInternalPlotBorderTop()) ) ) {
double factor=pow(2.0, 1.0*static_cast<double>(event->delta())/120.0)*2.0;
double xmin=plotter->p2x((long)round(static_cast<double>(event->x())/magnification-static_cast<double>(plotter->getPlotWidth())/factor));
double xmax=plotter->p2x((long)round(static_cast<double>(event->x())/magnification+static_cast<double>(plotter->getPlotWidth())/factor));
@ -620,6 +652,8 @@ void JKQTPlotter::updateCursor() {
QBitmap cursor(":/JKQTPlotter/jkqtp_cursor_rectangle.png");
QBitmap mask(":/JKQTPlotter/jkqtp_cursor_rectangle_mask.png");
setCursor(QCursor(cursor, mask, 9, 14));
} else if (mouseActionMode==JKQTPlotter::PanPlotOnMove || mouseActionMode==JKQTPlotter::PanPlotOnRelease) {
setCursor(QCursor(Qt::OpenHandCursor));
} else if (mouseActionMode==JKQTPlotter::CircleEvents) {
QBitmap cursor(":/JKQTPlotter/jkqtp_cursor_circle.png");
QBitmap mask(":/JKQTPlotter/jkqtp_cursor_circle_mask.png");

View File

@ -191,15 +191,15 @@ class LIB_EXPORT JKQTPlotter: public QWidget {
* This allows you to e.g. draw rectangles or lines over the plot and receive a signal, when the drawing finishes */
enum MouseActionModes {
NoMouseAction=0, /*!< \brief no action is to be performed */
DragPlotWindow=1, /*!< \brief the user can draw the current plot window while keeping the left mouse-button pushed down (=panning) */
PanPlot=DragPlotWindow, /*!< \copydoc DragPlotWindow */
ZoomRectangle=2, /*!< \brief draw a rectangle and when finish zoom to that rectangle */
RectangleEvents=3, /*!< \brief draw a rectangle and when finished execute the signal userRectangleFinished() */
CircleEvents=4, /*!< \brief draw a circle and when finished execute the signal userCircleFinished() */
EllipseEvents=5, /*!< \brief draw an ellipse and when finished execute the signal userEllipseFinished() */
LineEvents=6, /*!< \brief draw a line and when finished execute the signal userLineFinished() */
ScribbleEvents=7, /*!< \brief let the user scribble on the plot (left mouse button is kept pressed) and call userScribbleClick() for each new position */
ClickEvents=8 /*!< \brief sinply call userClickFinished() for every single-click of the mouse button */
PanPlotOnMove, /*!< \brief the user can drag the current plot window while keeping the left mouse-button pushed down (=panning), the new widow is applied/displayed whenever the mouse moves */
PanPlotOnRelease, /*!< \brief the user can drag the current plot window while keeping the left mouse-button pushed down (=panning), the new widow is applied/displayed when the left mouse button is released */
ZoomRectangle, /*!< \brief draw a rectangle and when finish zoom to that rectangle */
RectangleEvents, /*!< \brief draw a rectangle and when finished execute the signal userRectangleFinished() */
CircleEvents, /*!< \brief draw a circle and when finished execute the signal userCircleFinished() */
EllipseEvents, /*!< \brief draw an ellipse and when finished execute the signal userEllipseFinished() */
LineEvents, /*!< \brief draw a line and when finished execute the signal userLineFinished() */
ScribbleEvents, /*!< \brief let the user scribble on the plot (left mouse button is kept pressed) and call userScribbleClick() for each new position */
ClickEvents /*!< \brief sinply call userClickFinished() for every single-click of the mouse button */
};
/** \brief options of how to react to a right mouse button click */
@ -365,11 +365,6 @@ class LIB_EXPORT JKQTPlotter: public QWidget {
/*! \brief set the property menuSpecialContextMenu ( \copybrief menuSpecialContextMenu ). \details Description of the parameter menuSpecialContextMenu is: <BLOCKQUOTE>\copydoc menuSpecialContextMenu </BLOCKQUOTE>. \see menuSpecialContextMenu for more information */
void setMenuSpecialContextMenu(QMenu* menu);
/*! \brief sets the property zoomByMouseWheel ( \copybrief zoomByMouseWheel ) to the specified \a __value.
\details Description of the parameter zoomByMouseWheel is: <BLOCKQUOTE>\copydoc zoomByMouseWheel </BLOCKQUOTE>
\see zoomByMouseWheel for more information */
void setZoomByMouseWheel(bool __value);
/*! \brief returns the property zoomByMouseWheel ( \copybrief zoomByMouseWheel ).
\details Description of the parameter zoomByMouseWheel is: <BLOCKQUOTE>\copydoc zoomByMouseWheel </BLOCKQUOTE>
\see zoomByMouseWheel for more information */
@ -591,6 +586,12 @@ class LIB_EXPORT JKQTPlotter: public QWidget {
void setMouseActionMode(const MouseActionModes & __value);
/*! \brief equivalent to \c setMouseActionMode(JKQTPlotter::ZoomRectangle) */
void setZoomByMouseRectangle(bool zomByrectangle);
/*! \brief sets the property zoomByMouseWheel ( \copybrief zoomByMouseWheel ) to the specified \a __value.
\details Description of the parameter zoomByMouseWheel is: <BLOCKQUOTE>\copydoc zoomByMouseWheel </BLOCKQUOTE>
\see zoomByMouseWheel for more information */
void setZoomByMouseWheel(bool __value);
/*! \brief sets the property leftDoubleClickAction ( \copybrief leftDoubleClickAction ) to the specified \a __value.
\details Description of the parameter leftDoubleClickAction is: <BLOCKQUOTE>\copydoc leftDoubleClickAction </BLOCKQUOTE>
\see leftDoubleClickAction for more information */
@ -798,17 +799,31 @@ class LIB_EXPORT JKQTPlotter: public QWidget {
/** \brief this is set \c true if we are drawing a zoom rectangle */
bool mouseDragingRectangle;
/** \brief when zooming by moving the mouse this contains the x-coordinate the user clicked on */
/** \brief when draging the mouse this contains the x-coordinate the user clicked on (in plot coordinates) */
double mouseDragRectXStart;
/** \brief when zooming by moving the mouse this contains the x-coordinate the mouse is currently
/** \brief when draging the mouse this contains the x-coordinate the user clicked on (in pixels) */
int mouseDragRectXStartPixel;
/** \brief when draging the mouse this contains the x-coordinate the mouse is currently
* pointing to (in pixels) */
int mouseDragRectXEndPixel;
/** \brief when draging the mouse this contains the y-coordinate the mouse is currently
* pointing to (in pixels) */
int mouseDragRectYEndPixel;
/** \brief when draging the mouse this contains the x-coordinate the mouse is currently
* pointing to
*/
double mouseDragRectXEnd;
/** \brief when zooming by moving the mouse this contains the y-coordinate the user clicked on */
/** \brief when draging the mouse this contains the y-coordinate the user clicked on (in plot coordinates) */
double mouseDragRectYStart;
/** \brief when zooming by moving the mouse this contains the y-coordinate the user clicked on (in pixels) */
int mouseDragRectYStartPixel;
/** \brief when zooming by moving the mouse this contains the y-coordinate the mouse is currently
* pointing to
*/