Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/151.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用paintEvent在Qt5中制作自定义按钮_C++_Qt_User Interface_Qt5 - Fatal编程技术网

C++ 使用paintEvent在Qt5中制作自定义按钮

C++ 使用paintEvent在Qt5中制作自定义按钮,c++,qt,user-interface,qt5,C++,Qt,User Interface,Qt5,我想制作一个自定义按钮,它在每个平台上看起来都一样,没有继承QPushButton或QAbstractButton,而是继承QWidget。此按钮应包含一个pixmap as图标和一个文本以及一个可选字幕。到目前为止,我一直在工作,但问题是小部件的宽度。小部件本身被剪裁成一定的宽度 我的问题是,当我用画师画了很多东西时,父小部件如何知道小部件的新大小?新的大小可以是任意大小,具体取决于文本或像素地图 编辑1 大小提示给出了所需大小的估计值 QSize Button::sizeHint() con

我想制作一个自定义按钮,它在每个平台上看起来都一样,没有继承QPushButton或QAbstractButton,而是继承QWidget。此按钮应包含一个pixmap as图标和一个文本以及一个可选字幕。到目前为止,我一直在工作,但问题是小部件的宽度。小部件本身被剪裁成一定的宽度

我的问题是,当我用画师画了很多东西时,父小部件如何知道小部件的新大小?新的大小可以是任意大小,具体取决于文本或像素地图

编辑1

大小提示给出了所需大小的估计值

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);
    ...
}