Век живи, век учись! Вот так выглядит код, который заставляет правильно работать масштабирование:
class PlotSettings
{
public:
double minX;
double maxX;
int numXTicks;
double minY;
double maxY;
int numYTicks;
protected:
static void adjustAxis(double& min, double& max, int& numTicks);
public:
PlotSettings();
void scroll(int dx, int dy);
void scale(double delta_x, double delta_y);
void adjust();
double spanX() const { return fabs(maxX - minX); }
double spanY() const { return fabs(maxY - minY); }
};
/// Увеличение/уменьшение значения minX, maxX, minY, maxY на интервал между 2-мя отметками
void PlotSettings::scale(double delta_x, double delta_y)
{
if((minX == maxX || minY == maxY) && delta_x < 0 && delta_y < 0) return;
double stepX = spanX() / numXTicks;
minX -= delta_x * stepX;
maxX += delta_x * stepX;
double stepY = spanY() / numYTicks;
minY -= delta_y * stepY;
maxY += delta_y * stepY;
}
/// Класс для отображения параметров по времени или по расстоянию
class GraphicDisplay : public QDialog, public Ui::GraphicDisplayClass
{
Q_OBJECT
private:
QMap<int, QVector<QPointF>> curveMap; ///< список всех изображаемых кривых
ParamPlotSettings settings; ///< настройка для определения масштаба
QRubberBand* rubber; ///< "резиновая лента"
QPoint origin; ///< начальные координаты выделяемой области
bool rubberBandIsShown; ///< флажок попадания курсора в "резиновую ленту"
QPen myPen; ///< карандаш для рисования линий определенной жирности и цвета
enum { MARGIN = 10 };
QPainter painter; ///< рисовальщик
QVector<QPointF> data; ///< вектор загружаемой кривой
private:
void drawGrid(QPainter* painter);
void drawCurves(QPainter* painter);
void drawLegend(QPainter* painter, QRect& rect, int& k, int id);
QPointF initXY(double& sx, double& sy);
protected:
void paintEvent(QPaintEvent* events);
void keyPressEvent(QKeyEvent* events);
void wheelEvent(QWheelEvent* events);
void mousePressEvent(QMouseEvent* events);
void mouseMoveEvent(QMouseEvent* events);
void mouseReleaseEvent(QMouseEvent* events);
void resizeEvent(QResizeEvent* events) { QDialog::resizeEvent(events); update(); }
void closeEvent(QCloseEvent* events) { QDialog::closeEvent(events); }
void showEvent(QShowEvent* events) { QDialog::showEvent(events); }
public:
GraphicDisplay(QWidget *parent = 0);
GraphicDisplay(QWidget *parent, ParamPlotSettings& st);
~GraphicDisplay();
void zoom(double delta) { settings.scale(delta, delta); settings.adjust(); update(); }
void setPlotSettings(const ParamPlotSettings& sts) { settings = sts; settings.adjust(); update(); }
/// Изменение масштаба при движении колесика
void GraphicDisplay::wheelEvent(QWheelEvent* events)
{
int numDegrees = events -> delta() / 8;
double numTicks = numDegrees / 15.0;
zoom(numTicks);
update();
}
/// Нажатие на кнопки клавиатуры
void GraphicDisplay::keyPressEvent(QKeyEvent* events)
{
switch(events -> key())
{
case Qt::Key_Plus:
zoom(1.0);
break;
case Qt::Key_Minus:
zoom(-1.0);
break;
case Qt::Key_Left:
settings.scroll(-1, 0);
update();
break;
case Qt::Key_Right:
settings.scroll(1, 0);
update();
break;
case Qt::Key_Up:
settings.scroll(0, 1);
update();
break;
case Qt::Key_Down:
settings.scroll(0, -1);
update();
break;
default:
QWidget::keyPressEvent(events);
}
}
/// Отрисовка сетки
void GraphicDisplay::drawGrid(QPainter* painter)
{
QRect rect(paramsDisplay -> rect());
if(!rect.isValid()) return;
QRect boundString;
int _max = max(settings.numXTicks, settings.numYTicks);
for(int i=0, j=0, k=0; i<=_max; ++i, ++j, ++k)
{
if(j <= settings.numXTicks) ///< отрисовка по оси X
{
int x = rect.left() + (j * (rect.width() - 1) / settings.numXTicks);
double label = settings.minX + (j * settings.spanX() / settings.numXTicks);
QString s_label = round(label);
painter -> setPen(Qt::black);
painter -> drawLine(x, rect.top(), x, rect.bottom());
if(j != settings.numXTicks)
{
int flags = Qt::AlignHCenter | Qt::AlignTop;
boundString = painter -> boundingRect(boundString, flags, s_label);
painter -> drawText(x - (boundString.width() + 5), rect.bottom() - (boundString.height() + 5),
boundString.width(), boundString.height(), flags, s_label);
}
}
if(k <= settings.numYTicks) ///< отрисовка по оси Y
{
int y = rect.bottom() - (k * (rect.height() - 1) / settings.numYTicks);
double label = settings.minY + (k * settings.spanY() / settings.numYTicks);
QString s_label = round(label);
painter -> setPen(Qt::black);
painter -> drawLine(rect.left(), y, rect.right(), y);
if(k != settings.numYTicks)
{
int flags = Qt::AlignRight | Qt::AlignTop;
boundString = painter -> boundingRect(boundString, flags, s_label);
painter -> drawText(rect.left() + 5, y - boundString.height(),
boundString.width(), boundString.height(), flags, s_label);
}
}
}
painter -> drawRect(rect.adjusted(0, 0, -1, -1));
}
/// Отрисовка легенды
void GraphicDisplay::drawLegend(QPainter* painter, QRect& rect, int& k, int id)
{
QString pname = fact_prm[id].param_name;
QString dimension = fact_prm[id].dimension;
myPen.setWidth(1);
painter -> drawLine(QLineF(QPointF(rect.right() - 45, rect.top() + 25 * k),
QPointF(rect.right() - 65, rect.top() + 25 * k)));
painter -> setPen(Qt::black);
int flags = Qt::AlignCenter;
QRect boundString = painter -> boundingRect(boundString, flags, pname);
painter -> drawText(QPointF(rect.right() - (boundString.width() + 7), rect.top() + 25 * k), pname);
boundString = painter -> boundingRect(boundString, flags, dimension);
painter -> drawText(QPointF(rect.right() - (boundString.width() + 7),
rect.bottom() - 2 * boundString.height()), dimension);
++k;
}
/// Инициализация координат
QPointF GraphicDisplay::initXY(double& sx, double& sy)
{
QRect rect(paramsDisplay -> rect());
double dx, dy;
dx = sx - settings.minX;
dy = sy - settings.minY;
double x = rect.left() + (dx * (rect.width() - 1) / settings.spanX());;
double y = rect.bottom() - (dy * (rect.height() - 1) / settings.spanY());
return QPointF(x, y);
}
/// Отрисовка графика
void GraphicDisplay::drawCurves(QPainter* painter)
{
QRect rect(paramsDisplay -> rect());
if(!rect.isValid()) return;
painter -> setClipRect(rect.adjusted(1, 1, -1, -1));
QMapIterator<int, QVector<QPointF>> iter(curveMap);
int k = 1;
while(iter.hasNext())
{
iter.next();
int id = iter.key();
TP_PARAM ty = fact_prm[id].type;
if(settings.win_type != ty) continue;
const QVector<QPointF> &data = iter.value();
QPolygonF polyline(data.count());
for(int j=0; j<data.count(); ++j)
{
double x = data[j].x();
double y = data[j].y();
polyline[j] = initXY(x, y);
}
QString color = fact_prm[id].param_color.name();
QPen oldPen = painter -> pen();
myPen.setColor(fact_prm[id].param_color);
painter -> setPen(myPen);
painter -> drawPolyline(polyline);
int width = myPen.width();
drawLegend(painter, rect, k, id);
painter -> setPen(oldPen);
}
}
Практически месяц я парился с этим - но в итоге решение проблемы есть! УРА, уряяяяяяяяяя...
Можете поздравить!
)))