I'm trying to make a QT application that works as a Dungeons and Dragons character sheet. As a result, I need to have a widget inside another widget. For example, a stat block needs to look like this:
That means it needs a QLabel for the text, a QLineEdit for entering the bottom number, and another QLabel for the modifier (+3). It also needs to have an SVG file as a background.
My problem is this: Is there any way to make such a custom widget that incorporates all three needed widgets and the background into one singular widget? My current code currently looks like this:
statBlock.hpp:
class QLineEdit;
class QLabel;
class QSvgRenderer;
class QSize;
class StatBlockWidget : public QWidget {
Q_OBJECT
public:
StatBlockWidget(const QString& name, QWidget* parent = 0);
~StatBlockWidget();
protected:
QSize sizeHint() const override;
QSize minimumSizeHint() const override;
private:
QLineEdit* abilityScoreEntry;
AbilityScoreModDisplay* abilityModifierDisplay; // Custom widget that automatically shows the correct modifier for a stat's number.
QLabel* abilityName;
QSvgRenderer* svgRenderer;
QLabel* background;
};
statBlock.cpp:
#include "statBlock.hpp"
#include <QLineEdit>
#include <QLabel>
#include <QValidator>
#include <QSvgRenderer>
#include <QPainter>
#include <QPaintEvent>
#include <QPixmap>
#include <QSizePolicy>
StatBlockWidget::StatBlockWidget(const QString& name, QWidget* parent):
QWidget(parent)
{
// Properties of this widget
this->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
this->resize(100, 100);
// Create child widgets
abilityModifierDisplay = new AbilityScoreModDisplay(this);
abilityName = new QLabel(this);
abilityScoreEntry = new QLineEdit(this);
svgRenderer = new QSvgRenderer(QStringLiteral(":/charSheet/assets/statblock.svg"), this);
background = new QLabel(this);
QImage backgroundImage{100, 100, QImage::Format_A2RGB30_Premultiplied};
backgroundImage.fill(Qt::transparent);
// Set attributes
abilityModifierDisplay->raise();
abilityScoreEntry->raise();
abilityScoreEntry->setValidator(new QIntValidator(1, 30, this));
abilityName->raise();
abilityName->setText(name);
// Render the background svg onto the widget
QPainter painter(&backgroundImage);
svgRenderer->render(&painter);
background->setPixmap(QPixmap::fromImage(backgroundImage));
// Set styles and positions for inputs and outputs
abilityScoreEntry->setFixedWidth(80);
abilityScoreEntry->setAlignment(Qt::AlignCenter);
abilityScoreEntry->setStyleSheet("background-color: transparent;"
"color: black;"
"font-size: 35px;"
"border: 1px solid white;");
QPoint centerPoint = this->rect().center() - abilityScoreEntry->rect().center();
centerPoint.setY(centerPoint.y() - 10);
abilityScoreEntry->move(centerPoint);
abilityModifierDisplay->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
abilityModifierDisplay->setFixedWidth(this->width());
abilityModifierDisplay->move(0,-1); // Needed to fix center the text vertically.
abilityModifierDisplay->setStyleSheet("background-color: transparent;"
"color: black;"
"font-size: 14px");
abilityName->setFixedWidth(80);
abilityName->setAlignment(Qt::AlignCenter);
abilityName->setStyleSheet("background-color: transparent;"
"color: black;"
"font-size: 12px;");
centerPoint = this->rect().center() - abilityName->rect().center();
centerPoint.setY(centerPoint.y() + 40);
abilityName->move(centerPoint);
// Set fixed size for this widget
this->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
// Connect Signals and Slots
connect(abilityScoreEntry, SIGNAL(textChanged(const QString&)), abilityModifierDisplay, SLOT(updateModifer(const QString&)));
}
StatBlockWidget::~StatBlockWidget() {}
QSize StatBlockWidget::sizeHint() const {
return QSize(100,100);
}
QSize StatBlockWidget::minimumSizeHint() const {
return QSize(100,100);
}
What I'm trying to do in the code is create a custom widget with 4 child widgets, 3 for the text and numbers, and a QLabel as a background (and a QSvgRenderer to render the svg onto the QLabel). However, this approach is very hard to modify, and it will be harder to do for other aspects of the sheet.
Is there any way in QT that allows me to place widgets on a certain location of its parent widget, that is easy to adjust? I've looked into layouts, but those don't seem to be for a general placement of widgets (ie. in a line or grid), whereas I want to place the widgets very specifically on its parent (say, at 40% mark of its height and width). How could I do this?
QWidget
container or add some spacings in your layout etc. When you really need to display many things with different positions you might be more in theQGraphicsScene
use-case than just displaying a composed-widget. – ymoreau