logplus/qtpropertybrowser/qtComboBox.cpp

531 lines
15 KiB
C++
Raw Normal View History

/**
* @file QtComboBox.cpp
* @date 2011-10-17
*/
#include <QStyledItemDelegate>
#include <QApplication>
#include <QPainter>
#include <QValidator>
#include <QKeyEvent>
#include <QLineEdit>
#include <QPaintEvent>
#include <QDesktopWidget>
#include <QFontMetrics>
#include <QAbstractItemView>
#include "qtComboBox.h"
/**
* @class QtComboBoxItemDelegate
* @brief ComboBox弹出选择框Item
*/
class QTPROPERTYBROWSER_EXPORT QtComboBoxItemDelegate : public QStyledItemDelegate
{
public:
QtComboBoxItemDelegate(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);
}
};
/////////////////////////////////////////////////////////////////////
QtComboBox::QtComboBox(QWidget *pParent) :
QComboBox(pParent),
m_AddButton(false)
{
InitComboBox();
}
QtComboBox::QtComboBox(bool showAddButton, QWidget *pParent)
: QComboBox(pParent),
m_AddButton(showAddButton)
{
InitComboBox();
SetShowAddButton(m_AddButton);
}
QtComboBox::~QtComboBox()
{
}
void QtComboBox::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<QWidget*>(pObj);
if(pWgt && (pWgt != pView))
{
pWgt->setMaximumHeight(0);
}
}
setItemDelegate(new QtComboBoxItemDelegate(this));
}
void QtComboBox::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 QtComboBox::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 QtComboBox::GetMaxVisibleItems() const
{
return m_MaxVisibleItems;
}
void QtComboBox::SetMaxVisibleItems(const int count)
{
m_MaxVisibleItems = count;
}
void QtComboBox::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 QtComboBox::SetRealTimeValidate(bool flag)
{
m_RealTimeValidate = flag;
}
void QtComboBox::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 QtComboBox::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 QtComboBox::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);
}
}