I'm trying to create and save QGraphicsScene to .svg file and my code works properly. Which creates rectangle,circle and save it into .svg But problem is which can only open rectangles only,how can I implement this to open circle(ellipse too) Please help me.
here are my codes.
readsvg.h
#ifndef READSVG_H
#define READSVG_H
#include <QList>
#include <QGraphicsRectItem>
class ReadSVG
{
public:
ReadSVG();
static QList<QGraphicsRectItem *> getElements(const QString filename);
static QRectF getSizes(const QString filename);
//static QList<QGraphicsEllipseItem *> getElements(const QString filename);
//static QRectF getSizes(const QString filename);
};
#endif // READSVG_H
readsvg.cpp
#include "readsvg.h"
#include <QPen>
#include <QFile>
#include <QMessageBox>
#include <QDomDocument>
#include <QStringList>
ReadSVG::ReadSVG()
{
}
QList<QGraphicsRectItem *> ReadSVG::getElements(const QString filename)
{
QList<QGraphicsRectItem *> rectList; // We declare in the stack a list of rectangles
QDomDocument doc; // document object
QFile file(filename); // Open our SVG file
// If it did not open or could not transfer content to QDocDocument
if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file))
return rectList; // then return the list, but empty
// Look in the document for all objects with the tag g
QDomNodeList gList = doc.elementsByTagName("g");
// We start to sort them out
for (int i = 0; i < gList.size(); i++) {
QDomNode gNode = gList.item(i); // Select the node from the list
QDomElement rectangle = gNode.firstChildElement("rect"); // And we search in it for an element with the tag rect
// If the resulting elements are not zero, then
if (rectangle.isNull()){
continue;
} else {
// begin to form a rectangle
QGraphicsRectItem *rect = new QGraphicsRectItem();
// This flag makes the object moveable, it will be required for verification
rect->setFlag(QGraphicsItem::ItemIsMovable);
// We take sizes from the rect tag
QDomElement gElement = gNode.toElement();
rect->setRect(rectangle.attribute("x").toInt(),
rectangle.attribute("y").toInt(),
rectangle.attribute("width").toInt(),
rectangle.attribute("height").toInt());
/*
We take the parameters of the colors gNode from the node element
yes yes yes ... it's from gNode, not from rectangle. These parameters are stored in the tag g
* */
QColor fillColor(gElement.attribute("fill", "#ffffff")); // fill color
fillColor.setAlphaF(gElement.attribute("fill-opacity","0").toFloat());
rect->setBrush(QBrush(fillColor));
// as well as the color and thickness of the outline
QColor strokeColor(gElement.attribute("stroke", "#000000"));
strokeColor.setAlphaF(gElement.attribute("stroke-opacity").toFloat());
rect->setPen(QPen(strokeColor,gElement.attribute("stroke-width", "0").toInt()));
rectList.append(rect); // add a rectangle to the list
}
}
file.close();
return rectList;
}
QRectF ReadSVG::getSizes(const QString filename)
{
QDomDocument doc; // initialize the QDomDocument object on the stack
QFile file(filename); // Open our SVG file
// If it did not open or could not transfer content to QDocDocument
if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file))
return QRectF(0,0,200,200); // then return the values for the default scene
/* Next, we take the list of elements with the tag svg.
* In case the list of elements is not empty,
* then we will take the dimensions of the graphic scene.
* */
QDomNodeList list = doc.elementsByTagName("svg");
if(list.length() > 0) {
QDomElement svgElement = list.item(0).toElement();
QStringList parameters = svgElement.attribute("viewBox").split(" ");
return QRectF(parameters.at(0).toInt(),
parameters.at(1).toInt(),
parameters.at(2).toInt(),
parameters.at(3).toInt());
}
return QRectF(0,0,200,200);
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QWidget>
#include <QtCore>
#include <QtGui>
#include <QSvgGenerator>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_pushButton_clicked();
void on_btnSave_clicked();
void on_btnOpen_clicked();
private:
Ui::Widget *ui;
QGraphicsScene *scene;
QGraphicsEllipseItem *elipse;
QGraphicsRectItem *rect;
QString path;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include "readsvg.h"
#include <QCursor>
#include <QFileDialog>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
QBrush redBrush(Qt::red);
QBrush blueBrush(Qt::blue);
QPen blackPen(Qt::black);
blackPen.setWidth(6);
elipse = scene->addEllipse(10,10,100,100,blackPen,redBrush);
rect = scene->addRect(-10,-10,100,100,blackPen,blueBrush);
rect->setFlag(QGraphicsItem::ItemIsMovable, true);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
QString fileName= QFileDialog::getSaveFileName(this, "Save image", QCoreApplication::applicationDirPath(), "BMP Files (*.bmp);;JPEG (*.JPEG);;PNG (*.png)" );
if (!fileName.isNull())
{
QPixmap pixMap = this->ui->graphicsView->grab();
pixMap.save(fileName);
}
}
void Widget::on_btnSave_clicked()
{
// Заберём путь к файлу и его имененем, который будем создавать
QString newPath = QFileDialog::getSaveFileName(this, trUtf8("Save SVG"),
path, tr("SVG files (*.svg)"));
if (newPath.isEmpty())
return;
path = newPath;
QSvgGenerator generator;
generator.setFileName(path);
generator.setSize(QSize(scene->width(), scene->height()));
generator.setViewBox(QRect(0, 0, scene->width(), scene->height()));
generator.setTitle(trUtf8("SVG Example"));
generator.setDescription(trUtf8("File created by SVG Example"));
QPainter painter;
painter.begin(&generator);
scene->render(&painter);
painter.end();
}
void Widget::on_btnOpen_clicked()
{
QString newPath = QFileDialog::getOpenFileName(this, trUtf8("Open SVG"),
path, tr("SVG files (*.svg)"));
if (newPath.isEmpty())
return;
path = newPath;
scene->clear();
scene->setSceneRect(ReadSVG::getSizes(path)); // Set the size of the graphic scene
// Install the objects on the graphical scene, get them using the getElements
foreach (QGraphicsRectItem *item, ReadSVG::getElements(path)) {
QGraphicsRectItem *rect = item;
scene->addItem(rect);
}
}
You can continue with the approach that you have started. Look for elements with the tag names that you want. Start with the "circle" tag. Here's what a ciricle tag might look like;
<circle cx="5" cy="5" r="3" fill="#0f0"/>
Related
i'm new to C++ and Qt and can't seem to find the right solution for this. I want to create a QTreeView using a QStandardItemModel. I have a list of file/folder paths (within a QStringList) structured in a format like this:
Arena/Main/00078/a.txt
Arena/Main/00080/b.txt
Arena/Main/00080/collision/c.txt
Arena/Main/00080/light/d.txt
Arena/Main/00081/e.txt
Characters/f.txt
Characters/Main/g.txt
Characters/Main/someFolder/h.txt
I previously used a QFileSystemModel and made actual temporary directories, iterating through the list as a workaround:
QDir dir(temp_path);
if (!dir.exists(dir_string)){
dir.mkpath(dir_string);
}
QFile file(filepath_str);
file.open(QIODevice::WriteOnly);
Which gave me a working result like this: https://i.stack.imgur.com/ITzJz.png
However, the list can reach up to 10,000+ files making it a longer backwards workaround. I want to populate a QTreeView in a similar way using a QStandardItemModel created from the path list.
You can store the created paths in a map like this:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMap>
#include <QStandardItemModel>
class QStandardItem;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
void addPathRecusively(const QStringList &path_parts, QStandardItem *parent, int layer = 1);
QMap<QString, QStandardItem*> path_item_map_;
QStandardItemModel model_;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QStringList>
#include <QTreeView>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QStringList filenames =
{
"Arena/Main/00078/a1.txt",
"Arena/Main/00078/a2.txt",
"Arena/Main/00080/b.txt",
"Arena/Main/00080/collision/c.txt",
"Arena/Main/00080/light/d.txt",
"Arena/Main/00081/e1.txt",
"Arena/Main/00081/e2.txt",
"Arena/Main/00081/e3.txt",
"Characters/f.txt",
"Characters/Main/g.txt",
"Characters/Main/someFolder/h.txt",
};
for (auto &filename : filenames)
{
QStringList parts = filename.split("/");
parts.pop_back();
addPathRecusively(parts, model_.invisibleRootItem());
}
QTreeView *view = new QTreeView{this};
view->setModel(&model_);
this->setCentralWidget(view);
this->resize(500, 500);
}
MainWindow::~MainWindow()
{
}
void MainWindow::addPathRecusively(const QStringList &path_parts, QStandardItem *parent, int layer)
{
QStringList path_parts_to_layer;
std::copy(path_parts.begin(), path_parts.begin() + layer, std::back_inserter(path_parts_to_layer));
QString path = path_parts_to_layer.join("/");
auto item = path_item_map_.value(path);
if (item == nullptr)
{
item = new QStandardItem{path_parts_to_layer.last()};
path_item_map_.insert(path, item);
parent->appendRow({item, new QStandardItem});
}
if (path_parts.length() == layer)
{
auto file_count_index = model_.indexFromItem(item).siblingAtColumn(1);
model_.setData(file_count_index, file_count_index.data().toInt() + 1, Qt::DisplayRole);
}
else
addPathRecusively(path_parts, item, layer + 1);
}
I have made a custom QGraphicsPixMap QGraphicsItem as I need to have functions that trigger when someone clicks on it! The header for this is seen below:
#ifndef NEWGPIXMAP_H
#define NEWGPIXMAP_H
#include <QObject>
#include <QGraphicsPixmapItem>
#include <QGraphicsSceneMouseEvent>
class NewGPixmap : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
public:
NewGPixmap();
void mousePressEvent(QGraphicsSceneMouseEvent *event);
// void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
// void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
};
#endif // NEWGPIXMAP_H
And the .cpp for this can be seen here:
#include "newgpixmap.h"
#include <iostream>
#include <QPointF>
NewGPixmap::NewGPixmap()
{
}
void NewGPixmap::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QPointF pos = event->pos();
int x = pos.x();
int y = pos.y();
std::cout<<x<<" "<<y<<std::endl;
}
When I try and update the pixmap in the QGraphicsScene (stored in a variable called "scene") I get no errors however the PixMap isn't displayed.
This is the code I used prior to implementing my own QGraphicsPixMap which worked fine:
void MainWindow::on_openImage_triggered()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Choose File"));
QImage image(fileName);
QGraphicsPixmapItem* item = new QGraphicsPixmapItem(QPixmap::fromImage(image));
scene->clear();
scene->addItem(item);
}
And now that I am using my own QGraphicsPixMap implementation, this is what code I have:
void MainWindow::on_openImage_triggered()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Choose File"));
QImage image(fileName);
NewGPixmap item;
item.setPixmap(QPixmap::fromImage(image));
scene->clear();
scene->addItem(&item);
}
The problem is that the pixmap wont load into the QGraphicsScene.
Thanks for your help!
Variables are destroyed when their scope ends, in your case "NewGPixmap item;" it is a local variable so it will be deleted when finished running on_openImage_triggered. If you want the object to not depend on the life cycle of the variable then you must use a pointer like your example with QGraphicsPixmapItem:
void MainWindow::on_openImage_triggered()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Choose File"));
QImage image(fileName);
NewGPixmap *item = new NewGPixmap;
item->setPixmap(QPixmap::fromImage(image));
scene->clear();
scene->addItem(item);
}
I have an application which shows some images in a grid and rest of the widgets in their respective positions. Something like this
Drawing inspiration from this i managed to solve keeping the aspect ratio of an image while resizing.
What are the issues:
The QLabel widgets(image widgets) overlap if QMainWindow is shrinked. Check the image below
The whole application is apparently not suited for different screens. Running this application on a laptop, layout is completely messed up.
What have i done:
Here is the MVCE code i have created
//ImageWidget.h
#ifndef IMAGEWIDGET_H
#define IMAGEWIDGET_H
#include <QLabel>
#include <QResizeEvent>
#include <QWidget>
class ImageWidget : public QLabel
{
Q_OBJECT
public:
explicit ImageWidget(QWidget* parent = nullptr);
virtual QSize sizeHint() const;
QPixmap scaledPixmap() const;
virtual int widthForHeight(int height) const;
public slots:
void setPixmap ( const QPixmap& p);
void resizeEvent(QResizeEvent* ev);
private:
QPixmap pix;
};
#endif // IMAGEWIDGET_H
ImageWidget.cpp
#include "imagewidget.h"
ImageWidget::ImageWidget(QWidget* parent) :
QLabel(parent)
{
setStyleSheet("QLabel{margin-left: 10px; border-radius: 25px; background: white; color: #4A0C46;}");
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
sizePolicy.setWidthForHeight(true);
setSizePolicy(sizePolicy);
setMinimumSize(sizeHint());
}
void ImageWidget::setPixmap (const QPixmap& p)
{
pix = p;
QLabel::setPixmap(scaledPixmap());
}
/* virtual */ int ImageWidget::widthForHeight(int height) const
{
return pix.isNull() ? height * pix.height() / pix.width() : height;
}
QSize ImageWidget::sizeHint() const
{
if(pix.width() != 0)
{
int h = this->height();
return QSize(widthForHeight(h), h);
}
else
{
return QSize(300, 300);
}
}
QPixmap ImageWidget::scaledPixmap() const
{
auto scaled = pix.scaled(this->size() * devicePixelRatioF(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
scaled.setDevicePixelRatio(devicePixelRatioF());
return scaled;
}
void ImageWidget::resizeEvent(QResizeEvent* )
{
if (!pix.isNull())
{
QLabel::setPixmap(scaledPixmap());
}
}
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
#include <QTableWidget>
#include "imagewidget.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
protected:
virtual void resizeEvent(QResizeEvent* event) override;
private:
Ui::MainWindow *ui;
ImageWidget* lbl1;
ImageWidget* lbl2;
ImageWidget* lbl3;
ImageWidget* lbl4;
QPushButton* btn1;
QPushButton* btn2;
QPushButton* btn3;
QPushButton* btn4;
QTableWidget* tableWidget;
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QVBoxLayout>
#include <QTabWidget>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QTabBar>
MainWindow::MainWindow(QWidget* parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QVBoxLayout* mainLayout = new QVBoxLayout;
QVBoxLayout* tabLay = new QVBoxLayout;
QHBoxLayout* buttonLay = new QHBoxLayout;
QGridLayout* gridLay = new QGridLayout;
QHBoxLayout* dockLay = new QHBoxLayout;
btn1 = new QPushButton(this);
btn1->setText("Button1");
btn2 = new QPushButton(this);
btn2->setText("Button2");
btn3 = new QPushButton(this);
btn3->setText("Button3");
btn4 = new QPushButton(this);
btn4->setText("Button4");
QTabWidget* tabView = new QTabWidget(this);
tabView->addTab(new QWidget(), "Table");
tabView->setMinimumSize(500, 300);
tabView->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
tableWidget = new QTableWidget(this);
tableWidget->setFixedHeight(200);
lbl1 = new ImageWidget(this);
lbl2 = new ImageWidget(this);
lbl3 = new ImageWidget(this);
lbl4 = new ImageWidget(this);
QPixmap lbl1Pix("1.png");
QPixmap lbl2Pix("2.png");
QPixmap lbl3Pix("3.png");
QPixmap lbl4Pix("4.png");
lbl1->setPixmap(lbl1Pix);
lbl1->show();
lbl2->setPixmap(lbl2Pix);
lbl2->show();
lbl3->setPixmap(lbl3Pix);
lbl3->show();
lbl4->setPixmap(lbl4Pix);
lbl4->show();
buttonLay->addWidget(btn1);
buttonLay->addWidget(btn2);
buttonLay->addWidget(btn3);
buttonLay->addWidget(btn4);
tabLay->addWidget(tabView);
gridLay->addWidget(lbl1, 0, 0);
gridLay->addWidget(lbl2, 0, 1);
gridLay->addWidget(lbl3, 1, 0);
gridLay->addWidget(lbl4, 1, 1);
dockLay->addLayout(gridLay);
dockLay->addLayout(tabLay);
mainLayout->addLayout(dockLay);
mainLayout->addLayout(buttonLay);
mainLayout->addWidget(tableWidget);
centralWidget()->setLayout(mainLayout);
setMinimumSize(200,200);
show();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::resizeEvent(QResizeEvent * /*event*/)
{
// get label dimensions
int h = lbl1->height();
int w = lbl1->widthForHeight(h);
lbl1->setFixedWidth(w);
lbl2->setFixedWidth(w);
lbl3->setFixedWidth(w);
lbl4->setFixedWidth(w);
}
Main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
What do i want:
Set a minimum size to the whole application so that the imagewidgets do not overlap.
Make the whole app work on any PC or laptop screen with different resolutions.
The imagewidgets should take up available space while keeping the aspect ratio of the images and the QTabWidget on the right should have a fixed size.
Maybe there is an easy solution but i am bit confused with Qt Layout management system.
EDIT1: Added the image with overlapping widgets
Here is what I think is happening. When you set the pixmap like here:
QLabel::setPixmap(scaledPixmap());
The label will set the size of the images as the minimum size. And from that point on the label can not be resized any smaller.
The solution I have found around this is to set the following resize flags for the QLabel in the constructor:
QSizePolicy sizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
setSizePolicy(sizePolicy);
This way the QLabel will be resizable at all times. Or you might have to adapt the minimum width.
I am not sure if that is even it, but maybe it is a good start. Let me know what you make of this.
I'm trying to create a simple frame in Qt with a tick and some text. I made two new label implementations because I wanted the labels to dynamically fill all the available space but when I resize the window the sizes are off, as shown by the qDebug output, which represents the size of the image label:
Resized: 244 , 244 <-- Window first created
Resized: 305 , 305 <-- Window maximized
Resized: 135 , 135 <-- Window restored to original size
As you can see, when the window is restored to its original size the image is not. The last size should be 244, 244.
The code which describes the behaviour of the two widgets is the following:
"widgets.h":
/*
* This file includes many custom widgets.
*/
#ifndef APOCRYPHA_WIDGETS
#define APOCRYPHA_WIDGETS
#include <QWidget>
#include <QLabel>
#include <QTimer>
#include <QPixmap>
#include <QResizeEvent>
#include <QPaintEvent>
class AutoTextLabel : public QLabel {
Q_OBJECT
public:
explicit AutoTextLabel(QWidget* parent);
AutoTextLabel(QWidget* parent, QString text);
protected:
void resizeEvent(QResizeEvent* event) override;
private:
QTimer* resizeTimer;
private slots:
void onResizeEnd();
};
class AutoImageLabel : public QLabel {
Q_OBJECT
public:
explicit AutoImageLabel(QWidget* parent);
AutoImageLabel(QWidget* parent, const QPixmap& pixmap);
void setFillOrientation(int orientation);
QSize sizeHint() const override;
public slots:
void setPixmap(const QPixmap &newPix);
void resizeEvent(QResizeEvent* event) override;
protected:
// void paintEvent(QPaintEvent* event) override;
private:
int fillOrientation;
int widthForHeight(int h) const;
int heightForWidth(int w) const override;
QPixmap scaledPixmap() const;
QPixmap labelPixmap;
};
#endif //APOCRYPHA_WIDGETS
"widgets.cpp":
/*
* This file includes many custom widgets.
*/
#include "widgets.h"
#include <QPainter>
#include <QDebug>
AutoTextLabel::AutoTextLabel(QWidget *parent, QString text) : QLabel(text, parent){
// Enable antialiasing
QFont aaFont(font());
aaFont.setStyleStrategy(QFont::PreferAntialias);
setFont(aaFont);
// This timer is used to fire a slot when a window is resized
resizeTimer = new QTimer();
resizeTimer->setSingleShot(true);
connect(resizeTimer, SIGNAL(timeout()), SLOT(onResizeEnd()));
}
AutoTextLabel::AutoTextLabel(QWidget *parent) : AutoTextLabel(parent, "") {}
void AutoTextLabel::resizeEvent(QResizeEvent *event) {
QWidget::resizeEvent(event);
// Only fire when 25ms have passed since the last resize.
resizeTimer->start(25);
}
void AutoTextLabel::onResizeEnd() {
QFont updatedFont(font());
// Resize Text
if (!text().isEmpty()){
int fontSize = 1;
updatedFont.setPixelSize(fontSize);
QRect boundingRectangle;
// Update bounding rectangle
if (wordWrap())
boundingRectangle = QFontMetrics(updatedFont).boundingRect(contentsRect(), Qt::TextWordWrap, text());
else
boundingRectangle = QFontMetrics(updatedFont).boundingRect(text());
while (boundingRectangle.height() <= contentsRect().height()) {
fontSize++;
updatedFont.setPixelSize(fontSize);
// Update bounding rectangle
if (wordWrap())
boundingRectangle = QFontMetrics(updatedFont).boundingRect(contentsRect(), Qt::TextWordWrap, text());
else
boundingRectangle = QFontMetrics(updatedFont).boundingRect(text());
}
updatedFont.setPixelSize(fontSize - 1);
setFont(updatedFont);
}
}
/* Auto Image Label */
AutoImageLabel::AutoImageLabel(QWidget *parent, const QPixmap &pixmap) : QLabel(parent) {
setMinimumSize(1, 1);
setScaledContents(false);
setPixmap(pixmap);
}
AutoImageLabel::AutoImageLabel(QWidget *parent) : QLabel(parent) {
setScaledContents(false);
}
void AutoImageLabel::resizeEvent(QResizeEvent *event) {
QWidget::resizeEvent(event);
if(!labelPixmap.isNull())
QLabel::setPixmap(scaledPixmap());
qDebug() << "Resized: " << scaledPixmap().width() << ", " << scaledPixmap().height();
}
int AutoImageLabel::widthForHeight(int h) const {
return labelPixmap.isNull() ? width() : (labelPixmap.width() * h) / labelPixmap.height();
}
int AutoImageLabel::heightForWidth(int w) const {
return labelPixmap.isNull() ? height() : (labelPixmap.height() * w) / labelPixmap.width();
}
void AutoImageLabel::setFillOrientation(int orientation) {
this->fillOrientation = orientation;
}
QSize AutoImageLabel::sizeHint() const {
if (fillOrientation == Qt::Horizontal)
return QSize(width(), heightForWidth(width()));
else
return QSize(widthForHeight(height()), height());
}
QPixmap AutoImageLabel::scaledPixmap() const {
return labelPixmap.scaled(sizeHint(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
void AutoImageLabel::setPixmap(const QPixmap &newPix) {
labelPixmap = newPix;
QLabel::setPixmap(scaledPixmap());
}
"other_frames.h":
//
// Created by Riccardo on 18/09/2017.
//
#ifndef APOCRYPHA_OTHER_FRAMES_H
#define APOCRYPHA_OTHER_FRAMES_H
#include <QFrame>
#include <QLabel>
#include <QGridLayout>
#include <QWidget>
#include <QResizeEvent>
#include <QPixmap>
#include <QTimer>
#include "widgets.h"
class ConfirmationFrame : public QFrame {
Q_OBJECT
public:
explicit ConfirmationFrame(QWidget* parent);
ConfirmationFrame(QWidget* parent, const QString& text);
private:
QGridLayout* layout;
AutoImageLabel* imageLabel;
AutoTextLabel* textLabel;
};
#endif //APOCRYPHA_OTHER_FRAMES_H
"other_frames.cpp":
//
// Created by Riccardo on 18/09/2017.
//
#include "other_frames.h"
#include <QDebug>
ConfirmationFrame::ConfirmationFrame(QWidget* parent, const QString &text) : QFrame(parent) {
textLabel = new AutoTextLabel(this, text);
QPixmap pix(":/images/check-tick.png");
imageLabel = new AutoImageLabel(this, pix);
textLabel->setAlignment(Qt::AlignCenter);
imageLabel->setAlignment(Qt::AlignCenter);
textLabel->setWordWrap(true);
// Green Background
setStyleSheet("background-color: rgba(106, 242, 94, 1);");
layout = new QGridLayout();
layout->setSpacing(0);
layout->setContentsMargins(32, 32, 32, 32);
layout->setRowStretch(0, 1);
layout->setRowStretch(1, 1);
layout->addWidget(imageLabel, 0, 1);
layout->addWidget(textLabel, 1, 1);
setLayout(layout);
}
ConfirmationFrame::ConfirmationFrame(QWidget *parent) : ConfirmationFrame(parent, "") {
}
"window_main.h":
#ifndef WINDOW_MAIN_H
#define WINDOW_MAIN_H
#include <QMainWindow>
#include <QMenuBar>
#include <QMenu>
#include <QGridLayout>
#include <QFrame>
#include <QScreen>
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
QFrame *mainFrame;
void center(QScreen* screen);
void autoSetSize(QScreen* screen);
private:
void createMenu();
// Components
QGridLayout *mainLayout;
QMenuBar *menuBar;
QMenu *fileMenu;
};
#endif // WINDOW_MAIN
"window_main.cpp":
#include "window_main.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
mainFrame = new QFrame();
mainLayout = new QGridLayout();
mainLayout->setSpacing(0);
mainLayout->setContentsMargins(0, 0, 0, 0);
createMenu();
mainFrame->setStyleSheet("background-color: red;");
mainFrame->setLayout(mainLayout);
setCentralWidget(mainFrame);
}
void MainWindow::createMenu(){
menuBar = new QMenuBar;
fileMenu = new QMenu(tr("&File"), this);
menuBar->addMenu(fileMenu);
setMenuBar(menuBar);
}
void MainWindow::center(QScreen *screen) {
QSize size = screen->availableSize();
int x = size.width() / 2 - width() / 2;
int y = size.height() / 2 - height() / 2;
move(x, y);
}
void MainWindow::autoSetSize(QScreen *screen) {
QSize screenSize = screen->availableSize();
// TODO Math.round
setMinimumSize(QSize((int)(screenSize.width() / 1.25), (int)(screenSize.height() / 1.25)));
}
"main.cpp":
#include <QApplication>
#include <iostream>
#include <QFile>
#include "quiz/choice.h"
#include "quiz/question.h"
#include "quiz/quizmaker.h"
#include <QSettings>
#include <QStandardPaths>
#include <QDebug>
#include <src/user_interface/other_frames.h>
#include "user_interface/window_main.h"
#include <QScreen>
#include <QFontDatabase>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
// Set Application Parameters
QCoreApplication::setOrganizationName("Riccardo Fagiolo");
QCoreApplication::setOrganizationDomain("kopharex.me");
QCoreApplication::setApplicationName("Apocrypha");
// Set application font
const int id = QFontDatabase::addApplicationFont(":/fonts/montserrat/Montserrat-Regular.otf");
QString family = QFontDatabase::applicationFontFamilies(id).at(0);
QFont font(family);
font.setStyleStrategy(QFont::PreferAntialias);
a.setFont(font);
// App Settings
QSettings settings;
settings.setValue("data_dir", QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
// Create UI
auto* window = new MainWindow();
ConfirmationFrame* cframe = new ConfirmationFrame(window, "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?");
window->mainFrame->layout()->addWidget(cframe);
window->autoSetSize(a.primaryScreen());
//cframe->updateTextLabel();
window->show();
window->center(a.primaryScreen());
// [...] - Nothing related to user interface.
return a.exec();
}
Here is a screenshot of the current MainWindow and ConfirmationFrame to give you an idea of what i'm trying to accomplish:
Window Screenshot
All comments regarding the code are welcome.
Thanks for any help,
Riccardo
Hello I tried to fix the resizing issue with an hack.
Before starting the timer to resize the text, just reduce its font to a 1 pixel font:
void AutoTextLabel::resizeEvent(QResizeEvent *event) {
QWidget::resizeEvent(event);
// set a very small font, then start the timer
QFont updatedFont(font());
updatedFont.setPixelSize(1);
setFont(updatedFont);
// Only fire when 25ms have passed since the last resize.
resizeTimer->start(25);
}
Can the effect be acceptable in your opinion?
I want to create a grid of 22x22 individual rectangles. I will be filling each rectangle with a colour based on a predefined colour scale.
At the moment my header file looks like this:
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QtGui>
#include <QtCore>
#include <QGraphicsScene>
#define GRIDDIM 22
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
QGraphicsScene *scene;
QGraphicsRectItem *rec[GRIDDIM*GRIDDIM];
protected:
void paintEvent(QPaintEvent *e);
};
#endif // DIALOG_H
So I have declared 22x22 individual rectangle objects in the rec[] array.
My .cpp file looks like this:
#include "dialog.h"
#include "ui_dialog.h"
#include <QGraphicsView>
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
scene = new QGraphicsScene(this);
//rec = new QGraphicsRectItem;
ui->graphicsView->setScene(scene);
QBrush redBrush(Qt::red);
QBrush blueBrush(Qt::blue);
QPen blackPen(Qt::black);
QPen bluePen(Qt::blue);
blackPen.setWidth(0);
bluePen.setWidth(0);
int height = 15;
int width = 15;
int xpos = 0;
int ypos = 0;
for (int i=0;i<GRIDDIM;i++){
for(int j=0;j<GRIDDIM;j++){
scene->addRect(i*(width),j*(height),width,height,blackPen);
}
}
But this is just assigning the generic rect object by using addrect.
Is it possible to implement my rec[] array into the scene so that I can then say for example set rec[10] blue?
Using:
QGraphicsRectItem *rec = new QGraphicsRectItem(QRect(xpos,ypos,width,height));
Gives back an error:
allocation of incomplete type 'QGraphicsRectItem'
forward declaration of 'QGraphicsRectItem'