解决方案是使用模型视图模式进行组合框和子类化QComboBox。
1:实现自定义模型。在我的情况下,我在 row = 2 (QString m_strEditableValue) 中有可编辑项目,在 0,1 行中有固定项目。
class MyModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit MyModel(QObject *parent = nullptr);
QModelIndex index(int row, int column, const QModelIndex &parent) const;
QModelIndex parent(const QModelIndex &child) const;
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
Qt::ItemFlags flags(const QModelIndex &index) const;
private:
QString m_strEditableValue;
};
MyModel::MyModel(QObject *parent) : QAbstractItemModel(parent)
{
m_strEditableValue = "default value";
}
QModelIndex MyModel::index(int row, int column, const QModelIndex &parent) const
{
return createIndex(row, column);
}
QModelIndex MyModel::parent(const QModelIndex &child) const
{
return QModelIndex();
}
int MyModel::rowCount(const QModelIndex &parent) const
{
return 3;
}
int MyModel::columnCount(const QModelIndex &parent) const
{
return 1;
}
QVariant MyModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole || role == Qt::EditRole)
{
if (index.row() == 0) {
return tr("First fixed value");
}
if (index.row() == 1) {
return tr("Second fixed value");
}
if (index.row() == 2) {
return m_strEditableValue;
}
}
return QVariant();
}
bool MyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role == Qt::EditRole) {
if (index.row() == 2) {
m_strEditableValue = value.toString();
return true;
}
}
return false;
}
Qt::ItemFlags MyModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags f = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
if (index.row() == 2) {
//mark editable only for row 2
f = f | Qt::ItemIsEditable;
}
return f;
}
2:子类QComboBox 改变标准行为
class MyCombobox : public QComboBox
{
Q_OBJECT
public:
explicit MyCombobox(QWidget *parent = nullptr);
private slots:
void OnEditTextChanged(const QString& text);
void OnCurrentIndexChanged(int index);
public slots:
};
MyCombobox::MyCombobox(QWidget *parent) : QComboBox(parent)
{
connect(this, &QComboBox::editTextChanged, this, &MyCombobox::OnEditTextChanged);
connect(this, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MyCombobox::OnCurrentIndexChanged);
}
void MyCombobox::OnEditTextChanged(const QString &text)
{
if (model()) {
//set data to model immediately
model()->setData(model()->index(currentIndex(), 0), text);
}
}
void MyCombobox::OnCurrentIndexChanged(int index)
{
if (model())
{
//disable editing if model disable it
Qt::ItemFlags flags = model()->flags(model()->index(index, 0));
if (flags & Qt::ItemIsEditable) {
lineEdit()->setReadOnly(false);
} else {
lineEdit()->setReadOnly(true);
}
}
}
3:使用
MyModel *cbModel = new MyModel(this);
ui->cbEditable->setModel(cbModel);