Creating Graphics Tiles Using QVector(Basics Before QCache) - c++

I am trying to upgrade my Seismic Graph Viewer to use tile graphics rendering. I am very unfamiliar with the process but my attempt to create a simple example is below. The reason why I need to use either QVector or QCache(I'm using QVector right now for simplicity) is to save ram and the tiles needed to be created on the fly. I'm not entirely sure if you're able to do what I'm trying to do below, but essentially it creates an array of bitmaps, makes them items, and then tries to add them to the scene. There are twelve errors when this program compiles, none of which directly refer the code that I made in the mainWindow.cpp.
the errors are either this
C:\Qt\Qt5.9.1\5.9.1\mingw53_32\include\QtCore\qvector.h:713: error:
use of deleted function 'QGraphicsPixmapItem&
QGraphicsPixmapItem::operator=(const QGraphicsPixmapItem&)' with the
only thing changing being the location of the error (different header
files)
or this
C:\Qt\Qt5.9.1\5.9.1\mingw53_32\include\QtWidgets\qgraphicsitem.h:861:
error: 'QGraphicsPixmapItem::QGraphicsPixmapItem(const
QGraphicsPixmapItem&)' is private Q_DISABLE_COPY(QGraphicsPixmapItem)
which is in the qgraphicsitem.h header file
The code that produces doesn't compile due to these errors popping up in the header files
int count;
QVector<QBitmap> BitmapArrayTiles;
QVector<QGraphicsPixmapItem> PixmapItemsArray;
QGraphicsPixmapItem currentItem;
QBitmap currentBitmap;
QGraphicsScene *scene = new QGraphicsScene();
for(count = 0; count < 4; count++)
{
currentBitmap = QBitmap(150,150);
QPainter Painter(&currentBitmap);
QPen Pen(Qt::black); // just to be explicit
Painter.setPen(Pen);
drawStuff(Painter);
BitmapArrayTiles.insert(0, currentBitmap);
currentItem.setPixmap(BitmapArrayTiles[count]);
PixmapItemsArray.insert(count, currentItem);
scene->addItem(&currentItem);
currentItem.mapToScene((count*150)+150, (count*150)+150);
}
ui->TileView->setScene(scene);
^
I have not changed the header files manually so I'm not entirely sure why I would be getting these errors.

Using pointers and tears
int count;
QGraphicsScene *scene = new QGraphicsScene(0, 0, 150*4, 150*4);
QVector<QBitmap*> BitmapArrayTiles;
QVector<QGraphicsPixmapItem*> BitmapItemsArray;
QGraphicsPixmapItem* CurrentItem;
QBitmap *CurrentBitmap;
const QBitmap* CurrentBitmapConstPointer = CurrentBitmap;
for(count = 0; count < 4; count++)
{
CurrentBitmap = new QBitmap(150,150);
QPainter Painter(CurrentBitmap);
QPen Pen(Qt::black); // just to be explicit
Painter.setPen(Pen);
drawStuff(Painter);
BitmapArrayTiles.insert(count, CurrentBitmap);
CurrentItem = new QGraphicsPixmapItem(*BitmapArrayTiles[count]);
BitmapItemsArray.insert(count, CurrentItem);
//PixmapItemsArray.insert(count, currentItem);
scene->addItem(BitmapItemsArray[count]);
BitmapItemsArray[count]->setPos((count*150)+150, (count*150)+150);
}
ui->TileView->setScene(scene);

Related

How do I grab a QPixmap of a QtDataVizualisation in a QWidget and save to file?

I am trying to make a 3D scatter plot using QtDataVisualizationQ3DScatter and then to take a QPixmap of that and save to file.
Here is my code.
//set up the 3D scatter chart
QtDataVisualization::Q3DScatter *graph = new QtDataVisualization::Q3DScatter();
QWidget *widget = QWidget::createWindowContainer(graph);
QtDataVisualization::QScatter3DSeries *series = new QtDataVisualization::QScatter3DSeries;
//set up the data variable
QtDataVisualization::QScatterDataArray data;
//add data to the data variable
for (int i; i < nodes.size(); i = i + 1)
{
data << QVector3D(x[i], y[i], z[i]);
}
//add the data to series
series->dataProxy()->addItems(data);
//add series to graph
graph->addSeries(series);
//set the graph properties
graph->activeTheme()->setType(QtDataVisualization::Q3DTheme::ThemeArmyBlue);
graph->scene()->activeCamera()->setCameraPreset(QtDataVisualization::Q3DCamera::CameraPresetIsometricRight);
graph->seriesList().at(0)->setMesh(QtDataVisualization::QAbstract3DSeries::MeshPoint);
graph->setShadowQuality(QtDataVisualization::QAbstract3DGraph::ShadowQuality(0));
//widget->show();
const QRect rectangle(0,0,widget->width(),widget->height());
QPixmap test = widget->grab(rectangle);
test.save(QString(workingDirectory) + "/test.png", "PNG");
When I uncomment the "widget->show()", the test.png is just a white square but the widget comes up and shows the full 3DScatter. When I comment out the "widget->show()", test.png is still just a white square. I can't seem to get this to work.
When commenting widget->show(), add a widget->repaint() call to force the widget to be painted/rendered before saving it in the file.
I realise this question is quite old but for anyone who's interested:
QAbstract3DGraph has a function renderToImage. This is inherited by Q3DScatter.
You should be able to grab a qimage of your scene using:
QImage myImage = graph->renderToImage();
and then convert this to a pixmap:
QPixmap p;
p.convertFromImage(myImage);

Qt Charts Bar Plot Resize Crash

Situation:
I wrote a bar plot using QtCharts, QChartView, QChart, QBarSeries, QBarSet, QValueAxis and QCategoryAxis and it works fine.
Problem:
When i resize the window or use QRubberbandon the plot, it crashes.
What i tried:
Every other plot i wrote is not affected by that problem, including the ones using QStackedBarSeries. The Problem also occured in another program i wrote in the same situation.
Code - Head:
int D_Plot::Plot_Stat_Multi_MeanMedian(
QChartView *pChartView,
vector<vector<double> > *vv_SetSta,
bool pl_mean,
bool pl_sd,
bool pl_median,
bool pl_adm,
QString name_title,
QString name_categories,
QString name_y)
Code - Body:
//Chart
QChart *chart = new QChart();
chart->setTitle(name_title);
//Sets
QBarSet set_mean("Mean");
QBarSet set_sdev("Standard Deviation");
QBarSet set_medi("Median");
QBarSet set_aadm("Average Absolute Deviation from Median");
//Categories
QStringList categories;
//Series
QBarSeries *series = new QBarSeries();
for(unsigned int set = 0; set < vv_SetSta->size(); set++)
{
if(pl_mean) set_mean.append((*vv_SetSta)[set][c_STAT_MEAN_ARITMETIC]);
if(pl_sd) set_sdev.append((*vv_SetSta)[set][c_STAT_STAN_DEV_SAMPLE]);
if(pl_median) set_medi.append((*vv_SetSta)[set][c_STAT_MEDIAN]);
if(pl_adm) set_aadm.append((*vv_SetSta)[set][c_STAT_ABS_DEV_MED]);
categories.append(QString::number(set));
}
if(pl_mean) series->append(&set_mean);
if(pl_sd) series->append(&set_sdev);
if(pl_median) series->append(&set_medi);
if(pl_adm) series->append(&set_aadm);
chart->addSeries(series);
//Axis
QBarCategoryAxis *X_axis = new QBarCategoryAxis();
X_axis->append(categories);
X_axis->setTitleText(name_categories);
chart->setAxisX(X_axis, series);
QValueAxis *Y_axis = new QValueAxis();
Y_axis->setTitleText(name_y);
chart->setAxisY(Y_axis, series);
//Showing
pChartView->setChart(chart);
return ER_Okay;
You are creating your QBarSet objects locally (i.e. not via the new operator) and passing a pointer to these sets to the QBarSet::append method which AFAIK takes ownership if the objects pointed to i.e feels obliged to de-allocate them when going out of scope. This is bound to fail with locally allocated objects.

Qt programming QComboBox

I am using Qt and C++ to add some features to a freeware called: EASYPAINT.
I had to add a more intuitive method in which the users can see the actual width directly from the tool instead of changing numbers. ( just like in the new windows paint , where you can actually see the line thickness and not pixels.)
I am using a QComboBox. My question is (look at the code first), instead of having 20 (penSizeList->addItem), I know we can have addItems.... But what about the icon. for each Item, will I have to search for 20 different line thickness.png and add them? Or is there another method I can use?
And also, how can I get rid of the string in addItem, and only keep an image or icon in the QComboBox.
QComboBox *penSizeList = new QComboBox();
penSizeList->setIconSize(QSize(100,100));
penSizeList->setStatusTip("Pen Size");
QIcon ONEpxIcon(":/media/actions-icons/clear-gray.png");
QIcon THREEpxIcon(":/media/instruments-icons/canvas-lines1.png");
penSizeList->addItem(ONEpxIcon,"1px");
penSizeList->addItem(THREEpxIcon,"2px");
penSizeList->addItem(THREEpxIcon,"3px");
penSizeList->addItem(THREEpxIcon,"4px");
penSizeList->addItem(THREEpxIcon,"5px");
penSizeList->addItem(THREEpxIcon,"6px");
penSizeList->addItem(THREEpxIcon,"7px");
penSizeList->addItem(THREEpxIcon,"8px");
penSizeList->addItem(THREEpxIcon,"9px");
penSizeList->addItem(THREEpxIcon,"10px");
penSizeList->addItem(THREEpxIcon,"11px");
penSizeList->addItem(THREEpxIcon,"12px");
penSizeList->addItem(THREEpxIcon,"13px");
penSizeList->addItem(THREEpxIcon,"14px");
penSizeList->addItem(THREEpxIcon,"15px");
penSizeList->addItem(THREEpxIcon,"16px");
penSizeList->addItem(THREEpxIcon,"17px");
penSizeList->addItem(THREEpxIcon,"18px");
penSizeList->addItem(THREEpxIcon,"19px");
penSizeList->addItem(THREEpxIcon,"20px");
connect(penSizeList,SIGNAL(activated(int)), this, SLOT(penValueChanged(int)));
Try to do this in loop.
penSizeList->addItem(ONEpxIcon,"1px");
for(int i = 2; i < 21 ; i++)
{
penSizeList->addItem(THREEpxIcon,QString("%1px").arg(i));
}
Or if you have different icons for each line:
for(int i = 1; i < 21 ; i++)
{
penSizeList->addItem(QIcon(QString("iconLine%1.png").arg(i)),QString("%1px").arg(i));
}
If you want only icons, set empty string:
penSizeList->addItem(icon,"");
If you want full image then you should set this image as background. For example:
QPixmap pxmap("G:/2/qt.jpg");
QStandardItemModel *md = new QStandardItemModel;
QStandardItem *iii = new QStandardItem;
iii->setBackground(QBrush(Qt::red));
iii->setText("ss");
QStandardItem *iiii = new QStandardItem;
iiii->setBackground(QBrush(pxmap));
iiii->setText("ss");
md->setItem(1,0,iii);
md->setItem(0,0,iiii);
ui->comboBox->setModel(md);

Add a tiled base map to a GraphicsScene

I try to create a tiled base map by using Qt GUI:
I have two classes: one to set my tile images that inherits from QGraphicPixmapItem, one to load my map from a text file that is a 2D array composed of the numbers 1, 0 and 2, and add it to a scene:
But my program quits unexpectedly and I do not know where is the break:
my tile class:
class mapTile: public QGraphicsPixmapItem
{
public:
enum Tile {DOOR, GRASS, FIRE};
mapTile(): QGraphicsPixmapItem(),currentTile(GRASS){
syncBitmap();
}
Tile getTile() const {return currentTile;}
void setTile(Tile newTile){
if(currentTile!= newTile){
currentTile=newTile;
syncBitmap();
}
}
private:
void syncBitmap() {//Set my image to my tile
switch(currentTile) {
case DOOR:
image->setPixmap(QPixmap(":/mpa/castledoors.png"));
case GRASS:
image->setPixmap(QPixmap(":/map/grass3_blur.jpg"));
case FIRE:
image->setPixmap(QPixmap(":/map/feu1/png"));
}
}
Tile currentTile;
QGraphicsPixmapItem *image;
};
my class map:
Map.h:
class Map
{
public:
static const int TILE_SIZE=20; //value of the tile in pixels!!!->20X20=a tile
void paintMap(QGraphicsScene *scene);
Map();
private:
static const int WIDTH= 13;// width of the grid cell
static const int HEIGHT= 9;//height of the grid cell
//my grid cell map !!!!
int array[WIDTH][HEIGHT];
mapTile *tile; //my tile
};
And Map.cpp
/*Create a default Map*/
Map::Map()
{
QFile myfile("path to my file");
if (!myfile.open(QIODevice::ReadOnly | QIODevice::Text))
{
QMessageBox::information(0, "error", myfile.errorString());
}
QTextStream in(&myfile);
QString line ;
QStringList fields;
int i=0;
int j=0;
while (!in.atEnd()) {
//Fill my array with my list--> convert Qtring into Int
for (i=0; i<HEIGHT; i++ ) {
line = in.readLine();
fields = line.split(" ");
for(j=0;j<WIDTH;j++)
{
//cout<<fields[j].toInt();
array[i][j] = fields[j].toInt();
}
}
}
}
//Paint my map with my tile
void Map::paintMap(QGraphicsScene *scene){
int i=0, j=0;
tile= new mapTile();
for (i=0; i<HEIGHT; i++){
for(j=0; j<WIDTH; j++){
switch(array[i][j]){
case 0:
tile->setTile(mapTile::GRASS);
tile->setPos(i,j);
scene->addItem(tile);
j+=TILE_SIZE;
case 1:
tile->setTile(mapTile::FIRE);
tile->setPos(i,j);
scene->addItem(tile);
j+=TILE_SIZE;
case 2:
tile->setTile(mapTile::DOOR);
tile->setPos(i,j);
scene->addItem(tile);
j+=TILE_SIZE;
}
i+=TILE_SIZE;//
}
}
}
and finally my mainwindow (I directly give the file.cpp):
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
myMap= new Map;
scene= new QGraphicsScene(this);
myMap->paintMap(scene);
ui->graphicsView->setScene(scene);
}
MainWindow::~MainWindow()
{
delete ui;
}
Sorry guys for the long post but I am stuck!
Any ideas on what I missed?
Well, there are at least five problems in your code:
You can't share the same myTile instance when adding them to the scene. You need to create a new one each time you're adding a tile to the scene. At the moment you're creating only one instance at the start of Map::paintMap.
Your myTile class inherits from QGraphicsPixmapItem, however it also has a QGraphicsPixmapItem *image; member which it leaves uninitialized (so it's a roaming pointer), but then it uses it in image->setPixmap(QPixmap(":/mpa/castledoors.png")); which will crash. Instead, you'll want to just call setPixmap(QPixmap(":/mpa/castledoors.png")) (calling the function of your superclass).
In the above item you may have noticed that you misspelled "map" as "mpa", though this will not be the reason of your crash.
In mapTile::syncPixmap as well as in Map::paintMap, you forgot the break; statements in the switch. Without those, all tiles would appear like fire tiles.
You're adding your tile size to the i and j iterators, as if they were the pixel coordinates, but at the same time you're using them as array indexes. You need to either use separate variables for the pixel coordinates or multiply i and j by the TILE_SIZE when calling setPos instead.
Good luck!
I have finally found solutions to my problems:
I added a scene to my function paintMap for adding each item to my scene and created a QGraphicScene* getScene() that returns the scene then I just call it my mainWindow by just writing
ui->graphicsView->setScene(myMap->getScene())
Moreover in my mapTile class I don't use anymore the function setTile(). I removed it, then changed my QGraphicPixmapItem *image by a QPixmap image and in my function syncbitmap() I did
this->setPixmap(image.scaled(TILE_SIZE,TILE_SIZE));at the end of my switch! Why? Because my tile is already a QGraphicsPixmapItem (inheritance) so I just have to set a pixmap to it! And I put it at the end of the switch because if I set the image before, the image will never change because it will be already set! And finally in the constructor I removed currentTile(GRASS), added a Tile variable in my constructor as an argument and just put currentTile= name of your variable in the constructor and then called the syncBitmap function. So in paintMap() you just have to do:
tile= new mapTile(mapTile::GRASS);
tile->setPos(j*TILE_SIZE,i*TILE_SIZE);
scene->addItem(tile);
in each case! VoilĂ !
I hope that will help a newbie like me, at least to understand the logic behind! I am not sure that is the best way to do but this way works for me! :)

Spacing between widgets in QHBoxLayout

I'm trying to create a GUI with QtCreator. For this GUI, I need to display several images with different sizes next to each other. These images should be touching each other.
I use a QWidget with a QHBoxLayout, where I add the labels (with different sizes) containing the images.
According to related questions, I should use setSpacing and setContentsMargin to remove these spaces, but that won't work; I tried several times.
Here's the code:
QWidget *widget = new QWidget(ui->tagcloud);
QHBoxLayout * l = new QHBoxLayout(widget);
ui->tagcloud->setWidget(widget);
for(int i=0;i<list.size();++i)
{
QLabel *lab = new QLabel;
QPixmap pic((list[i].imgPath).c_str()); //This fetches the image
int sizeChange = 50 + (2*list[i].percent); //Calculates the size of the image
lab->setFixedSize(QSize(sizeChange, sizeChange));
lab->setPixmap(pic);
lab->setScaledContents(true);
l->addWidget(lab);
l->setSpacing(0);
}
However, when I run this, the spacing remains the same (i.e. definitely not zero).
If I add more labels to the layout, the spacing seems to get smaller.
Can anyone explain or help me? Thanks!
Setting spacing to 0 and adding stretch before and after works for me :
l->addStretch();
for(int i = 0; i < list.size(); ++i)
{
QLabel *lab = new QLabel;
QPixmap pic((list[i].imgPath).c_str()); //This fetches the image
int sizeChange = 50 + (2*list[i].percent); //Calculates the size of the image
lab->setFixedSize(QSize(sizeChange, sizeChange));
lab->setPixmap(pic);
lab->setScaledContents(true);
l->addWidget(lab);
}
l->addStretch();
l->setSpacing(0);
Also this works I think
l->setSizeConstraint(QLayout::SetMaximumSize);