I created small game when player controls the ellipse and while he moves I draw other Rect items on the screen. While I like that they overlay all other existing items, I dont want new items to cover that ellipse. Is there any way to make that ellipse always on top of anything else?
You can use QGraphicsItem::setZValue on your rectangles and ellipse.
For example, upon creating an ellipse item you give it value of 2 and upon creating a rectangle item you give it value of 1. This way ellipse will always overlay any given rectangle.
If you like the way new rectangles overlay existing ones, you can recalculate z values of existing rectangle items upon creating, giving the new one z value of the last created rectangle item incremented by one, while also incrementing z value of ellipse item so it is guaranteed to be more than z value of any given rectangle item.
Related
I am using Qt Graphics Framework for displaying an image. I have opened a raw image in subclassed QGraphicsScene in QGraphicsView using addPixmap(). I have added zoom feature by using scale function and drag mode is set as scroll hand drag. Now, I need to get the pixel coordinates within the scene on mouse hover such that the x and y value show the pixel in the image (drawn by pixmap) the mouse is currently pointing to. I tried using pos() but it didn't work.
Here is the code from Widget.cpp:
img = openImage(dirPath2.toLocal8Bit().data(),
sizeX,sizeY,file_heade,scan_heade,bpp,sign);
QPixmap x = QPixmap(sizeX,sizeY);
x.convertFromImage(img,Qt::AutoColor);
scene->addPixmap(x);
ui->disp_img->setDragMode(QGraphicsView::ScrollHandDrag);
GraphicsScene.h:
class GraphicsScene : public QGraphicsScene {
public:
GraphicsScene(QWidget *parent) : QGraphicsScene(parent){}
};
(preferably the pixmap coordinates but even that doesn't happen and if the values change when zoomed I will use scale factor to get the original values)
I suggest you start by reading about Qt's Graphics Coordinate System.
There are various layers of coordinate systems and you need to think about those with which you dealing with. At the top layer is the screen (or view), which is where the mouse coordinates reside.
The next layer from the view is the graphics scene. Graphics items, such as the QGraphicsPixmapItem which you added with addPixmap, reside here. The graphics scene can be visualised as a world of items, each with there own position and orientation.
Moving to the last coordinate system is an item's local coordinate system. If, for example, we take a rectangle, it may have local coordinates of (-5, -5, 10, 10) for (x, y, w, h). This item is then placed in the scene at some position. If its position is the origin of the scene (0,0), then the item's local coordinates would read the same as its scene coordinates.
However, if we move the rectangle +5 units in x-axis, its local coordinates are the same, but its scene coordinates would now be (0, -5, 10, 10).
Likewise, the view (QGraphicsScene) is a window into the scene and can be looking at the whole scene, or just part of it. As the view's top left coordinate is (0,0), it may map onto (0,0) of the scene, or may not, depending on what area of the scene the view is looking at.
So, by getting a mouse position you're starting in the view's coordinates and need to convert to the scene's coordinate system. Fortunately, Qt provides lots of useful functions for this at every level.
To convert the mouse coordinates from the view to the scene, you can use the view's mapToScene function.
Using the scene coordinates you can then get an item and map that to the local coordinate's of the item with the item's mapFromScene.
I'm new to Qt, so I might mangle this question. Having said that-
I'm rendering an image within a subclassed QGraphicsView. I added the image to the scene as a Pixmap with addPixmap(). I'd like to overlay (blit) smaller images on top of the larger one in specific locations. I can add the smaller image to the scene as well by again calling addPixmap(), but it always displays in the upper left corner. I'd like to set those coordinates myself.
How can I accomplish this?
Thanks!
QGraphicsScene::addPixmap returns a pointer to the added QGraphicsPixmapItem. If you want to set its position, you can do something like this:
QGraphicsPixmapItem *item = scene->addPixmap(yourPixmap);
item->setPos(50, 50); // sets position to scene coordinate (50, 50)
If you want to overlay images on top of other images, make sure you know about z-values. See the QGraphicsItem documentation for details. Basically, the z-value determines the stacking order.
Lastly, familiarize yourself with parenting of QGraphicsItems. When a QGraphicsItem has a parent item, it means (among other things) that its coordinates are expressed in terms of its parents' coordinates. So if an item has a position of (0, 0), but it's the child of an item whose scene position is (50, 50), then the child item will be displayed at (50, 50). So, given the above example, you could then do:
QGraphicsPixmapItem *childItem = new QGraphicsPixmapItem(item);
This creates a new item, "childItem", whose parent is "item". Its coordinates are (0, 0), because they haven't been set yet, but its scene coordinates are (50, 50), because it is the child of "item". Note that when you specify an item's parent, you don't need to add the child item to the scene; it is implicitly added.
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
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.
I want to modify the fridge magnets example provided with Qt in a way that when I drag a label and drop it over another, it will push the label beneath the dragged label to the side, so they will never overlap one another.
I've seen how collision is detected in the colliding mice example, where it uses a QGraphicsScene to draw the QGraphicsItem mice on, and scene()->collidingItems(this) to see which mice are colliding.
The problem is that the fridge magnets example uses a class that inherits QWidget in place of QGraphicsScene, so there's no collidingItems() method to check when we have a collision.
How do I go about doing that?
You can get the location and size of each QWidget from geometry(), which returns a QRect. QRect has function intersects(), which will tell you if it intersects another QRect. After the drop is complete, iterate through all of the labels and check if any of them do intersect the new position.
(This will be easier if you modify dragwidget to keep a QList<DragLabel*> of each label on the dragwidget.)
QRect droppedRect = newLabel->geometry();
foreach(DragLabel* label, dragLabelList)
{
if (droppedRect.intersects(label->geometry())
{
// Add to the list of covered labels that need to be moved.
}
}
The harder part: If there is an intersection, move the old label out of the way.
Maybe try the following algorithm: Move the offending label out of the way in the direction that takes the least movement. Now check it against all the other labels. Any of those that are covered should be moved in the same direction. Repeat until all the labels are uncovered.