📄 qcombobox.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2006 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://www.trolltech.com/products/qt/opensource.html**** If you are unsure which license is appropriate for your use, please** review the following information:** http://www.trolltech.com/products/qt/licensing.html or contact the** sales department at sales@trolltech.com.**** 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 "qcombobox.h"#ifndef QT_NO_COMBOBOX#include <qstylepainter.h>#include <qlineedit.h>#include <qapplication.h>#include <qdesktopwidget.h>#include <qlistview.h>#include <qitemdelegate.h>#include <qstandarditemmodel.h>#include <qmap.h>#include <qevent.h>#include <qlayout.h>#include <qscrollbar.h>#ifndef QT_NO_IM#include "qinputcontext.h"#endif#include <private/qcombobox_p.h>#include <qdebug.h>QComboBoxPrivate::QComboBoxPrivate() : QWidgetPrivate(), model(0), lineEdit(0), container(0), insertPolicy(QComboBox::InsertAtBottom), sizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow), minimumContentsLength(0), shownOnce(false), autoCompletion(true), duplicatesEnabled(false), skipCompletion(false), frame(true), maxVisibleItems(10), maxCount(INT_MAX), modelColumn(0), arrowState(QStyle::State_None), hoverControl(QStyle::SC_None), autoCompletionCaseSensitivity(Qt::CaseInsensitive), indexBeforeChange(-1){}QStyleOptionMenuItem QComboMenuDelegate::getStyleOption(const QStyleOptionViewItem &option, const QModelIndex &index) const{ QStyleOptionMenuItem menuOption; menuOption.palette = QApplication::palette("QMenu"); menuOption.state = QStyle::State_None; if (mCombo->window()->isActiveWindow()) menuOption.state = QStyle::State_Active; if (option.state & QStyle::State_Enabled) menuOption.state |= QStyle::State_Enabled; if (option.state & QStyle::State_Selected) menuOption.state |= QStyle::State_Selected; menuOption.checkType = QStyleOptionMenuItem::NonExclusive; menuOption.checked = mCombo->currentIndex() == index.row(); menuOption.menuItemType = QStyleOptionMenuItem::Normal; menuOption.icon = qvariant_cast<QIcon>(index.model()->data(index, Qt::DecorationRole)); menuOption.text = index.model()->data(index, Qt::DisplayRole).toString() .replace(QLatin1Char('&'), QLatin1String("&&")); menuOption.tabWidth = 0; menuOption.maxIconWidth = option.decorationSize.width() + 4; menuOption.menuRect = option.rect; menuOption.rect = option.rect; extern QHash<QByteArray, QFont> *qt_app_fonts_hash(); menuOption.font = qt_app_fonts_hash()->value("QComboMenuItem", mCombo->font()); return menuOption;}void QComboBoxPrivate::updateArrow(QStyle::StateFlag state){ Q_Q(QComboBox); if (arrowState == state) return; arrowState = state; QStyleOptionComboBox opt = getStyleOption(); q->update(q->style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxArrow));}void QComboBoxPrivate::_q_modelReset(){ Q_Q(QComboBox); if (lineEdit) { lineEdit->setText(""); updateLineEditGeometry(); } q->update();}void QComboBoxPrivate::_q_modelDestroyed(){ Q_Q(QComboBox); model = 0; q->setModel(new QStandardItemModel(0, 1, q));}bool QComboBoxPrivate::updateHoverControl(const QPoint &pos){ Q_Q(QComboBox); QRect lastHoverRect = hoverRect; QStyle::SubControl lastHoverControl = hoverControl; bool doesHover = q->testAttribute(Qt::WA_Hover); if (lastHoverControl != newHoverControl(pos) && doesHover) { q->update(lastHoverRect); q->update(hoverRect); return true; } return !doesHover;}QStyle::SubControl QComboBoxPrivate::newHoverControl(const QPoint &pos){ Q_Q(QComboBox); QStyleOptionComboBox opt = getStyleOption(); opt.subControls = QStyle::SC_All; hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, pos, q); hoverRect = (hoverControl != QStyle::SC_None) ? q->style()->subControlRect(QStyle::CC_ComboBox, &opt, hoverControl, q) : QRect(); return hoverControl;}QComboBoxPrivateContainer::QComboBoxPrivateContainer(QAbstractItemView *itemView, QComboBox *parent) : QFrame(parent, Qt::Popup), combo(parent), view(0), top(0), bottom(0){ // we need the combobox and itemview Q_ASSERT(parent); Q_ASSERT(itemView); setAttribute(Qt::WA_WindowPropagation); // setup container blockMouseReleaseTimer.setSingleShot(true); // we need a vertical layout QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, this); layout->setSpacing(0); layout->setMargin(0); // set item view setItemView(itemView); // add scroller arrows if style needs them QStyleOptionComboBox opt = comboStyleOption(); if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)) { top = new QComboBoxPrivateScroller(QAbstractSlider::SliderSingleStepSub, this); bottom = new QComboBoxPrivateScroller(QAbstractSlider::SliderSingleStepAdd, this); top->hide(); bottom->hide(); } else { setFrameStyle(QFrame::StyledPanel|QFrame::Plain); setLineWidth(1); } if (top) { layout->insertWidget(0, top); connect(top, SIGNAL(doScroll(int)), this, SLOT(scrollItemView(int))); } if (bottom) { layout->addWidget(bottom); connect(bottom, SIGNAL(doScroll(int)), this, SLOT(scrollItemView(int))); }}void QComboBoxPrivateContainer::scrollItemView(int action){#ifndef QT_NO_SCROLLBAR if (view->verticalScrollBar()) view->verticalScrollBar()->triggerAction(static_cast<QAbstractSlider::SliderAction>(action));#endif}/* Hides or shows the scrollers when we emulate a popupmenu*/void QComboBoxPrivateContainer::updateScrollers(){#ifndef QT_NO_SCROLLBAR if (!top || !bottom) return; QStyleOptionComboBox opt = comboStyleOption(); if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo) && view->verticalScrollBar()->minimum() < view->verticalScrollBar()->maximum()) { bool needTop = view->verticalScrollBar()->value() > (view->verticalScrollBar()->minimum() + spacing()); bool needBottom = view->verticalScrollBar()->value() < (view->verticalScrollBar()->maximum() - spacing()*2); if (needTop) top->show(); else top->hide(); if (needBottom) bottom->show(); else bottom->hide(); } else { top->hide(); bottom->hide(); }#endif // QT_NO_SCROLLBAR}/* Sets currentIndex on entered if the LeftButton is not pressed. This means that if mouseTracking(...) is on, we setCurrentIndex and select even when LeftButton is not pressed.*/void QComboBoxPrivateContainer::setCurrentIndex(const QModelIndex &index){ view->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);}/* Returns the item view used for the combobox popup.*/QAbstractItemView *QComboBoxPrivateContainer::itemView() const{ return view;}/*! Sets the item view to be used for the combobox popup.*/void QComboBoxPrivateContainer::setItemView(QAbstractItemView *itemView){ Q_ASSERT(itemView); // clean up old one if (view) { view->removeEventFilter(this); view->viewport()->removeEventFilter(this);#ifndef QT_NO_SCROLLBAR disconnect(view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(updateScrollers())); disconnect(view->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(updateScrollers()));#endif disconnect(view, SIGNAL(entered(QModelIndex)), this, SLOT(setCurrentIndex(QModelIndex))); delete view; view = 0; } // setup the item view view = itemView; view->setParent(this); qobject_cast<QBoxLayout*>(layout())->insertWidget(top ? 1 : 0, view); view->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); view->installEventFilter(this); view->viewport()->installEventFilter(this); QStyleOptionComboBox opt = comboStyleOption();#ifndef QT_NO_SCROLLBAR if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo)) view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);#endif if (style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking, &opt, combo) || style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo)) { view->setMouseTracking(true); } view->setSelectionMode(QAbstractItemView::SingleSelection); view->setFrameStyle(QFrame::NoFrame); view->setLineWidth(0); view->setEditTriggers(QAbstractItemView::NoEditTriggers);#ifndef QT_NO_SCROLLBAR connect(view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(updateScrollers())); connect(view->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(updateScrollers()));#endif connect(view, SIGNAL(entered(QModelIndex)), this, SLOT(setCurrentIndex(QModelIndex)));}/*! Returns the spacing between the items in the view.*/int QComboBoxPrivateContainer::spacing() const{ QListView *lview = qobject_cast<QListView*>(view); if (lview) return lview->spacing(); return 0;}void QComboBoxPrivateContainer::changeEvent(QEvent *e){ if (e->type() == QEvent::StyleChange) { QStyleOptionComboBox opt = comboStyleOption(); view->setMouseTracking(style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking, &opt, combo) || style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo)); } QWidget::changeEvent(e);}bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e){ switch (e->type()) { case QEvent::KeyPress: switch (static_cast<QKeyEvent*>(e)->key()) { case Qt::Key_Enter: case Qt::Key_Return:#ifdef QT_KEYPAD_NAVIGATION case Qt::Key_Select:#endif if (view->currentIndex().isValid()) { combo->hidePopup(); emit itemSelected(view->currentIndex()); } return true; case Qt::Key_Down: if (!(static_cast<QKeyEvent*>(e)->modifiers() & Qt::AltModifier)) break; // fall through case Qt::Key_F4: case Qt::Key_Escape:#ifdef QT_KEYPAD_NAVIGATION case Qt::Key_Back:#endif combo->hidePopup(); return true; default: break; } break; case QEvent::MouseMove: { if (isVisible()) { QMouseEvent *m = static_cast<QMouseEvent *>(e); QPoint vector = m->pos() - initialClickPosition; if (vector.manhattanLength() > 9 && blockMouseReleaseTimer.isActive()) blockMouseReleaseTimer.stop(); } break; } case QEvent::MouseButtonRelease: { QMouseEvent *m = static_cast<QMouseEvent *>(e); if (isVisible() && view->rect().contains(m->pos()) && view->currentIndex().isValid() && !blockMouseReleaseTimer.isActive()) { combo->hidePopup(); emit itemSelected(view->currentIndex()); return true; } break; } default: break; } return QFrame::eventFilter(o, e);}void QComboBoxPrivateContainer::hideEvent(QHideEvent *){ emit resetButton();}void QComboBoxPrivateContainer::mousePressEvent(QMouseEvent *e){ QStyleOptionComboBox opt = comboStyleOption(); opt.subControls = QStyle::SC_All; opt.activeSubControls = QStyle::SC_ComboBoxArrow; QStyle::SubControl sc = style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, combo->mapFromGlobal(e->globalPos()), combo); if ((combo->isEditable() && sc == QStyle::SC_ComboBoxArrow) || (!combo->isEditable() && sc != QStyle::SC_None)) setAttribute(Qt::WA_NoMouseReplay); QFrame::mousePressEvent(e);}void QComboBoxPrivateContainer::mouseReleaseEvent(QMouseEvent *e){ Q_UNUSED(e); emit resetButton();}QStyleOptionComboBox QComboBoxPrivateContainer::comboStyleOption() const{ QStyleOptionComboBox opt; opt.state = QStyle::State_None; opt.rect = combo->rect(); opt.palette = combo->palette(); opt.init(combo); opt.subControls = QStyle::SC_All; opt.activeSubControls = QStyle::SC_None; opt.editable = combo->isEditable(); return opt;}/*! \enum QComboBox::InsertPolicy This enum specifies what the QComboBox should do when a new string is entered by the user. \value NoInsert The string will not be inserted into the combobox. \value InsertAtTop The string will be inserted as the first item in the combobox. \value InsertAtCurrent The current item will be \e replaced by the string. \value InsertAtBottom The string will be inserted after the last item in the combobox. \value InsertAfterCurrent The string is inserted after the current item in the combobox. \value InsertBeforeCurrent The string is inserted before the current item in the combobox. \omitvalue NoInsertion \omitvalue AtTop \omitvalue AtCurrent \omitvalue AtBottom \omitvalue AfterCurrent \omitvalue BeforeCurrent*//*! \enum QComboBox::SizeAdjustPolicy This enum specifies how the size of the QComboBox should adjust when new content is added or content changes. \value AdjustToContents The combobox will always adjust to the contens \value AdjustToContentsOnFirstShow The combobox will adjust to its contents the first time it is show. \value AdjustToMinimumContentsLength The combobox only adjusts to the \l minimumContentsLength*//*! \fn void QComboBox::activated(int index) This signal is sent when an item in the combobox is activated by the user. The item's \a index is given.*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -