Я создаю завершитель для Combobox.
MyComboBox.cpp
MyComboBox::MyComboBox( QWidget *p_parent ) : QComboBox( p_parent )
{
setEditable( true );
m_view = new CompleterView();
m_sourceModel = new CompleterSourceModel( this );
m_sourceModel->setCompleterData( createTestData() ); //here I put test data for debugging.
// I have checked, data is loaded into the model successfully.
setView( m_view );
setModel( m_sourceModel );
QCompleter *completer = new QCompleter( m_sourceModel, this );
completer->setCompletionMode( QCompleter::PopupCompletion );
completer->setModelSorting( QCompleter::CaseInsensitivelySortedModel );
completer->setFilterMode( Qt::MatchContains );
completer->setCaseSensitivity( Qt::CaseInsensitive );
completer->setWrapAround( true );
setCompleter( completer );
}
Мое представление основано на TreeView
CompleterView.cpp
CompleterView::CompleterView( QWidget *p_parent ) : QTreeView( p_parent )
{
setFocusPolicy( Qt::NoFocus );
setCursor( QCursor( Qt::PointingHandCursor ) );
setFrameShape( QFrame::NoFrame );
setSelectionBehavior( QAbstractItemView::SelectRows );
setSelectionMode( QAbstractItemView::SingleSelection );
setRootIsDecorated( false );
setSortingEnabled( true );
setIndentation( 0 );
expandAll();
}
Моя модель основана на QAbstractItemModel
(функции parent
и index
здесь не важны для моего случая)
CompleterSourceModel.cpp
CompleterSourceModel::CompleterSourceModel( QObject *p_parent ) : QAbstractItemModel( p_parent )
{
}
QModelIndex CompleterSourceModel::index( int p_row, int p_column, const QModelIndex &p_parent ) const
{
return createIndex( p_row, p_column, nullptr );
}
QModelIndex CompleterSourceModel::parent( const QModelIndex &p_index ) const
{
return {};
}
int CompleterSourceModel::rowCount( const QModelIndex &p_parent ) const
{
return m_completerData.data().size();
}
int CompleterSourceModel::columnCount( const QModelIndex &p_parent ) const
{
return m_completerData.headers().size() + 1; //+1 is for my purpose
}
QVariant CompleterSourceModel::data( const QModelIndex &p_index, int p_role ) const
{
if ( p_role == Qt::UserRole )
{
if ( m_completerData.data().values().size() > p_index.row() )
{
return QVariant( static_cast<int>( m_completerData.data().values().at( p_index.row() ) ) );
}
}
else if ( p_role == Qt::DisplayRole )
{
QList<QPair<QString, QVariant>> rowContent = m_completerData.data().keys().at( p_index.row() );
CompleterData::Type type = m_completerData.data().values().at( p_index.row() );
if ( type == CompleterData::Type::Header || type == CompleterData::Type::SecondHeader )
{
if ( p_index.column() == 0 )
{
return rowContent.first().first;
}
}
else
{
if ( rowContent.size() > p_index.column() )
{
return rowContent.at( p_index.column() ).first;
}
}
}
return {};
}
QVariant CompleterSourceModel::headerData( int p_section, Qt::Orientation p_orientation, int p_role ) const
{
if ( p_role == Qt::DisplayRole && p_orientation == Qt::Horizontal )
{
if ( m_completerData.headers().size() > p_section )
{
return m_completerData.headers().at( p_section );
}
}
return {};
}
void CompleterSourceModel::setCompleterData( const CompleterData &p_completerData )
{
m_completerData = p_completerData;
}
Я посмотрел и сравнил свой код с 4 примерами Qt для Completer пример 1 пример 2 пример 3 пример 4
По-моему, я не вижу различий между кодом mein и их кодом.Они просто устанавливают setCompleter()
и ничего более особенного, сигнал / слот не требуется.Но я не знаю, почему мой код не работает.Когда я набираю в выпадающем списке, ничего не появляется.Не могли бы вы показать что-то нехорошее в моем коде?
Обновление
CompleterData.cpp
QMap < QList<QPair<QString, QVariant>>, CompleterData::Type> CompleterData::data() const
{
return m_data;
}
void CompleterData::addData( const QList<QPair<QString, QVariant>> &p_rowData, CompleterData::Type p_type )
{
m_data.insert( p_rowData, p_type );
}
void CompleterData::setData( const QMap < QList<QPair<QString, QVariant>>, CompleterData::Type> &p_data )
{
m_data = p_data;
}
void CompleterData::setTitle( const QString &p_title )
{
m_title = p_title;
}
const QString &CompleterData::title() const
{
return m_title;
}
void CompleterData::setHeaders( const QStringList &p_headers )
{
m_headers = p_headers;
}
const QStringList &CompleterData::headers() const
{
return m_headers;
}
CompleterData.h
class CompleterData
{
public:
enum Type
{
Header,
SecondHeader,
Data,
LastUsed
};
CompleterData() = default;
QMap <QList<QPair<QString, QVariant>>, CompleterData::Type> data() const;
void setData( const QMap < QList<QPair<QString, QVariant>>, CompleterData::Type> &p_data );
void addData( const QList<QPair<QString, QVariant>> &p_rowData, CompleterData::Type p_type );
void setHeaders( const QStringList &p_headers );
void setTitle( const QString &p_label );
const QStringList &headers() const;
const QString &title() const;
private:
QMap <QList<QPair<QString, QVariant>>, CompleterData::Type> m_data;
QString m_title;
QStringList m_headers;
};