QSizeGrip 小記

iteye_20954發表於2011-12-31

QSizeGrip 是幹嘛用的,Manual中如是說:

  • The QSizeGrip class provides a resize handle for resizing top-level windows.

一般位於頂級視窗(QMainWindow或QDialog)的右下角

  • 它是QWidget的派生類,你可以放置到另一個QWidget的任何位置
  • 通過它可以改變它所在頂級視窗的大小

BUG?

當看到下面這些東西的時候

  • QTBUG-13975: QSizeGrip does not handle ESC or ALT-TAB correctly on Windows

  • QTBUG-13074: QSizeGrip not giving MouseButtonRelease Event on Windows

  • QTBUG-7350: QStatusBar::setSizeGripEnabled ( false ) has no effect on Mac OS X

  • QTBUG-22867: QSizeGrip crashes when reparented

  • ...

突然感覺的到這個看似普通的,而且原始碼短小的QWidget的派生類,似乎大有看頭

原始碼

  • 原始碼結構不太複雜,但是裡面與平臺相關的部分尚不太瞭解(故爾忽略.

幾乎所有的QWidget的派生類都會重新實現

    void paintEvent(QPaintEvent *);

QSizeGrip也不例外。

QSizeGrip主要就是響應滑鼠左鍵動作,故爾,重新實現

    void mousePressEvent(QMouseEvent *);
    void mouseMoveEvent(QMouseEvent *);
    void mouseReleaseEvent(QMouseEvent *mouseEvent);

這部分是重點(先略過吧)

QSizeGrip需要根據其所處的頂級視窗的狀態(最大化、全屏等)來決定其是否隱藏,這是通過事件過濾器來實現的。

bool QSizeGrip::eventFilter(QObject *o, QEvent *e)
{
    Q_D(QSizeGrip);
    if ((isHidden() && testAttribute(Qt::WA_WState_ExplicitShowHide))
        || e->type() != QEvent::WindowStateChange
                || o != d->tlw) {
        return QWidget::eventFilter(o, e);
    }
    Qt::WindowStates sizeGripNotVisibleState = Qt::WindowFullScreen;
#ifndef Q_WS_MAC
    sizeGripNotVisibleState |= Qt::WindowMaximized;
#endif
    // Don't show the size grip if the tlw is maximized or in full screen mode.
    setVisible(!(d->tlw->windowState() & sizeGripNotVisibleState));
    setAttribute(Qt::WA_WState_ExplicitShowHide, false);
    return QWidget::eventFilter(o, e);
}

配合這個東西,QSizeGripPrivate 中:

    void updateTopLevelWidget()
    {
        Q_Q(QSizeGrip);
        QWidget *w = qt_sizegrip_topLevelWidget(q);
        if (tlw == w)
            return;
        if (tlw)
            tlw->removeEventFilter(q);
        tlw = w;
        if (tlw)
            tlw->installEventFilter(q);
    }

    // This slot is invoked by QLayout when the size grip is added to
    // a layout or reparented after the tlw is shown. This re-implementation is basically
    // the same as QWidgetPrivate::_q_showIfNotHidden except that it checks
    // for Qt::WindowFullScreen and Qt::WindowMaximized as well.
    void _q_showIfNotHidden()
    {
        Q_Q(QSizeGrip);
        bool showSizeGrip = !(q->isHidden() && q->testAttribute(Qt::WA_WState_ExplicitShowHide));
        updateTopLevelWidget();
        if (tlw && showSizeGrip) {
            Qt::WindowStates sizeGripNotVisibleState = Qt::WindowFullScreen;
#ifndef Q_WS_MAC
            sizeGripNotVisibleState |= Qt::WindowMaximized;
#endif
            // Don't show the size grip if the tlw is maximized or in full screen mode.
            showSizeGrip = !(tlw->windowState() & sizeGripNotVisibleState);
        }
        if (showSizeGrip)
            q->setVisible(true);
    }

此外,QSizeGrip會跟著所在視窗移動,所以

 void moveEvent(QMoveEvent *moveEvent);