Algorithm for drawing a straight line with Shift button pressing - c++

I have line painter widget in my project. So, I have to develope algorithm, which allows to correct line to straight, when user presser Shift key. i have seen similar in Photoshop and Paint.
But my own method doesn't work. I'm working with Qt libs.
Code here. drawedPoints_ is QList of QPointF
void GesturePaintSurface::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
isDrawingFinished_ = false;
drawedPoints_.clear();
firstPoint_ = event->pos();
drawedPoints_.append(firstPoint_);
}
else
{
event->ignore();
isDrawingFinished_ = true;
}
}
void GesturePaintSurface::mouseMoveEvent(QMouseEvent *event)
{
if (!isDrawingFinished_)
{
if (isShiftPressed_)
{
QPoint newPoint;
if (abs(drawedPoints_.last().rx() - event->pos().rx()) < 5)
{
newPoint.rx() = firstPoint_.x();
newPoint.ry() = event->pos().y();
}
else
{
newPoint.rx() = event->pos().x();
newPoint.ry() = firstPoint_.y();
}
drawedPoints_.append(newPoint);
}
else
drawedPoints_.append(event->pos());
repaint();
}
}
Sorry for my language. thanks in advance!

First problem is that you are appending point every time mouse moves! Second problem is that this condition to make vertical or horizontal line is wrong.
It should be like that:
void GesturePaintSurface::mouseMoveEvent(QMouseEvent *event)
{
if (!isDrawingFinished_)
{
QPoint newPoint;
if (event->modifiers().test(Qt::ShiftModifier)) {
newPoint = drawedPoints_.last();
if (qAbs(newPoint.x()-event->x())<qAbs(newPoint.y()-event->y())) {
newPoint.setY(event->y());
} else {
newPoint.setX(event->X());
}
} else {
newPoint = event->pos();
}
if (drawedPoints_.count()>1) {
drawedPoints_.last() = newPoint;
} else {
drawedPoints_.append(newPoint);
}
update(); // update is better then repaint!
}
}

Related

How to determine mouse clicked point is inside in any QGraphicsItem from scene in Qt?

I have a QGraphicsView which contains large number of QGraphicsItem.
I want to check, mouse clicked point is inside any of QGraphicsItem or not. And if it is inside in any QGraphicsItem, that item should be highlighted.
But though the mouse clicked point is not inside in any QGraphicsItem, some of the polylines are getting highlighted.
bool myViewer::eventFilter(QObject* watched, QEvent* event)
{
bool filterEvent = false;
switch (event->type())
{
case QEvent::MouseButtonPress:
{
FindingPosition(event);
break;
}
}
}
void myViewer::FindingPosition(QEvent* event)
{
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
QPointF mousePoint = _view->mapToScene(mouseEvent->pos());
foreach(QGraphicsItem* t , _scene->items())
{
if(t->contains(t->mapFromScene(mousePoint)))
{
QGraphicsRectItem* rItem = qgraphicsitem_cast<QGraphicsRectItem*>(t);
if (rItem)
{
rItem->setSelected(false);
QPen mPen;
mPen.setWidth(1);
mPen.setBrush(Qt::red);
rItem->setPen(mPen);
break;
}
else
{
QGraphicsPathItem* pItem = qgraphicsitem_cast<QGraphicsPathItem*>(t);
if (pItem)
{
pItem->setSelected(false);
QPen mPen;
mPen.setWidth(1);
mPen.setBrush(Qt::red);
pItem->setPen(mPen);
break;
}
}
}
}
}
}

Add, move, resize, replace or delete qgraphicslineitem or another graphics object

Colleagues warned me that I was wrong to ask. That's why I completely redrafted my pervious question.
a) where best to create a new line
b) how to reliably select a specific line between 20 others
c) how best to move starting point of a line
d) how best to move end point of a line
e) how best to move line
f) how to delete a line
Everything is described in the documentation and examples, but each example chooses a different place for the actions. Someone uses the view, some scene and the other does most of the things in line. Someone uses bouding rect, another not, someone uses editing mode in view another not etc...
myscene.cpp
#include "myscene.h"
#include "myview.h"
#include "mymovingpoint.h"
#include <qgraphicsitem.h>
#include <qgraphicsview.h>
#include <qobject.h>
#include <qgraphicsview.h>
#include <qpoint.h>
#include <qmath.h>
/*
*
*
*/
myScene::myScene(QObject *parent)
: QGraphicsScene(parent)
{
myMode = myMode::InsertItem;
}
/*
*
*
*/
void myScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
# remove item added by clickevent, if doubleclicked
if(line)
{
removeItem(line);
}
# if doubleclick and left button, select existing item
if(mouseEvent->buttons().testFlag(Qt::LeftButton))
{
//QGraphicsItem *item = itemAt(mouseEvent->scenePos(), QTransform());
# itemAt() returns only the object exactly under the mouse
# function getNearObject return object 3 points around
QGraphicsItem *item = getNearObject(mouseEvent);
if(item)
{
myMode = myMode::EditItem;
myLineItem *tempLine = dynamic_cast<myLineItem*>(item);
oldLine = line;
line = tempLine;
QColor myclr;
myclr.setRgb(255,0,0,255);
line->setPen(QPen(myclr, 2));
line->addMovingPoints();
}
else
{
myMode = myMode::InsertItem;
}
}
}
/*
*
*
*/
#return nearest objects
QGraphicsItem* myScene::getNearObject(QGraphicsSceneMouseEvent *mouseEvent)
{
int roundvalue = -3;
int roundx;
int roundy;
QPointF pointf = mouseEvent->scenePos();
QPointF pointtmp;
roundx = roundvalue;
roundy = roundvalue;
while(roundy <= roundvalue*-1)
{
while(roundx <= roundvalue*-1)
{
pointtmp.setX(pointf.x()-roundx);
pointtmp.setY(pointf.y()-roundy);
QGraphicsItem *item = itemAt(pointtmp, QTransform());
if(item)
{
return item;
}
roundx += 1;
}
roundx += roundvalue;
roundy += 1;
}
return NULL;
}
/*
*
*
*/
void myScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
if(mouseEvent->buttons().testFlag(Qt::LeftButton))
{
QGraphicsItem *item = itemAt(mouseEvent->scenePos(), QTransform());
if(myMode == myMode::InsertItem)
{
if(oldLine)
{
myLineColor.setRgb(213, 182, 10, 255);
oldLine->setPen(QPen(myLineColor, 2));
}
}
if(myMode == myMode::EditItem)
{
myLineItem *tempLine = dynamic_cast<myLineItem*>(item);
if(tempLine)
{
oldLine = line;
line = tempLine;
QColor myclr;
myclr.setRgb(255,0,0,255);
line->setPen(QPen(myclr, 2));
myMovingPoint myPoint(line);
}
}
else if(myMode == myMode::InsertItem)
{
oldLine = line;
if(mouseEvent->modifiers() & Qt::ControlModifier)
{
line = new myLineItem(QLineF(toNearest5(mouseEvent->scenePos()), toNearest5(mouseEvent->scenePos())));
}
else
{
line = new myLineItem(QLineF(mouseEvent->scenePos(), mouseEvent->scenePos()));
}
myLineColor.setRgb(213, 182, 10, 255);
line->setPen(QPen(myLineColor, 2));
}
else
{
QGraphicsScene::mousePressEvent(mouseEvent);
}
}
}
/*
*
*
*/
void myScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
if(!items().contains(line))
{
addItem(line);
}
if(mouseEvent->buttons().testFlag(Qt::LeftButton))
{
QLineF newLine;
if(myMode == myMode::InsertItem)
{
if(mouseEvent->modifiers() & Qt::ControlModifier)
{
newLine = QLineF(toNearest5(line->line().p1()), toNearest5(mouseEvent->scenePos()));
}
else
{
newLine = QLineF(line->line().p1(), mouseEvent->scenePos());
}
myLineColor.setRgb(213, 182, 10, 255);
line->setLine(newLine);
update();
}
else if(myMode == myMode::EditItem)
{
QLineF newLine = QLineF(line->line().p1(), mouseEvent->scenePos());
line->setLine(newLine);
update();
}
}
QGraphicsScene::mouseMoveEvent(mouseEvent);
}
/*
*
*
*/
void myScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
myMode = myMode::InsertItem;
QGraphicsScene::mouseReleaseEvent(mouseEvent);
}
/*
*
*
*/
void myScene::keyPressEvent(QKeyEvent * keyEvent)
{
if(keyEvent->key() == Qt::Key_Delete)
{
if(line)
{
removeItem(line);
}
}
}
/*
*
*
*/
QPointF myScene::toNearest5(QPointF i)
{
int shift = 10;
int r = i.x();
int s = i.y();
r = (i.x()+5.0)/10;
s = (i.y()+5.0)/10;
r = r*10;
s = s*10;
QPointF output = QPointF(r, s);
return (output);
}
mysceneview.cpp
#include "myview.h"
#include <qmath.h>
#include <qmatrix.h>
myView::myView(QGraphicsScene *scene, QWidget *parent)
: QGraphicsView(scene, parent)
{
}
void myView::keyPressEvent(QKeyEvent *event)
{
QGraphicsView::keyPressEvent(event);
}
void myView::keyReleaseEvent(QKeyEvent *event)
{
QGraphicsView::keyReleaseEvent(event);
}
void myView::enterEvent(QEvent *event)
{
viewport()->setCursor(Qt::ArrowCursor);
QGraphicsView::enterEvent(event);
}
void myView::mousePressEvent(QMouseEvent* event)
{
if (event->modifiers() & Qt::ControlModifier)
{
viewport()->setCursor(Qt::ArrowCursor);
_lastPos = QPoint(event->pos());
//_lastPos = QPoint(event->pos().x()-event->pos().x()%5, event->pos().y()-event->pos().y()%5);
}
else
{
viewport()->setCursor(Qt::ArrowCursor);
_lastPos = event->pos();
}
QGraphicsView::mousePressEvent(event);
}
void myView::mouseMoveEvent(QMouseEvent* event)
{
viewport()->setCursor(Qt::ArrowCursor);
if (event->buttons().testFlag(Qt::RightButton))
{
QScrollBar *hBar = horizontalScrollBar();
QScrollBar *vBar = verticalScrollBar();
QPoint delta = event->pos() - _lastPos;
_lastPos = event->pos();
hBar->setValue(hBar->value() + (isRightToLeft() ? delta.x() : -delta.x()));
vBar->setValue(vBar->value() - delta.y());
//event->ignore();
}
QGraphicsView::mouseMoveEvent(event);
}
void myView::mouseReleaseEvent(QMouseEvent* event)
{
viewport()->setCursor(Qt::ArrowCursor);
QGraphicsView::mouseReleaseEvent(event);
}
#if QT_CONFIG(wheelevent)
void myView::wheelEvent(QWheelEvent *e)
{
if (e->delta() > 0)
{
x=x+0.1;
qreal scale = x;
QMatrix matrix;
matrix.scale(scale, scale);
setMatrix(matrix);
//zoomIn(6);
}
else
{
x=x-0.1;
qreal scale = x;
QMatrix matrix;
matrix.scale(scale, scale);
setMatrix(matrix);
//zoomOut(6);
}
e->accept();
}
#endif
you should define in your model, what's a scene, what's a view, and what is and an item.
logically this is how it goes:
scene: collection of drawable objects, cannot be viewed.
view: a window on the scene, if the object belonging to the scene is in this window, it is shown, if it is not then it's occluded
item: is a draw-able object, stores the position of its vertex in object coordinate.
when you draw you draw in the view, then the object stores the points in its object space coordinate, they will be constant during zooms, moves, rotations and pans, they change only when you select the vertex and move it in the view.
so mylineitem is only a container for an absolute coordinate.
scene is a container of all the mylineitem, just a list of objects
view is your controller of the way the system draws the items of the scene.
this model allows you to export your drawable items either individually or as a scene without worrying about remaping the points to the new coordinate space of the new view.
Do all your object editing in the view, because it defines the distance between the points in its coordinate system.
expl:
view, coordinate system: Cartesian, 10x10x10 cm
your draw a line p1-p2
p1(0,0,0) origin of the object space, p2(1,1,1) and it maps in the view to p1view(3,5,4) expl and p2view(13,15,14) in view coordinate. means each unit in object space is 10cm in view space.
export this line to another view where system: 20x20x20 cm then line keeps its relative size and changes its coordinate to preserve it.

pan when mousewheel pressed in Qt C++

I've got an application which handles zooming in/out using the mouse wheel with this event in Qt Creator.
cpp
void QNodeView::wheelEvent(QWheelEvent* event) {
setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
// Scale the view / do the zoom
double scaleFactor = 1.15;
if(event->delta() > 0) {
// Zoom in
scale(scaleFactor, scaleFactor);
} else {
// Zooming out
scale(1.0 / scaleFactor, 1.0 / scaleFactor);
}
}
This is in the header file
h
protected:
//Take over the interaction
virtual void wheelEvent(QWheelEvent* event);
How can I add the ability to pan with the middle mouse button being pressed the user dragging the cursor?
I can post the project code if necessary just ask.
Thanks
Project files link (Qt Creator project)
https://www.dropbox.com/s/gbt4qqtdedltxek/QNodesEditor-master_01.zip?dl=0
At first, introduce some new member variables into your viewer class:
class QNodeView : public QGraphicsView
{
// ...
private:
int m_originalX = 0;
int m_originalY = 0;
bool m_moving = false;
};
Then reimplement mousePressEvent(), mouseMoveEvent(), and mouseReleaseEvent().
void QNodeView::mousePressEvent(QMouseEvent* event)
{
if (event->button() == Qt::MiddleButton)
{
// store original position
m_originalX = event->x();
m_originalY = event->y();
// set the "moving" state
m_moving = true;
}
}
void QNodeView::mouseMoveEvent(QMouseEvent* event)
{
if (m_moving)
{
// panning operates in the scene coordinates using x,y
QPointF oldp = mapToScene(m_originalX, m_originalY);
QPointF newp = mapToScene(event->pos());
QPointF translation = newp - oldp;
translate(translation.x(), translation.y());
m_originalX = event->x();
m_originalY = event->y();
}
}
void QNodeView::mouseReleaseEvent(QMouseEvent* event)
{
if (event->button() == Qt::MiddleButton)
{
m_moving = false;
}
}

Using QtimerEvent in QGraphicsScene

The timerEvent, which is a member of a QGLWidget class shall be triggered when the mousemove-function is called. I thought I could do it like this:
void GLWidget::timerEvent(QTimerEvent *e)
{
if (e->timerId()==1 && refresh==true)
{
refresh = !refresh;
swapBuffers();
update();
}
}
It looks like this:
void OpenGLScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
int mousex = event->scenePos().x();
int mousey = event->scenePos().y();
if ((test->modus==2) && (test->move1 != -1))
{
p_list[test->move1].x=mousex-(1220);
p_list[test->move1].y=mousey-( 610);
test->refresh = !(test->refresh);
test->timerEvent(???);
update();
}
}
But somehow I dont know what to put into where the questions marks are. I have tried several things. It is not working. I want to set timerId()=1.
Thanks for your help...
why don't you call your own event like :
void OpenGLScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
// ...
if ((test->modus==2) && (test->move1 != -1))
{
// ...
test->refresh = !(test->refresh);
//test->timerEvent(???); replaced by :
test->manuelUpdate(); // your own function
//...
}
}
and in your GLWidget :
void GLWidget::manuelUpdate()
{
if (refresh==true)
{
refresh = !refresh;
swapBuffers();
update();
}
}

Qt Creator, C++, mouse over function

I want to change the color of an ellipse when I move my mouse over it.
But I haven't found anything from reference and auto-complete from Qt Creator.
Do you guys know how to do it?
Some of my code:
void DrawingWidget::paintEvent(QPaintEvent *event) {
QPainter painter(this);
painter.fillRect(event->rect(), Qt::white);
for(int i = 0; i < pointList.size(); i++) {
if (pointList[i].x() >= 0 && pointList[i].y() >= 0)
painter.drawEllipse(pointList[i], 10, 10);
}
painter.drawLines(lineList);
m_mainWindow->updateCount();
}
Mouse press event handler:
void DrawingWidget::mousePressEvent(QMouseEvent *event) {
if (event->button() == Qt::LeftButton
&& event->buttons() == Qt::LeftButton) {
// DO STUFFF
}
}
Mouse move event handler:
void DrawingWidget::mouseMoveEvent(QMouseEvent *event) {
if (m_mainWindow->getSelectedTool() == MainWindow::moveVertexTool) {
m_x = event->x();
m_y = event->y();
if (isPointNear(m_x, m_y)) {
//STUFF
}
update();
}
}
}
Now I just need a mouse OVER event (handler).
I think what you are looking for are enter and leave events.
Use QWidget::underMouse() for check if the widget is under the mouse cursor.
For example:
void IconButton::paintEvent(QPaintEvent *)
{
QPainter painter(this);
// Note isDown should really use the active state but in most styles
// this has no proper feedback
QIcon::Mode mode = QIcon::Disabled;
if (isEnabled()) {
if (isDown())
mode = QIcon::Selected;
else
mode = underMouse() ? QIcon::Active : QIcon::Normal;
}
QPixmap pixmap = icon().pixmap(iconSize(), mode);
QRect pixmapRect = QRect(0, 0, pixmap.width(), pixmap.height());
pixmapRect.moveCenter(rect().center());
if (m_autoHide)
painter.setOpacity(m_iconOpacity);
painter.drawPixmap(pixmapRect, pixmap);
}
This value is not updated properly during drag and drop operations.