/** * @file PaiComboBox.cpp * @date 2011-10-17 */ #include #include #include #include #include #include #include #include #include #include #include "PaiComboBox.h" using namespace pai::gui; /** * @class PaiComboBoxItemDelegate * @brief 用来绘制ComboBox弹出选择框Item */ class PAI_WIDGET_EXPORT PaiComboBoxItemDelegate : public QStyledItemDelegate { public: PaiComboBoxItemDelegate(QObject *pParent = 0) : QStyledItemDelegate(pParent) { } protected: /** * @brief 重新实现重绘函数 * @param[in] pPainter 画笔 * @param[in] option 类型选项 * @param[in] index Model 索引 */ void paint(QPainter *pPainter, const QStyleOptionViewItem & option, const QModelIndex & index) const { QStyleOptionViewItemV4 opt = option; initStyleOption(&opt, index); opt.state = opt.state & ~QStyle::State_Selected; if((option.state & QStyle::State_Selected) && (option.state & QStyle::State_Enabled)) { QLinearGradient linearGrad(opt.rect.topLeft(), opt.rect.bottomLeft()); linearGrad.setColorAt(0, QColor("#FFFFFF")); linearGrad.setColorAt(1, QColor("#EAF2F4")); opt.backgroundBrush = QBrush(linearGrad); } else { opt.backgroundBrush = QBrush("#EFF5FA"); } const QWidget *pWidget = opt.widget; if(pWidget == NULL) { return; } QStyle *pStyle = pWidget ? pWidget->style() : QApplication::style(); pStyle->drawControl(QStyle::CE_ItemViewItem, &opt, pPainter, pWidget); if((option.state & QStyle::State_Selected) && (option.state & QStyle::State_Enabled)) { pPainter->save(); pPainter->setPen(QColor("#AACEDB")); pPainter->drawRoundedRect(option.rect.adjusted(1, 1, -2, -2), 1, 1); pPainter->restore(); } } /** * @brief 重设高度 * @param[in] option 类型选项 */ QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & /*index*/) const { return QSize(option.rect.width(), 24); } }; ///////////////////////////////////////////////////////////////////// PaiComboBox::PaiComboBox(QWidget *pParent) : QComboBox(pParent), m_AddButton(false) { InitComboBox(); } PaiComboBox::PaiComboBox(bool showAddButton, QWidget *pParent) : QComboBox(pParent), m_AddButton(showAddButton) { InitComboBox(); SetShowAddButton(m_AddButton); } PaiComboBox::~PaiComboBox() { } void PaiComboBox::InitComboBox() { m_pEditButton = NULL; m_RealTimeValidate = false; m_MaxVisibleItems = 10; // 默认显示10个 QAbstractItemView *pView = view(); // 将view初始设置为最小,防止调整位置和大小时闪烁 pView->parentWidget()->setFixedSize(QSize(0, 0)); pView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); // 当Item文本过长,则在右侧用“...”代替 pView->setTextElideMode(Qt::ElideRight); const QObjectList objs = view()->parentWidget()->children (); // 隐藏多余控件 foreach(QObject *pObj, objs) { QWidget *pWgt = qobject_cast(pObj); if(pWgt && (pWgt != pView)) { pWgt->setMaximumHeight(0); } } setItemDelegate(new PaiComboBoxItemDelegate(this)); } void PaiComboBox::SetShowAddButton(bool show) { if (show && m_pEditButton == NULL) { m_AddButton = true; m_pEditButton = new QToolButton(this); m_pEditButton->setIcon(QIcon(":/Edit.png")); m_pEditButton->setStyleSheet( "QToolButton{ background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1," "stop: 0.0 #FFFFFF, stop: 0.4 #F7FAFD,stop: 0.4 #E5EFF8, stop: 1.0 #BDD7EC);" "border: 1px solid #839CB6; border-left:0px;" "border-top-right-radius: 2px; border-bottom-right-radius: 2px}" "QToolButton:hover { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1," "stop: 0.0 #F1F9FE, stop: 0.4 #E1F3FC, stop: 0.4 #C9E9F9, stop: 1.0 #9BD7F1);}" "QToolButton:focus { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1," "stop: 0 #E6F5FB, stop: 0.38 #D0ECF8, stop: 0.39 #AADDF2, stop: 1.0 #70C5EA);}" ); connect(m_pEditButton, SIGNAL(clicked()), this, SIGNAL(EditButtonClicked())); } else if(!show && m_pEditButton) { // 去掉按钮所占空间 setStyleSheet(QString::fromUtf8("QComboBox{margin-right:0px}")); m_pEditButton->hide(); } } void PaiComboBox::showPopup () { QComboBox::showPopup(); if(count() == 0) { return; } // 每条Item的高度为24; const int ITEM_HEIGHT = 24; int popWidgetHeight = ITEM_HEIGHT * (m_MaxVisibleItems < count() ? m_MaxVisibleItems : count()) + 2; QPoint popWidgetPos(0, 0); // 屏幕高度 int iHeightOfScreen = QApplication::desktop()->height(); // 下方空间高度 int iBottomSpace = iHeightOfScreen - mapToGlobal(rect().bottomLeft()).y(); // 上方空间高度 int iTopSpace = mapToGlobal(rect().topLeft()).y(); if(iBottomSpace >= popWidgetHeight) //如果下方区域足够显示选择列表则在下方显示 { popWidgetPos = mapToGlobal(rect().bottomLeft()) - QPoint( -m_margin.left(), m_margin.bottom()); } else if(iTopSpace >= popWidgetHeight) //如果下方空间不足,而上方空间充足,则上方显示 { popWidgetPos = mapToGlobal(rect().topLeft()) - QPoint(0, popWidgetHeight) + QPoint(m_margin.left(), m_margin.top()); } else // 如果上下空间都不足,则调整显示条数 { if(iBottomSpace > iTopSpace) { popWidgetHeight = iBottomSpace; popWidgetPos = mapToGlobal(rect().bottomLeft()) - QPoint( -m_margin.left(), m_margin.bottom()); } else { popWidgetHeight = iTopSpace; popWidgetPos = mapToGlobal(rect().topLeft()) - QPoint(0, popWidgetHeight) + QPoint(m_margin.left(), m_margin.top()); } } // 调整view的位置和大小 QAbstractItemView *pView = view(); if(pView && pView->parentWidget()) { pView->parentWidget()->setFixedHeight(popWidgetHeight); pView->parentWidget()->move(popWidgetPos); int minWidth = rect().width() - m_margin.left() - m_margin.right(); int widthOfScreen = QApplication::desktop()->width(); // 如果ComboBox的宽度小于屏幕三分之一,根据每行Item文字长度调节下拉框宽度 if(rect().width() < widthOfScreen / 3) { // 根据每行Item文字长度,确定List的最小宽度 QFontMetrics metrics(pView->font()); QString text; for(int i = 0; i < count(); i++) { text = itemText(i) + " ";//添空格为边框占位 minWidth = minWidth > metrics.width(text) ? minWidth : metrics.width(text); } // 如果下拉框宽度超过显示屏宽度三分之一,则将其宽度设置为屏幕宽度的三分之一 if(minWidth > widthOfScreen / 3) { minWidth = widthOfScreen / 3; } } pView->parentWidget()->setFixedWidth(minWidth); } } int PaiComboBox::GetMaxVisibleItems() const { return m_MaxVisibleItems; } void PaiComboBox::SetMaxVisibleItems(const int count) { m_MaxVisibleItems = count; } void PaiComboBox::setStyleSheet(const QString & styleSheet) { QComboBox::setStyleSheet(styleSheet); QRegExp reg("(margin)\\s*:\\s*\\d+\\s*(px)(.*);"); int offset = styleSheet.toLower().indexOf(reg); if(offset != -1) { int end = styleSheet.indexOf(";", offset); QString str = styleSheet.mid(offset, end - offset); QStringList items = str.split(" "); if(items.size() == 1) { QRegExp num("(\\d+)"); int pos = num.indexIn(items[0]); QString value; if (pos > -1) { value = num.cap(1); } bool ok; int margin = value.toInt(&ok, 10); if(ok) { m_margin = QMargins(margin, margin, margin, margin); } } else if(items.size() == 4) { QRegExp num("(\\d+)"); int pos; bool ok; QString value; int left, top, right, bottom; pos = num.indexIn(items[0]); if (pos > -1) { value = num.cap(1); } left = value.toInt(&ok, 10); if(!ok) { return; } pos = num.indexIn(items[1]); if (pos > -1) { value = num.cap(1); } top = value.toInt(&ok, 10); if(!ok) { return; } pos = num.indexIn(items[2]); if (pos > -1) { value = num.cap(1); } right = value.toInt(&ok, 10); if(!ok) { return; } pos = num.indexIn(items[3]); if (pos > -1) { value = num.cap(1); } bottom = value.toInt(&ok, 10); if(!ok) { return; } m_margin = QMargins(left, top, right, bottom); } } else { int left; QRegExp regLeft("(margin-left)\\s*:\\s*\\d+\\s*(px)\\s*;"); offset = styleSheet.toLower().indexOf(regLeft); if(offset == -1) { left = 0; } else { int end = styleSheet.indexOf(";", offset); QString str = styleSheet.mid(offset, end - offset); QRegExp num("(\\d+)"); int pos = num.indexIn(str); QString value; if (pos > -1) { value = num.cap(1); } bool ok; int margin = value.toInt(&ok, 10); if(ok) { left = margin; } } int top; QRegExp regTop("(margin-top)\\s*:\\s*\\d+\\s*(px)\\s*;"); offset = styleSheet.toLower().indexOf(regTop); if(offset == -1) { top = 0; } else { int end = styleSheet.indexOf(";", offset); QString str = styleSheet.mid(offset, end - offset); QRegExp num("(\\d+)"); int pos = num.indexIn(str); QString value; if (pos > -1) { value = num.cap(1); } bool ok; int margin = value.toInt(&ok, 10); if(ok) { top = margin; } } int right; QRegExp regRight("(margin-right)\\s*:\\s*\\d+\\s*(px)\\s*;"); offset = styleSheet.toLower().indexOf(regRight); if(offset == -1) { right = 0; } else { int end = styleSheet.indexOf(";", offset); QString str = styleSheet.mid(offset, end - offset); QRegExp num("(\\d+)"); int pos = num.indexIn(str); QString value; if (pos > -1) { value = num.cap(1); } bool ok; int margin = value.toInt(&ok, 10); if(ok) { right = margin; } } int bottom; QRegExp regBottom("(margin-top)\\s*:\\s*\\d+\\s*(px)\\s*;"); offset = styleSheet.toLower().indexOf(regBottom); if(offset == -1) { bottom = 0; } else { int end = styleSheet.indexOf(";", offset); QString str = styleSheet.mid(offset, end - offset); QRegExp num("(\\d+)"); int pos = num.indexIn(str); QString value; if (pos > -1) { value = num.cap(1); } bool ok; int margin = value.toInt(&ok, 10); if(ok) { bottom = margin; } } m_margin = QMargins(left, top, right, bottom); } } void PaiComboBox::SetRealTimeValidate(bool flag) { m_RealTimeValidate = flag; } void PaiComboBox::keyPressEvent(QKeyEvent *pEvent) { if(pEvent->key() == Qt::Key_Return) { QComboBox::keyPressEvent(pEvent); pEvent->accept(); // 过滤事件,使其不往父窗体传递 return; } if((!m_RealTimeValidate) || (pEvent->key() == Qt::Key_Backspace) || (pEvent->key() == Qt::Key_Delete)) { QComboBox::keyPressEvent(pEvent); return; } QString currentStr = currentText(); QLineEdit *pLineEdit = lineEdit(); QString selectedText = pLineEdit->selectedText(); QString pressAfterStr; int pos = pLineEdit->cursorPosition(); if(selectedText.isEmpty()) { pressAfterStr = currentStr.insert(pos, pEvent->text()); } else { pressAfterStr = currentStr.replace(pLineEdit->selectionStart(), selectedText.size(), pEvent->text()); } const QValidator *pValidator = validator(); int postion = pressAfterStr.size(); if(pValidator && (pValidator->validate(pressAfterStr, postion) == QValidator::Invalid)) { pEvent->accept(); } else { QComboBox::keyPressEvent(pEvent); } return; } void PaiComboBox::resizeEvent(QResizeEvent *pEvent) { QComboBox::resizeEvent(pEvent); // 请不要添加m_pEditButton->isVisible()条件,因为没有paint之前控件是不可见的 if(m_AddButton && m_pEditButton) { // 为按钮所准备空间 setStyleSheet(QString::fromUtf8("QComboBox{margin-right:%1px}").arg(height())); } } void PaiComboBox::paintEvent(QPaintEvent *pEvent) { QComboBox::paintEvent(pEvent); if(m_AddButton && m_pEditButton && m_pEditButton->isVisible()) { // 添加限制条件确保这里不会频繁的调用 QRect rect(width()-height() - 1, 0, height() + 1, height()); if(m_pEditButton->geometry() != rect) { m_pEditButton->setGeometry(rect); } QPainter painter(this); painter.setPen(QColor("#839CB6")); painter.drawLine(width()-height() - 2, 6, width() - height() - 2, height() - 6); } }