📄 qabstractbutton.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtGui module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qabstractbutton.h"#include "qbuttongroup.h"#include "qabstractbutton_p.h"#include "qevent.h"#include "qpainter.h"#include "qapplication.h"#include "qstyle.h"#include "qaction.h"#ifndef QT_NO_ACCESSIBILITY#include "qaccessible.h"#endif#define AUTO_REPEAT_DELAY 300#define AUTO_REPEAT_INTERVAL 100/*! \class QAbstractButton \brief The QAbstractButton class is the abstract base class of button widgets, providing functionality common to buttons. \ingroup abstractwidgets This class implements an \e abstract button. Subclasses of this class handle user actions, and specify how the button is drawn. QAbstractButton provides support for both push buttons and checkable (toggle) buttons. Checkable buttons are implemented in the QRadioButton and QCheckBox classes. Push buttons are implemented in the QPushButton and QToolButton classes; these also provide toggle behavior if required. Any button can display a label containing text and an icon. setText() sets the text; setIcon() sets the icon. If a button is disabled, its label is changed to give the button a "disabled" appearance. If the button is a text button with a string containing an ampersand ('&'), QAbstractButton automatically creates a shortcut key. For example: \code QPushButton *button = new QPushButton(tr("Ro&ck && Roll"), this); \endcode The \key Alt+C shortcut is assigned to the button, i.e., when the user presses \key Alt+C the button will call animateClick(). See the \l {QShortcut#mnemonic}{QShortcut} documentation for details (to display an actual ampersand, use '&&'). You can also set a custom shortcut key using the setShortcut() function. This is useful mostly for buttons that do not have any text, because they have no automatic shortcut. \code button->setIcon(QIcon(":/images/print.png")); button->setShortcut(tr("Alt+F7")); \endcode All of the buttons provided by Qt (QPushButton, QToolButton, QCheckBox, and QRadioButton) can display both \l text and \l{icon}{icons}. A button can be made the default button in a dialog are provided by QPushButton::setDefault() and QPushButton::setAutoDefault(). QAbstractButton provides most of the states used for buttons: \list \o isDown() indicates whether the button is \e pressed down. \o isChecked() indicates whether the button is \e checked. Only checkable buttons can be checked and unchecked (see below). \o isEnabled() indicates whether the button can be pressed by the user. \o setAutoRepeat() sets whether the button will auto-repeat if the user holds it down. \l autoRepeatDelay and \l autoRepeatInterval define how auto-repetition is done. \o setCheckable() sets whether the button is a toggle button or not. \endlist The difference between isDown() and isChecked() is as follows. When the user clicks a toggle button to check it, the button is first \e pressed then released into the \e checked state. When the user clicks it again (to uncheck it), the button moves first to the \e pressed state, then to the \e unchecked state (isChecked() and isDown() are both false). QAbstractButton provides four signals: \list 1 \o pressed() is emitted when the left mouse button is pressed while the mouse cursor is inside the button. \o released() is emitted when the left mouse button is released. \o clicked() is emitted when the button is first pressed and then released, when the shortcut key is typed, or when click() or animateClick() is called. \o toggled() is emitted when the state of a toggle button changes. \endlist To subclass QAbstractButton, you must reimplement at least paintEvent() to draw the button's outline and its text or pixmap. It is generally advisable to reimplement sizeHint() as well, and sometimes hitButton() (to determine whether a button press is within the button). For buttons with more than two states (like tri-state buttons), you will also have to reimplement checkStateSet() and nextCheckState(). \sa QButtonGroup*/QAbstractButtonPrivate::QAbstractButtonPrivate(QSizePolicy::ControlType type) :#ifndef QT_NO_SHORTCUT shortcutId(0),#endif checkable(false), checked(false), autoRepeat(false), autoExclusive(false), down(false), blockRefresh(false),#ifndef QT_NO_BUTTONGROUP group(0),#endif autoRepeatDelay(AUTO_REPEAT_DELAY), autoRepeatInterval(AUTO_REPEAT_INTERVAL), controlType(type){}#ifndef QT_NO_BUTTONGROUPclass QButtonGroupPrivate: public QObjectPrivate{ Q_DECLARE_PUBLIC(QButtonGroup)public: QButtonGroupPrivate():exclusive(true){} QList<QAbstractButton *> buttonList; QPointer<QAbstractButton> checkedButton; void detectCheckedButton(); void notifyChecked(QAbstractButton *button); bool exclusive; QMap<QAbstractButton*, int> mapping;};QButtonGroup::QButtonGroup(QObject *parent) : QObject(*new QButtonGroupPrivate, parent){}QButtonGroup::~QButtonGroup(){ Q_D(QButtonGroup); for (int i = 0; i < d->buttonList.count(); ++i) d->buttonList.at(i)->d_func()->group = 0;}bool QButtonGroup::exclusive() const{ Q_D(const QButtonGroup); return d->exclusive;}void QButtonGroup::setExclusive(bool exclusive){ Q_D(QButtonGroup); d->exclusive = exclusive;}/*! Adds the given \a button to the end of the group's internal list of buttons. \sa removeButton()*/void QButtonGroup::addButton(QAbstractButton *button){ addButton(button, -1);}void QButtonGroup::addButton(QAbstractButton *button, int id){ Q_D(QButtonGroup); if (QButtonGroup *previous = button->d_func()->group) previous->removeButton(button); button->d_func()->group = this; d->buttonList.append(button); if (id != -1) d->mapping[button] = id; if (d->exclusive && button->isChecked()) button->d_func()->notifyChecked();}void QButtonGroup::removeButton(QAbstractButton *button){ Q_D(QButtonGroup); if (d->checkedButton == button) { d->detectCheckedButton(); } if (button->d_func()->group == this) { button->d_func()->group = 0; d->buttonList.removeAll(button); d->mapping.remove(button); }}QList<QAbstractButton*> QButtonGroup::buttons() const{ Q_D(const QButtonGroup); return d->buttonList;}QAbstractButton *QButtonGroup::checkedButton() const{ Q_D(const QButtonGroup); return d->checkedButton;}QAbstractButton *QButtonGroup::button(int id) const{ Q_D(const QButtonGroup); return d->mapping.key(id);}void QButtonGroup::setId(QAbstractButton *button, int id){ Q_D(QButtonGroup); if (button && id != -1) d->mapping[button] = id;}int QButtonGroup::id(QAbstractButton *button) const{ Q_D(const QButtonGroup); return d->mapping.value(button, -1);}int QButtonGroup::checkedId() const{ Q_D(const QButtonGroup); return d->mapping.value(d->checkedButton, -1);}// detect a checked button other than the current onevoid QButtonGroupPrivate::detectCheckedButton(){ QAbstractButton *previous = checkedButton; checkedButton = 0; if (exclusive) return; for (int i = 0; i < buttonList.count(); i++) { if (buttonList.at(i) != previous && buttonList.at(i)->isChecked()) { checkedButton = buttonList.at(i); return; } }}#endif // QT_NO_BUTTONGROUPQList<QAbstractButton *>QAbstractButtonPrivate::queryButtonList() const{#ifndef QT_NO_BUTTONGROUP if (group) return group->d_func()->buttonList;#endif Q_Q(const QAbstractButton); QList<QAbstractButton*>candidates; if (q->parentWidget() && autoExclusive) { candidates = qFindChildren<QAbstractButton *>(q->parentWidget()); for (int i = candidates.count() - 1; i >= 0; --i) { QAbstractButton *candidate = candidates.at(i); if (!candidate->autoExclusive()#ifndef QT_NO_BUTTONGROUP || candidate->group()#endif ) candidates.removeAt(i); } } return candidates;}QAbstractButton *QAbstractButtonPrivate::queryCheckedButton() const{#ifndef QT_NO_BUTTONGROUP if (group) return group->d_func()->checkedButton;#endif Q_Q(const QAbstractButton); QList<QAbstractButton *> buttonList = queryButtonList(); if (buttonList.count() == 1) // no group return 0; for (int i = 0; i < buttonList.count(); ++i) { QAbstractButton *b = buttonList.at(i); if (b->d_func()->checked && b != q) return b; } return checked ? const_cast<QAbstractButton *>(q) : 0;}void QAbstractButtonPrivate::notifyChecked(){#ifndef QT_NO_BUTTONGROUP Q_Q(QAbstractButton); if (group) { QAbstractButton *previous = group->d_func()->checkedButton; group->d_func()->checkedButton = q; if (group->d_func()->exclusive && previous && previous != q) previous->nextCheckState(); } else#endif if (autoExclusive) { if (QAbstractButton *b = queryCheckedButton()) b->setChecked(false); }}void QAbstractButtonPrivate::moveFocus(int key){ QList<QAbstractButton *> buttonList = queryButtonList();;#ifndef QT_NO_BUTTONGROUP bool exclusive = group ? group->d_func()->exclusive : autoExclusive;#else bool exclusive = autoExclusive;#endif QWidget *f = qApp->focusWidget(); QAbstractButton *fb = ::qobject_cast<QAbstractButton *>(f); if (!fb || !buttonList.contains(fb)) return; QAbstractButton *candidate = 0; int bestScore = -1; QRect fGeometry = f->geometry(); QPoint goal(f->mapToGlobal(fGeometry.center())); for (int i = 0; i < buttonList.count(); ++i) { QAbstractButton *button = buttonList.at(i); if (button != f && button->isEnabled()) { QRect buttonGeometry = button->geometry(); QPoint p(button->mapToGlobal(buttonGeometry.center())); int score = (p.y() - goal.y())*(p.y() - goal.y()) + (p.x() - goal.x())*(p.x() - goal.x()); bool betterScore = score < bestScore || !candidate; switch(key) { case Qt::Key_Up: if (p.y() < goal.y() && betterScore) { if (qAbs(p.x() - goal.x()) < qAbs(p.y() - goal.y())) { candidate = button; bestScore = score; } else if (buttonGeometry.x() == fGeometry.x()) { candidate = button; bestScore = score/2; } } break; case Qt::Key_Down: if (p.y() > goal.y() && betterScore) { if (qAbs(p.x() - goal.x()) < qAbs(p.y() - goal.y())) { candidate = button; bestScore = score; } else if (buttonGeometry.x() == fGeometry.x()) { candidate = button; bestScore = score/2; } } break; case Qt::Key_Left: if (p.x() < goal.x() && betterScore) { if (qAbs(p.y() - goal.y()) < qAbs(p.x() - goal.x())) { candidate = button; bestScore = score; } else if (buttonGeometry.y() == fGeometry.y()) { candidate = button; bestScore = score/2; } } break; case Qt::Key_Right: if (p.x() > goal.x() && betterScore) { if (qAbs(p.y() - goal.y()) < qAbs(p.x() - goal.x())) { candidate = button; bestScore = score; } else if (buttonGeometry.y() == fGeometry.y()) { candidate = button; bestScore = score/2; } } break; } } } if (exclusive#ifdef QT_KEYPAD_NAVIGATION && !QApplication::keypadNavigationEnabled()#endif && candidate && fb->d_func()->checked && candidate->d_func()->checkable) candidate->click(); if (candidate) { if (key == Qt::Key_Up || key == Qt::Key_Left) candidate->setFocus(Qt::BacktabFocusReason); else candidate->setFocus(Qt::TabFocusReason); }}void QAbstractButtonPrivate::fixFocusPolicy(){ Q_Q(QAbstractButton); QList<QAbstractButton *> buttonList = queryButtonList(); for (int i = 0; i < buttonList.count(); ++i) { QAbstractButton *b = buttonList.at(i); if (!b->isCheckable()) continue; b->setFocusPolicy((Qt::FocusPolicy) ((b == q || !q->isCheckable()) ? (b->focusPolicy() | Qt::TabFocus) : (b->focusPolicy() & ~Qt::TabFocus))); }}void QAbstractButtonPrivate::init(){ Q_Q(QAbstractButton); q->setFocusPolicy(Qt::FocusPolicy(q->style()->styleHint(QStyle::SH_Button_FocusPolicy))); q->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, controlType)); q->setForegroundRole(QPalette::ButtonText); q->setBackgroundRole(QPalette::Button);}void QAbstractButtonPrivate::refresh()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -