#qt #qcombobox #qcompleter
#qt #qcombobox #qcompleter
Вопрос:
Я создаю завершитель для 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 amp;p_parent ) const
{
return createIndex( p_row, p_column, nullptr );
}
QModelIndex CompleterSourceModel::parent( const QModelIndex amp;p_index ) const
{
return {};
}
int CompleterSourceModel::rowCount( const QModelIndex amp;p_parent ) const
{
return m_completerData.data().size();
}
int CompleterSourceModel::columnCount( const QModelIndex amp;p_parent ) const
{
return m_completerData.headers().size() 1; // 1 is for my purpose
}
QVariant CompleterSourceModel::data( const QModelIndex amp;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 amp;amp; p_orientation == Qt::Horizontal )
{
if ( m_completerData.headers().size() > p_section )
{
return m_completerData.headers().at( p_section );
}
}
return {};
}
void CompleterSourceModel::setCompleterData( const CompleterData amp;p_completerData )
{
m_completerData = p_completerData;
}
Я просмотрел и сравнил свой код с 4 примерами Qt для Completer
пример 1 , пример 2, пример 3, пример 4
На мой взгляд, я не вижу разницы между mein code и их кодом. Они просто устанавливаются setCompleter()
и ничего более особенного, сигнал / слот не требуется. Но я не знаю, почему мой код не работает. Когда я набираю в выпадающем списке, ничего не отображается. Не могли бы вы показать мне что-то нехорошее в моем коде?
Обновить
CompleterData.cpp
QMap < QList<QPair<QString, QVariant>>, CompleterData::Type> CompleterData::data() const
{
return m_data;
}
void CompleterData::addData( const QList<QPair<QString, QVariant>> amp;p_rowData, CompleterData::Type p_type )
{
m_data.insert( p_rowData, p_type );
}
void CompleterData::setData( const QMap < QList<QPair<QString, QVariant>>, CompleterData::Type> amp;p_data )
{
m_data = p_data;
}
void CompleterData::setTitle( const QString amp;p_title )
{
m_title = p_title;
}
const QString amp;CompleterData::title() const
{
return m_title;
}
void CompleterData::setHeaders( const QStringList amp;p_headers )
{
m_headers = p_headers;
}
const QStringList amp;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> amp;p_data );
void addData( const QList<QPair<QString, QVariant>> amp;p_rowData, CompleterData::Type p_type );
void setHeaders( const QStringList amp;p_headers );
void setTitle( const QString amp;p_label );
const QStringList amp;headers() const;
const QString amp;title() const;
private:
QMap <QList<QPair<QString, QVariant>>, CompleterData::Type> m_data;
QString m_title;
QStringList m_headers;
};
Комментарии:
1. Не могли бы вы предоставить свой
CompleterData
класс?2. @RomhaKorev: Я обновил 🙂
3. Ваша модель очень сложна только для представления дерева. Почему вы не используете
QStandardItemModel
?4. @RomhaKorev: я не думаю, что это слишком сложно в моем случае. Вы думаете, что моя модель здесь может привести к проблеме? И есть ли какое-либо преимущество при использовании
QStandardItemModel
по сравнению сQAbstractItemModel
?5. на самом деле мне рекомендуется использовать
QAbstractItemModel
для большей гибкости. И до сих пор я все еще использую этот класс.