I have a rectangle class that has 2 points, the center axes point and the size of the rectangle. Lets say I want to drag the bottom of the rectangle with the mouse but keep the top of it in the same position. What is the algorithm to find the center position and the new rectangle size based on the mouse? Thanks in advance :)
Move the center in the same direction and half the distance (in either or both X and Y) as the bottom (right-hand corner) was dragged.
I would assume a graphics API is at hand here, what is it? I also assume that you have worked out how to detect that mouse clicking onto the edge of your box, have you decided exactly how that works though? do they just need to click near it, and they then drag the exact corner or what?
I can tell you that you are going to need to log the position of the mouse when they first click and get the differance to where they are now. Half that distance, and then add it to the original centre.
EDIT
oh, for the new size, its the difference of the mouse position added onto the original size. so if the mouse has moved down (increasing y) and left (decreasing x) say 10 units each way, you make the box ten units taller and ten narrower, the centre will be 5 down and 5 left.
It would be easier to tell the difference in the mouse movement, and create a new rectangle that size. Then use the rectangle class to check for the center point. Far easier than offsetting the old center.
Related
I want to trigger where I click with the mouse on my QGraphicsView.
Problem here: this QGraphicsView is always zoomed in. But I want to get the point relative to the whole widget and not only to the viewport.
Or in other words: when I zoomed in and click on the upper left corner, the location should NOT be 0,0 (the QMousePressEvent just gives me this point). It should be the distance from there to the upper left corner of the whole sceneRectangle (or to the middle, doesn't matter).
Is there any way to do this?
Thanks for answers.
You can do what you want with Qt's mapToScene function.
I am implementing a function (Using Qt) that is supposed to move a widget to the cursor position as part of a drag and drop functionality.
I have three events that get triggered, mouse down, mouse move, and mouse up. When the mouse moves and is down, a signal is sent to the widget to move itself to the cursor; however, I have encountered some strange behavior.
This simple code:
void Block::moveToCursor()
{
block->move(block->mapFromGlobal(QCursor::pos()));
qDebug() << block->mapFromGlobal(QCursor::pos());
}
where "block" is a QLabel that is a member of Block and is a child of the window's central widget.
It produces this result:
As it can be seen in the debug output, the coordinates are flip flopping (or flickering) every time there is a pixel move. The first coordinated are correct but the second set of coordinates seem to be relative to the top right corner of the window.
I have tried all the mapping functions:
block->move(block->mapFromParent(QCursor::pos()));
-Produces a similar result with the second set of coordinates relative to the center of the window.
block->move(block->mapFrom(this->block, QCursor::pos()));
-This produces an even stranger result. The block does not flicker and moves correctly with respect to the mouse, but the initial position of the block seems to be off by the distance from the top right corner of the computer screen. It also only shows one point when printed out in debug, yet it is moving on the screen. Every time you see Continue Drag, the mouse has moved at least one pixel.
Can someone explain this strange behavior to me and show me the correct way of moving the widget to the cursor at the exact position from where it was originally clicked?
To get the coordinate in relation to the parent (like wanted from move()-Method), you need to use the mapFromGlobal on the parent like this:
block->move(block->parentWidget()->mapFromGlobal(QCursor::pos()));
Just give it a try. The reason for this is, lets consider what happens when you are at position 1,1 inside the child. But the child is for example at position 123,123 from its parent top-left. You would now move it to 1,1, causing it to jump 122 pixels each.
My widget is frameless because of the sleek looks and so I need to reimplement the resize behaviour.
If I drag the bottom right corner it already works with this code:
void mouseMoveEvent(QMouseEvent *event) {
resize(event->pos().x(), event->pos().y());
}
But what about all the other corners? For example the bottom left corner.
As one expects, it should behave as if the top right corner of the widget would be fixed.
But in the resize function, the upper left corner is fixed, because there is the event.pos()==0.
My idea was to resize the window and then move it, so that it looks as if it would not move, but only change size around the upper left corner. As this leads to flickering and even not the perfect result, is there a better way?
EDIT: Solution:
a) You can define in mousePressEvent:
offset = event->pos();
initialFixedCornerPosX = this->width()+this->pos().x();
initialFixedCornerPosY = this->pos().y();
and in mouseMoveEvent
int x = event->globalX();
int y = event->globalY();
int x_w = offset.x();
int y_w = offset.y();
setGeometry(x-x_w,initialFixedCornerPosY,initialFixedCornerPosX-x+x_w,y-initialFixedCornerPosY);
or
b) in mouseMoveEvent
QRect rect = geometry();
rect.setBottomLeft(event->globalPos());
setGeometry(rect);
To both resize and move the window in one step without flickering, you should use QWidget::setGeometry(QRect) by providing a modified rectangle previously fetched using the corresponding getter function QWidget::geometry().
QRect rect = geometry();
// (then modify...)
setGeometry(rect);
To modify a corner of a QRect, you could either modify each edge or the corners directly. Depending on the rest of your logic, one makes more sense than the other. I'd prefer the second of the following two options:
Example using corners:
If you detect that the user drags the bottom left corner, use
rect.setBottomLeft(event->pos());
However, you of course need to consider edges too, and if you consider corners as separate cases this results in eight cases to be considered in the mouse event.
Example using only edges:
If you detect that the mouse is on the left edge (it might be as well on the top or bottom corner, which are only special cases, so for now we ignore that):
rect.setLeft(event->pos().x());
and if you detect it is on the bottom edge, then
rect.setBottom(event->pos().y());
so if both cases are true, this effectively moves the corner of the rect. So you only need to consider four cases to drag all edges and corners of your window! This assumes that you have a single widget which handles the resize (i.e. your top level widget, which has a margin on the layout to have the children not touch the window edge), and do not add a widget for each corner / edge.
This is continue of my previous question -> Draw mouse pointer icon?
I want to draw mouse in specific window on the desktop, i already know how to draw the mouse and how to track the movement of the real mouse.
But i fail to convert screen coordinates, here is example what i want to do:
When the REAL mouse is in the upper left corner 0,0 the DRAWN mouse to be in 0,0 of my specific window, and when the REAL mouse is in the down right corner 1600,900 the DRAWN mouse to be in 700,400 of my specific window.
I will re-explain if someone is not understanding exactly the problem.
Thanks in advance.
You need to scale the mouse position w.r.t your window dimensions.
Let DX and DY be the desktop size. Let WX and WY be your window size. Let (Dmx,Dmy) be the coordinate of the original mouse position w.r.t the desktop. Then the position of your mouse within your window according to your requirement would be (Dmx/DX * WX, Dmy/DY * WY). When coding, please remember to make sure the division happens with floating point numbers.
I have a scene which has a basically table-like layout. Thus I'd like it to scroll like a table... one row or column at a time. Specifically, the upper left visible item should have it's upper left corner in the upper left corner of the viewport, unless the scrollbars are at their maximum (in which case it is the bottom/right item that is exactly in view). Pressing an arrow key should display the next row or column in that direction.
Normally that is easily achievable by inheriting QAbstractScrollArea and setting it up as appropriate, but QGraphicsView already does this. Is there someone who can think of a clever method for achieving this effect?
just override QGraphicsScene::keyPressEvent and...
right: move a cells width in positive x
left: move a cells width in negative x
up: move a cells height in negative y
down: move a cells height in positive y
you'll have to disable this movement at the ends of the table, but it sounds a lot simpler that you might have initially thought
EDIT
overload QGraphicsView::scrollContentsBy to handle the scroll bar movement. You could store the dx and dy parameters and only scroll the movement when this value is greater than the size of a cell