C++ 使用paintEvent在Qt5中制作自定义按钮
我想制作一个自定义按钮,它在每个平台上看起来都一样,没有继承QPushButton或QAbstractButton,而是继承QWidget。此按钮应包含一个pixmap as图标和一个文本以及一个可选字幕。到目前为止,我一直在工作,但问题是小部件的宽度。小部件本身被剪裁成一定的宽度 我的问题是,当我用画师画了很多东西时,父小部件如何知道小部件的新大小?新的大小可以是任意大小,具体取决于文本或像素地图 编辑1 大小提示给出了所需大小的估计值C++ 使用paintEvent在Qt5中制作自定义按钮,c++,qt,user-interface,qt5,C++,Qt,User Interface,Qt5,我想制作一个自定义按钮,它在每个平台上看起来都一样,没有继承QPushButton或QAbstractButton,而是继承QWidget。此按钮应包含一个pixmap as图标和一个文本以及一个可选字幕。到目前为止,我一直在工作,但问题是小部件的宽度。小部件本身被剪裁成一定的宽度 我的问题是,当我用画师画了很多东西时,父小部件如何知道小部件的新大小?新的大小可以是任意大小,具体取决于文本或像素地图 编辑1 大小提示给出了所需大小的估计值 QSize Button::sizeHint() con
QSize Button::sizeHint() const {
QFont nameFont(font());
QFont descriptionFont(font());
QFontMetrics nameFontMetric(nameFont);
QFontMetrics descriptionFontMetric(descriptionFont);
nameFont.setBold(true);
QSize result(0, 0);
result.setWidth(getPixmap().width() + 5
+ nameFontMetric.horizontalAdvance(' ')
+ qMax(descriptionFontMetric.boundingRect(m_ptr->description).width(), nameFontMetric.boundingRect(m_ptr->name).width()));
result.setHeight(qMax(getPixmap().height(),
nameFontMetric.boundingRect(m_ptr->name).height() + descriptionFontMetric.boundingRect(m_ptr->description).height()));
return result;
}
paint方法是从paintEvent方法中调用的,在该方法中,使用QPainter创建了一个painter(此)
有了这个方法,我就可以工作了,但另一个问题是在布局中调整大小,我想拉伸这个小部件,以便一行中的所有小部件都具有相同的宽度。情况似乎不是这样,我不知道怎么做
编辑2:
我是通过使用updateGeometry()实现的,它告诉布局系统大小提示已更改(这就是我理解文档的方式)。这样做的缺点是,我必须在内部保持大小,并检查它是否在paintEvent内部发生了变化
void Button::paint(QPainter *painter)
{
QRect drawingRect;
QFont nameFont(painter->font());
QFont descriptionFont(painter->font());
nameFont.setBold(true);
descriptionFont.setPointSize(nameFont.pointSize() / 1.5);
QFontMetrics nameFontMetric(nameFont, painter->device());
QFontMetrics descriptionFontMetric(descriptionFont, painter->device());
auto nameFontRectInitial = nameFontMetric.boundingRect(m_ptr->name + " ");
auto nameFontRect = nameFontMetric.boundingRect(nameFontRectInitial, 0, m_ptr->name + " ");
auto descriptionFontRectInitial = descriptionFontMetric.boundingRect(m_ptr->description + " ");
auto descriptionFontRect = descriptionFontMetric.boundingRect(descriptionFontRectInitial, 0, m_ptr->description + " ");
// Get rect of widget so far
auto r = rect();
auto labelRect = r;
auto descriptionRect = r;
labelRect = labelRect.translated(getPixmap().width() + 5, 0);
descriptionRect = descriptionRect.translated(getPixmap().width() + 5, 0);
labelRect.setSize(nameFontRect.size());
descriptionRect.setSize(descriptionFontRect.size());
descriptionRect.translate(0, labelRect.height());
drawingRect = labelRect | descriptionRect | getPixmap().rect();
drawingRect.adjust(0,0,5,0);
if(drawingRect.width() != m_ptr->w || drawingRect.height() != m_ptr->h) {
m_ptr->w = drawingRect.width();
m_ptr->h = drawingRect.height();
updateGeometry();
}
// Draw background
painter->fillRect(r, palette().color(QPalette::Button));
// Draw name
painter->setFont(nameFont);
painter->setPen(palette().color(QPalette::Text));
painter->drawText(labelRect, Qt::AlignTop | Qt::TextSingleLine, m_ptr->name);
// Draw description
painter->setFont(descriptionFont);
painter->setPen(palette().color(QPalette::Text));
painter->drawText(descriptionRect, Qt::AlignTop, m_ptr->description);
}
Layout使用
sizeHint
来了解小部件需要多少空间,并根据拉伸因子分配所有额外空间,但只要按钮返回不同的sizeHint
(这取决于它们包含的文本),即使具有相同的拉伸因子,它们也会以不同的宽度结束。所以,为同一行中的按钮实现相同宽度的最简单方法是使它们返回相同的sizeHint
例如,您可以创建助手函数makesamewith
,该函数计算按钮组的最大按钮宽度,并强制它们在sizeHint
中返回此宽度。您可以在将布局应用到小部件后应用该功能
void makeSameWidth(QList<Button*> buttons, QLayout* layout) {
int width = 0;
for(Button* button: buttons) {
width = qMax(button.sizeHint().width(), width);
}
for(Button* button: buttons) {
button->setSizeHintWidth(width);
}
layout->invalidate();
}
class Button {
...
Button (...) : m_width(-1) ...
void setSizeHintWidth(int width) {
m_width = width;
}
int m_width;
}
QSize Button::sizeHint() const {
...
int width;
if (m_width < 0) {
width = getPixmap().width() + 5
+ nameFontMetric.horizontalAdvance(' ')
+ qMax(descriptionFontMetric.boundingRect(m_ptr->description).width(), nameFontMetric.boundingRect(m_ptr->name).width());
} else {
width = m_width;
}
int height = qMax(getPixmap().height(),
nameFontMetric.boundingRect(m_ptr->name).height() + descriptionFontMetric.boundingRect(m_ptr->description).height());
return QSizeHint(width, heigth);
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
makeSameWidth({ui->button1, ui->button2, ui->button3}, ui->buttonsLayout);
...
}
void makeSamewith(QList按钮、QLayout*布局){
整数宽度=0;
用于(按钮*按钮:按钮){
宽度=qMax(button.sizeHint().width(),width);
}
用于(按钮*按钮:按钮){
按钮->设置尺寸宽度(宽度);
}
布局->失效();
}
类按钮{
...
按钮(…):m_宽度(-1)。。。
void setSizeHintWidth(整数宽度){
m_宽度=宽度;
}
国际货币单位宽度;
}
QSize按钮::sizeHint()常量{
...
整数宽度;
如果(m_宽度<0){
宽度=getPixmap().width()+5
+nameFontMetric.horizontalAdvance(“”)
+qMax(descriptionFontMetric.boundingRect(m_ptr->description).width(),nameFontMetric.boundingRect(m_ptr->name.width());
}否则{
宽度=m_宽度;
}
int height=qMax(getPixmap().height(),
nameFontMetric.boundingRect(m_ptr->name.height()+descriptionFontMetric.boundingRect(m_ptr->description.height());
返回QSizeHint(宽度、高度);
}
主窗口::主窗口(QWidget*父窗口)
:QMainWindow(父级)
,ui(新ui::Main窗口)
{
用户界面->设置用户界面(此);
使用相同的方式({ui->button1,ui->button2,ui->button3},ui->ButtonLayout);
...
}
请展示您迄今为止尝试过的代码(最好是a),并查看和。感谢您的回复。到目前为止,我通过使用updateGeometry()实现了这一点,我不知道这是否是告知Qt小部件大小更改的预期方式。我认为MakeSamewith需要我知道每个按钮,但这是我想要避免的。
void makeSameWidth(QList<Button*> buttons, QLayout* layout) {
int width = 0;
for(Button* button: buttons) {
width = qMax(button.sizeHint().width(), width);
}
for(Button* button: buttons) {
button->setSizeHintWidth(width);
}
layout->invalidate();
}
class Button {
...
Button (...) : m_width(-1) ...
void setSizeHintWidth(int width) {
m_width = width;
}
int m_width;
}
QSize Button::sizeHint() const {
...
int width;
if (m_width < 0) {
width = getPixmap().width() + 5
+ nameFontMetric.horizontalAdvance(' ')
+ qMax(descriptionFontMetric.boundingRect(m_ptr->description).width(), nameFontMetric.boundingRect(m_ptr->name).width());
} else {
width = m_width;
}
int height = qMax(getPixmap().height(),
nameFontMetric.boundingRect(m_ptr->name).height() + descriptionFontMetric.boundingRect(m_ptr->description).height());
return QSizeHint(width, heigth);
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
makeSameWidth({ui->button1, ui->button2, ui->button3}, ui->buttonsLayout);
...
}