Qt异形窗口例子

这个原理简单,就是调用QWidget::setMask(...)设置窗口的掩膜实现异形窗口。下面的代码环境是VS2015和Qt5.9。其运行效果图如下,就是下图中显示“显示气球控件”文本的窗口:

头文件:

class MBalloonTip : public QWidget
{
    Q_OBJECT

public:
    static void showText(const QPoint& pos, const QString& itext, int msec = 5000);
    static void showText(QWidget* widget, const QString& itext, int msec = 5000);

private:
    MBalloonTip(QWidget* parent = 0);
    ~MBalloonTip();
    void paintEvent(QPaintEvent *event) override;
    QBitmap raiseShape();
    void setAutoCloseTimer(int msec);

private:
    static const QPoint hotspot;
    QBitmap bitmap;
    QString text;
};

CPP文件。下方将窗口设为Popup型的,这个类型的窗口没有边框并且失去活动焦点会自动关闭:

const QPoint MBalloonTip::hotspot(30, 0);

MBalloonTip::MBalloonTip(QWidget* parent) : 
    QWidget(parent)
{
    setWindowFlags(Qt::Popup | Qt::WindowStaysOnTopHint);
    setAttribute(Qt::WA_DeleteOnClose);
}

MBalloonTip::~MBalloonTip()
{
    qDebug() << "delete";
}

void MBalloonTip::showText(QWidget* widget, const QString& itext, int msec)
{
    QSize size = widget->size();
    QPoint pos = widget->mapToGlobal(QPoint(size.width() / 2, size.height()));
    showText(pos, itext, msec);
}

void MBalloonTip::showText(const QPoint& pos, const QString& itext, int msec)
{
    MBalloonTip *tips = new MBalloonTip;
    tips->text = itext;
    QFontMetrics fm = tips->fontMetrics();
    QSize sz = fm.size(0, itext);
    sz.setWidth(qMax(sz.width(), 48)); /* 最小宽度48 */
    /* 尺寸之宽高。宽边距18,高边距18加上上方箭头13像素 */
    tips->setGeometry(pos.x() - hotspot.x(), pos.y() - hotspot.y(), sz.width() + 18, sz.height() + 31);
    tips->bitmap = tips->raiseShape();
    tips->setMask(tips->bitmap);     /* 这个掩膜是白色隐藏黑色显示 */
    tips->show();
    /* 自动关闭 */
    tips->setAutoCloseTimer(msec);
}

void MBalloonTip::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(QPen(Qt::black, 1));
    painter.setBrush(QColor(255, 255, 232));
    QPainterPath ppath1;
    /* 之所以是14为了跟content矩形相交 */
    /* content矩形的上边y轴坐标是13 */
    QVector<QPointF> points = { { 30, 0 },{ 30, 14 },{ 44, 14 } };
    ppath1.addPolygon(points);
    QPainterPath ppath2;
    QRectF content(0, 13, width(), height() - 13);
    ppath2.addRoundedRect(content, 6, 6);
    painter.drawPath(ppath1 | ppath2);

    painter.setPen(Qt::black);
    painter.setBrush(Qt::NoBrush);
    painter.drawText(content, Qt::AlignCenter, text);
}

void MBalloonTip::setAutoCloseTimer(int msec)
{
    /* 定时关闭窗口 */
    QTimer *timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, [this]() { close(); });
    timer->setInterval(msec);
    timer->start();
}

QBitmap MBalloonTip::raiseShape()
{
    QBitmap bitmap(size());
    bitmap.fill(Qt::white);
    QPainter painter(&bitmap);
    painter.setPen(Qt::NoPen);
    painter.setBrush(Qt::black);
    const QPointF points[] = { { 30, 0 }, { 30, 14 }, { 44, 14 } };
    painter.drawPolygon(points, 3);
    QRectF rectangle(0, 13, width(), height() - 13);
    painter.drawRoundedRect(rectangle, 6, 6);
    return bitmap;
}

 

posted @ 2024-02-01 08:43  兜尼完  阅读(124)  评论(0编辑  收藏  举报