Здравствуйте. Дело в том, что я раньше занимался программированием сетевых многопоточных приложений/баз данных, а тут вдруг приспичило прокачать скиллы работы с двумерной графикой. Вобщем, делаю небольшой графический редактор. И возникла необходимость масштабировать графические элементы,
причём, чтобы сохранялась позиция курсора мыши над элементом, т. е. чтобы во время скейлинга объекты не "уезжали" из под курсора куда-либо.
Использую для задания позиции объектов и их масштаба объект QMatrix, который потом передаю в QPainter
Код такой:
C++ (Qt)
void DrawWidget::paintEvent(QPaintEvent *pe) { // Перерисовка
QPainter painter(this);
QMatrix matrix;
matrix.scale(scale, scale); //Масштабирование
matrix.translate(xOffset, yOffset); //Транслирование системы координат
painter.setMatrix(matrix);
painter.setRenderHint( QPainter::Antialiasing );
for (int i = 0; i < objectsCount; i++)
objects[i]->Draw(&painter);
}
void DrawWidget::mousePressEvent(QMouseEvent *pe) { //Нажатие кнопки мыши
if (pe->button() == Qt::LeftButton) {
down = true;
dragStartPosition = pe->pos();
setCursor(QCursor(Qt::ClosedHandCursor));
UnHighlightAllObjects();
for (int i = 0; i < objectsCount; i++)
if (objects[i]->Belongs(pe->x() / scale - xOffset, pe->y() / scale - yOffset)) {
SelectObject(objects[i]);
return;
}
}
repaint();
}
void DrawWidget::mouseMoveEvent(QMouseEvent *pe) {//Перемещение мыши
if (!down || !(pe->buttons() & Qt::LeftButton))
return;
xOffset -= (dragStartPosition.x() - pe->x()) / scale;
yOffset -= (dragStartPosition.y() - pe->y()) / scale;
dragStartPosition = pe->pos();
repaint();
}
void DrawWidget::mouseReleaseEvent(QMouseEvent *pe) {//Отпустили кнопку мыши
down = false;
setCursor(QCursor(Qt::ArrowCursor));
}
void DrawWidget::wheelEvent(QWheelEvent *pe) { //Прокрутка колёсика мыши
float oldScale = scale;
if (invertMouse)
scale -= pe->delta() / 1000.f;
else
scale += pe->delta() / 1000.f;
if (scale > 5.f)
scale = 5.f;
if (scale < 0.1f)
scale = 0.1f;
repaint();
}
Собственно, всё, что тут делается, это изменяет систему координат QPainter'а. То есть три поля класса xOffset, yOffset и scale объявлены как qreal. Требуется дописать код в wheelEvent для изменения xOffset и yOffset в зависимости от позиции курсора над виджетом.
Исходя из
формул, можно сказать, что
scale1*x + xoffset1 = scale2*x + xoffset2 => xoffset2 = scale1*x + xoffset1 - scale2*x
Следовательно код:
C++ (Qt)
void DrawWidget::wheelEvent(QWheelEvent *pe) {
float oldScale = scale;
if (invertMouse)
scale -= pe->delta() / 1000.f;
else
scale += pe->delta() / 1000.f;
if (scale > 5.f)
scale = 5.f;
if (scale < 0.1f)
scale = 0.1f;
xOffset = ((oldScale * pe->x()) + xOffset) - (scale * pe->x());
yOffset = ((oldScale * pe->y()) + yOffset) - (scale * pe->y());
repaint();
}
должен по идее работать. Однако, когда запускаю на выполнение и пытаюсь скейлить, то создаётся впечатление, что мы приближаемся к объекту по спиралеобразной траектории и позиция над объектом курсора никак не сохраняется
Кто уже решал подобную проблему, поделитесь советом как исправить ситуацию, пожалуйста.