Draw 32x32 Tiled Images in QT - qt

I'm curious to learn how to split an image into 32x32 (or really any size) selectable tiles and display them in Qt? An example is the Tiled Map Editor (the panel in the lower right corner of the screen). I'm thinking of trying to create a 2D level editor in Qt for fun but I'm fairly new to Qt and have yet to find the answer to this specific question. Or maybe I just don't know how to phrase the question.

Add your main image to a QPixmap, then for each tile that you want to create, call the QPixmap's copy function. This allows you to specify the area that you want to copy and returns you a new QPixmap with that area.
With each QPixmap tile you create using copy, use this to create a QGraphicsPixmapItem, which you then add to the QGraphicsScene.
So, you'd do something like this: -
// assuming your source image is in your resources qrc file
QPixmap srcImage(":/images/srcImage.png");
//in a loop for x and a 2nd loop for y
// copy a section of the source image
QPixmap tileImg = srcImage.copy(x, y, w, h);
// create the tile
QGraphicsPixmapItem* pTile = new QGraphicsPixmapItem(tileImg);
// add the pTile to the scene.
Using QGraphicsPixmapItem will provide you with a tiled object that can be positioned in the scene, selected and moved about.

Related

Button arrangement on a full-screen window

My intention is to provide a GUI with two sections, one of which displays k buttons, where k is the number of .txt files in a specific folder. I would be glad to know that there is a way to to simply add buttons (largest possible), still “nicely” arranged in a full screen window. In other words, I would like to only add push buttons, and these would be automatically arranged for me (no specification of coordinates and sizes).
The initial window should be full screen, and buttons should be as large as possible. Any description on how this might be achieved, with pointers to existing examples, is highly appreciated.
You should look into Qt Layouts, for exactly this kind of problem.
A simple example might look something like:
QStringList myListOfFiles;
QWidget *parentWidget; // The widget you want to put them into
QVBoxLayout *layout = new QVBoxLayout;
foreach(QString file, myListOfFiles)
{
QPushButton *button = new QPushButton(fileName,this);
layout->addWidget(button);
}
parentWidget->setLayout(layout);
This will arrange the buttons in one vertical column, and will be as wide as the parent widget. You could look at QGridLayout if you need more than one column.

An image at a specific point in Qt

I am trying to place a .png image(firm logo) at a specific point(coordinate). I've put several buttons, one after another, and now I want the image to be displayed just below these buttons. The code below should do the trick, but the coordinates are simply not working.
//QLabel myLabel; QVBoxLayout *layout; // class members, initialized with 'this'
QPixmap pixmap("v.png");
myLabel.setPixmap(pixmap);
myLabel.setMask(pixmap.mask());
myLabel.setGeometry(QRect(312, 454, 21, 20));
layout->addWidget(&myLabel);
How should I modify the code to simply include this image, possibly at a specific coordinate (just as with QPushButton)? Note that commenting out the last line removes the image, but, even when the image is shown, the buttons cannot be clicked (and they are not part of 'layout') Please provide code that would achieve image positioning with given coordinates.
QLayout is a controller which position widgets added to it. That is why it has no any sense to set coordinates to a widget and then place it to a layout. The layout will change the widget coordinates as soon as the widget is shown.
Futhermore, if you ask how to set certain position in coordinates, you shouldn't use QLayout at all, because it will change any position you set.
QPixmap pixmap("v.png");
myLabel.setPixmap(pixmap);
myLabel.setMask(pixmap.mask());
myLabel.setFixedSize(21, 20);
myLabel.move(312, 452); //ensure that this coordinates are in you widget
myLabel.show();
You will have to either show the label or put it in a layout or make sure it was given a parent in the constructor.
myLabel.setParent(parent_window)
The setParent method might also need you to show.
myLabel.show()
or
layout.addWidget(myLabel)

Change color of transparent image in Qt

I have a transparent image (QImage) overlayed over a video in Qt. I want to change the color of the transparent image only on clicks of button. Can some one tell me how to do this?
Thank You.
This can be done in many ways. I suggest to use QPainter to create new image. If you set SourceIn composition mode, starting image's alpha channel will be applied to any drawing that you will do. You just need to fill image with desired color.
QPixmap source_image; // should be preserved in a class member variable
QRgb base_color; // desired image color
QPixmap new_image = source_image;
QPainter painter(&new_image);
painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
painter.fillRect(new_image.rect(), base_color);
painter.end();
ui->label->setPixmap(new_image); // showing result
Note that I use QPixmap instead of QImage because QPixmaps are more efficient to display (and possibly paint). If you for some reason still want to use QImage, this code will work with QImage without any changes (excluding the last line of course).
Source image:
Result:

How to get visible scene rectangle of QGraphicsView?

I'm displaying a map built as rectangle of QGraphicsPixmapitem items (each item stands for one map tile). Because my map is quite large (around 30 MB of PNG files) I want to be able to load pixmaps on demand only when they're visible for user in QGraphicsView and unload when they became invisible.
Is there any way to figure out visible scene rectangle?
This gives you the visible scene rectangle:
sceneRect = graphicsView.mapToScene(graphicsView.rect()).boundingRect()
In case there is a shear or rotation transformation present it gives you the bounding rectangle of the visible scene area. If you do not have such transformations (only shift or zoom) the returned rectangle is the exact scene area.
Now for your real problem of efficiently display a huge tiles map in a scene? You could load the tiles in background and first evaluate if your Qt framework isn't already optimized for big pixmap that are outside the visible range. 30 MB also doesn't sound so big that it wouldn't fit into memory.
QGraphicsView inherits the QWidget::geometry() function. You can use this to determine its location and size within its parent widget. (Outside of its constructor)
The QGrapicsScene can be larger than the QGraphicsView. The default QGraphicsView will add horizontal and vertical scroll bars to house the QGraphicsScene. I imagine you would like to do something like this:
//create a QGraphicsScene (for this example *scene) that is the size of your entire map.
QGraphicsScene *scene=new QGraphicsScene(0,0,mapWidth,mapHeight);
//create a QGraphicsView* named view that is the size of your visible area
//I'm assuming visibleHeight and visibleWidth do not change (this is your viewing window)
QGraphicsView *view=new QGraphicsView(0,0,visibleWidth,visibleHeight);
view->setScene(scene);
Have the user control the x and y position of the scene that triggers some custom signal like sceneMoved(int,int). Before you redraw the scene, call a slot to check the new position of the scene:
connect(this,SIGNAL(sceneMoved(int,int)),this,SLOT(drawScene(int,int)));
void SomeClass::drawScene(int newX, int newY){
//if you already have a pointer to the scene do this, or call
//QGraphicsView::scene();
int oldX=scene->geometry()->x();
int oldY=scene->geometry()->y();
//now that you have your oldX, oldY, newX, and newY, visibleWidth, visibleHeight
//you can determine what you need to redraw, what you need to delete, and what can stay
}
There is still a lot of if..else, but you get the point. I suggest trying to segment your map into squares the size of your visible area.

Using QGraphicsView to display a local map

I'm trying to use QGraphicsView in order to display a map image and draw some items on top of it. The map boundaries are in a Cartesian coordinate system, for example NE(-500,200) to SW(600,-350). I know how to map image pixels <--> my coordinate system.
I would have to achieve the following:
Add a map image to the scene and tell Qt how to map the actual image pixels to scene coordinates.
Add graphic items at their real position, e.g. (-100,200)
Doing (2) is straightforward - simply add the item to the scene. How do I achieve (1)? what should I do after I call scene->addPixmap()?
Edit - A few clarifications:
I'm mapping an indoor area of a few hundred meters
The map will change at real-time in two ways:
The map gets bigger every few seconds
The graphic items move, change colors, etc.
Put the pixmap into a QGraphicsPixmapItem and place it in the scene.
Call setScale() to map the QGraphicsPixmapItem so 1 meter maps to 1 unit in the scene coordinate. ie. setScale(0.1) if 10 pixels in the pixmap equal 1 meter.
Update the pixmap and scale of the item as needed.
Call fitInView() to zoom to the pixmap.
Place other graphic items in the scene. Treat the units of the scene coordinate as meters.
...
Profit! :)

Resources