我试图通过子类化和设置区域掩码来创建圆形按钮,以便可以在项目中重用它。我知道我们可以覆盖paintEvent方法并绘制一个圆圈以将其显示为圆形按钮。但是这种方法的问题在于,如果用户在圆外(但在按钮rect内)单击,则将其视为按钮单击。设置区域遮罩时我们看不到这个问题。
我试图通过在resizeEvent / paintEvent中调用setmask方法来设置区域。无论哪种情况,按钮都将为空白。我试图找出子类内部的位置来设置区域遮罩。
#include <QPushButton>
namespace Ui {
class CRoundAnimatingBtn;
}
class CRoundAnimatingBtn : public QPushButton
{
Q_OBJECT
public:
explicit CRoundAnimatingBtn(QWidget *parent = nullptr);
~CRoundAnimatingBtn();
void StartAnimation(QColor r);
void StopAnimation();
public slots:
void timerEvent(QTimerEvent *e);
private:
Ui::CRoundAnimatingBtn *ui;
bool m_Spinning;
// QWidget interface
protected:
void resizeEvent(QResizeEvent *event) override;
void paintEvent(QPaintEvent * e) override;
};
#endif // ROUNDANIMATINGBTN_H
CRoundAnimatingBtn::CRoundAnimatingBtn(QWidget *parent)
: QPushButton (parent)
, ui(new Ui::CRoundAnimatingBtn)
, m_Spinning(false)
{
ui->setupUi(this);
}
CRoundAnimatingBtn::~CRoundAnimatingBtn()
{
delete ui;
}
void CRoundAnimatingBtn::paintEvent(QPaintEvent *e)
{
QPushButton::paintEvent(e);
if(m_Spinning)
{
// Animating code
}
}
void CRoundAnimatingBtn::StartAnimation(QColor r)
{
m_Spinning=true;
startTimer(5);
}
void CRoundAnimatingBtn::StopAnimation()
{
m_Spinning=false;
this->update();
}
void CRoundAnimatingBtn::timerEvent(QTimerEvent *e)
{
if(m_Spinning)
this->update();
else
killTimer(e->timerId());
}
void CRoundAnimatingBtn::DrawRing()
{
}
void CRoundAnimatingBtn::resizeEvent(QResizeEvent *event)
{
// -----------------------------------
// This code didn't work
// -----------------------------------
QRect rect = this->geometry();
QRegion region(rect, QRegion::Ellipse);
qDebug() << "PaintEvent Reound button - " << region.boundingRect().size();
this->setMask(region);
// ----------------------------------
// ------------------------------------
// This code worked
// -------------------------------------
int side = qMin(width(), height());
QRegion maskedRegion(width() / 2 - side / 2, height() / 2 - side / 2, side,
side, QRegion::Ellipse);
setMask(maskedRegion);
}
答案 0 :(得分:2)
Qt文档。提供了“非矩形”小部件的示例– Shaped Clock Example。
(不幸的是),我还记得在运行自己的样本之前记得这一点。
我从Qt文档开始。与
void QWidget::setMask(const QBitmap &bitmap)
仅导致其位图具有相应1位可见的小部件的像素。如果该区域包括小部件rect()外部的像素,则取决于平台,该区域中的窗口系统控件可能可见,也可能不可见。
请注意,如果该区域特别复杂,此效果可能会很慢。
以下代码显示了如何使用具有Alpha通道的图像生成窗口小部件的蒙版:
QLabel topLevelLabel; QPixmap pixmap(":/images/tux.png"); topLevelLabel.setPixmap(pixmap); topLevelLabel.setMask(pixmap.mask());
此代码显示的标签被包含在其中的图像遮盖了,使外观看起来像是在屏幕上直接绘制了不规则形状的图像。
掩盖的窗口小部件仅在其可见部分接收鼠标事件。
另请参见。mask(),clearMask(),windowOpacity()和Shaped Clock Example。
(阅读本文时,我仍然错过了示例的链接。)
首先,我准备了适合自己的像素图– dialog-error.png
:
我从其中一个应用程序转换了SVG。
我尝试将其作为图标和蒙版应用到QPushButton
。这看起来很奇怪。我不太确定到底是什么问题:
-使用resp。 QPushButton
作为顶层窗口小部件(即主窗口)
-QPushButton
的图标呈现和蒙版在位置或大小方面可能不匹配的事实。
无需深入研究,我更改了代码,并在下次尝试中修复了两个问题:
这很快就起作用了。我添加了一些代码以使效果更加明显:
因此,我来到了以下示例– testQPushButtonMask.cc
:
#include <QtWidgets>
class MainWindow: public QWidget {
public:
explicit MainWindow(QWidget *pQParent = nullptr):
QWidget(pQParent)
{ }
virtual ~MainWindow() = default;
MainWindow(const MainWindow&) = delete;
MainWindow& operator=(const MainWindow&) = delete;
protected:
virtual void mousePressEvent(QMouseEvent *pQEvent) override;
};
void MainWindow::mousePressEvent(QMouseEvent *pQEvent)
{
qDebug() << "MainWindow::mousePressEvent:" << pQEvent->pos();
QWidget::mousePressEvent(pQEvent);
}
class RoundButton: public QPushButton {
private:
QPixmap _qPixmap;
public:
RoundButton(const QPixmap &qPixmap, QWidget *pQParent = nullptr):
QPushButton(pQParent),
_qPixmap(qPixmap)
{
setMask(_qPixmap.mask());
}
virtual ~RoundButton() = default;
RoundButton(const RoundButton&) = delete;
RoundButton& operator=(const RoundButton&) = delete;
virtual QSize sizeHint() const override;
protected:
virtual void paintEvent(QPaintEvent *pQEvent) override;
};
QSize RoundButton::sizeHint() const { return _qPixmap.size(); }
void RoundButton::paintEvent(QPaintEvent*)
{
QPainter qPainter(this);
const int xy = isDown() * -2;
qPainter.drawPixmap(xy, xy, _qPixmap);
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
QPixmap qPixmap("./dialog-error.png");
// setup GUI
MainWindow qWin;
qWin.setWindowTitle(QString::fromUtf8("QPushButton with Mask"));
QVBoxLayout qVBox;
RoundButton qBtn(qPixmap);
qVBox.addWidget(&qBtn);
qWin.setLayout(&qVBox);
qWin.show();
// install signal handlers
QObject::connect(&qBtn, &RoundButton::clicked,
[](bool) { qDebug() << "RoundButton::clicked()"; });
// runtime loop
return app.exec();
}
相应的Qt项目文件testQPushButtonMask.pro
SOURCES = testQPushButtonMask.cc
QT += widgets
已在cygwin64上进行了编译和测试:
$ qmake-qt5 testQPushButtonMask.pro
$ make && ./testQPushButtonMask
Qt Version: 5.9.4
MainWindow::mousePressEvent: QPoint(23,22)
MainWindow::mousePressEvent: QPoint(62,24)
MainWindow::mousePressEvent: QPoint(62,61)
MainWindow::mousePressEvent: QPoint(22,60)
RoundButton::clicked()
关于输出: