最近需要在QComboBox中显示富文本,查询了好久都没发现如何实现,查看QCombox的代码发现,QComboBox显示时是分别由一个List和一个LineEdit来显示的,于是开始考虑先实现List和QLineEdit的富文本显示。
其中QListView已有人实现过富文本显示,参考此文章:
QComboBox* box = new QComboBox();
box->setItemDelegate(new textModel(15, 20));
其中,15与20是宽与高,因为我还重写了sizeHint函数,方便在不同场合使用时设置不同的尺寸。
此时,QComboBox在下拉时可以实现富文本显示,但是当下拉框隐藏时,依旧无法显示富文本,因为隐藏下拉框时,QComboBox通过一个QLineEdit来显示内容,而QLineEdit则不支持富文本,因此需要修改QLineEdit;
根据重写textModel类的经验,这次直接添加myLineEdit类,继承QLinEdit,重写其paint函数,实现富文本,再将其添加至QComboBox控件中即可。
box->setLineEdit(edit);
此时QComboBox已经可以正常显示富文本了,但又出现一个新问题:lineEdit所在区域,鼠标点击时,无法正常下拉只能在右侧箭头处下拉,还得修改。
普通的调用函数已经不能解决此问题了,只能重写QComboBox,于是创建meComboBox继承于QComboBox,同时给myLineEdit加上一个信号,当鼠标点击时,会传递一个click信号;由于QLineEdit没有click信号,只好重写其鼠标事件。
void myLineEdit::mousePressEvent(QMouseEvent * event)
{
if (event->type() == QEvent::MouseButtonPress&&event->button() == Qt::LeftButton) {
emit clicked();
}
QLineEdit::mousePressEvent(event);
}
这次直接在myComboBox中一劳永逸了。
if(edit==nullptr) edit = new myLineEdit();
edit->setReadOnly(true);
this->setLineEdit(edit);
this->setItemDelegate(new textModel(15, 20));
connect(edit, SIGNAL(clicked()), this, SLOT(editClicked()));
原本的想法是,接收到信号后,先确定当前ComboBox下拉框状态,再确定是打开还是隐藏下拉框,但是这个思路出现了问题。鼠标点击时,如果下拉框已经打开,会关闭一次再打开,正常逻辑应该是点击时,直接关闭,但这里多出一次打开。
查看QComboBox代码,发现原因在于,鼠标点击时,会直接触发一次关闭,这个关闭事件在lineEdit传来信号之前发生,于是当LineEdit信号传来之后,检测到下拉框已关闭,便会再次打开。因此还需要重写hidePopup函数,在关闭下拉框时判断一次,具体代码如下:
void myComboBox::hidePopup()
{
QPoint p = QCursor::pos();
if (edit->geometry().contains(this->mapFromGlobal(QCursor::pos()))) isHide = false;
else isHide = true;
QComboBox::hidePopup();
}
void myComboBox::editClicked()
{
if (isHide) showPopup();
else {
isHide = true;
}
}
下拉框每次关闭时,都会调用一次hidePopup()函数,在此时检测鼠标位置,如果当前鼠标位置在LineEdit范围内,则将isHide置为false,否则置为true;
当下拉框打开时,用户点击LineEdit区域,下拉框自动关闭,isHide=false->LineEdit传来信号,判断后,isHide=true。用户下一次点击LineEdit区域,由于下拉框已关闭,不触发hidePopup()函数,则当LineEdit信号传来,正常打开下拉框。用户点击其他区域,下拉框关闭,isHide=true,用户下次点击时,正常打开下拉框。
由此,成功实现了QComboBox的富文本显示,同时实现了myLineEdit类和textModel类,其中textModel类还可用于QListView、QTableView、QtreeView的富文本显示。