Completer 예제
Completer 예제는 모델에서 제공하는 데이터를 기반으로 입력 위젯에 문자열 자동 완성 기능을 구현하는 방법을 보여줍니다.

이 예제는 사용자 정의 항목 모델인 ` FileSystemModel`과 ` QCompleter ` 객체를 사용합니다. ` QCompleter `은 항목 모델을 기반으로 자동 완성 기능을 제공하는 클래스입니다. 모델 유형, 자동 완성 모드 및 대소문자 구분 여부는 콤보 박스를 사용하여 선택할 수 있습니다.
리소스 파일
Completer 예제에서는 countries.txt 및 words.txt 파일을 저장하기 위한 리소스 파일이 필요합니다. 리소스 파일에는 다음 코드가 포함되어 있습니다.
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/">
<file>resources/countries.txt</file>
<file>resources/wordlist.txt</file>
</qresource>
</RCC>FileSystemModel 클래스 정의
FileSystemModel 클래스는 로컬 파일 시스템에 대한 데이터 모델을 제공하는 QFileSystemModel 의 서브클래스입니다.
class FileSystemModel : public QFileSystemModel
{
public:
FileSystemModel(QObject *parent = nullptr);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
};이 클래스는 생성자와 ` data() ` 함수만 가지고 있는데, 이는 ` QFileSystemModel`의 ` data() ` 함수가 폴더만 반환하고 드라이브 레이블은 반환하지 않는 것과는 달리, ` data() `가 표시 역할을 위해 전체 파일 경로를 반환할 수 있도록 하기 위해 생성된 것이기 때문입니다. 이에 대한 자세한 설명은 ` FileSystemModel`의 구현 부분에서 확인할 수 있습니다.
FileSystemModel 클래스 구현
FileSystemModel 클래스의 생성자는 parent 를 QFileSystemModel 에 전달하는 데 사용됩니다.
FileSystemModel::FileSystemModel(QObject *parent)
: QFileSystemModel(parent)
{
}앞서 언급했듯이, data() 함수는 표시 용도로 전체 파일 경로를 반환하도록 재구현되었습니다. 예를 들어, QFileSystemModel 을 사용할 경우 뷰에 "Program Files"가 표시됩니다. 반면, FileSystemModel 을 사용하면 "C:\Program Files"가 표시됩니다.
QVariant FileSystemModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole && index.column() == 0) {
QString path = QDir::toNativeSeparators(filePath(index));
if (path.endsWith(QDir::separator()))
path.chop(1);
return path;
}
return QFileSystemModel::data(index, role);
}QCompleter 이 일치 항목을 찾기 위해 사용하는 Qt::EditRole 은 변경되지 않습니다.
MainWindow 클래스 정의
MainWindow 클래스는 QMainWindow 의 하위 클래스이며, about(), changeCase(), changeMode(), changeModel(), changeMaxVisible() 등 다섯 개의 비공개 슬롯을 구현합니다.
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
private slots:
void about();
void changeCase(int);
void changeMode(int);
void changeModel();
void changeMaxVisible(int);MainWindow 클래스 내에는 createMenu() 와 modelFromFile() 라는 두 개의 비공개 함수가 있습니다. 또한 필요한 비공개 위젯을 선언하는데, QComboBox 객체 3개, QCheckBox 1개, QCompleter 1개, QLabel 1개, 그리고 QLineEdit 1개입니다.
private:
void createMenu();
QAbstractItemModel *modelFromFile(const QString &fileName);
QComboBox *caseCombo = nullptr;
QComboBox *modeCombo = nullptr;
QComboBox *modelCombo = nullptr;
QSpinBox *maxVisibleSpinBox = nullptr;
QCheckBox *wrapCheckBox = nullptr;
QCompleter *completer = nullptr;
QLabel *contentsLabel = nullptr;
QLineEdit *lineEdit = nullptr;
};MainWindow 클래스 구현
MainWindow 의 생성자는 부모 위젯을 가진 MainWindow 를 생성하고 비공개 멤버를 초기화합니다. 그런 다음 createMenu() 함수가 호출됩니다.
세 개의 QComboBox 객체, 즉 modelComb, modeCombo 및 caseCombo 를 설정합니다. 기본적으로 modelCombo 는 QFileSystemModel 로, modeCombo 는 "Filtered Popup"으로, caseCombo 는 "Case Insensitive"로 설정됩니다.
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
createMenu();
QWidget *centralWidget = new QWidget;
QLabel *modelLabel = new QLabel;
modelLabel->setText(tr("Model"));
modelCombo = new QComboBox;
modelCombo->addItem(tr("QFileSystemModel"));
modelCombo->addItem(tr("QFileSystemModel that shows full path"));
modelCombo->addItem(tr("Country list"));
modelCombo->addItem(tr("Word list"));
modelCombo->setCurrentIndex(0);
QLabel *modeLabel = new QLabel;
modeLabel->setText(tr("Completion Mode"));
modeCombo = new QComboBox;
modeCombo->addItem(tr("Inline"));
modeCombo->addItem(tr("Filtered Popup"));
modeCombo->addItem(tr("Unfiltered Popup"));
modeCombo->setCurrentIndex(1);
QLabel *caseLabel = new QLabel;
caseLabel->setText(tr("Case Sensitivity"));
caseCombo = new QComboBox;
caseCombo->addItem(tr("Case Insensitive"));
caseCombo->addItem(tr("Case Sensitive"));
caseCombo->setCurrentIndex(0);maxVisibleSpinBox 가 생성되며, 이는 완성기(completer)에 표시될 항목의 수를 결정합니다.
그런 다음 wrapCheckBox 를 설정합니다. 이 checkBox 는 completer 의 setWrapAround() 속성이 활성화되었는지 비활성화되었는지를 결정합니다.
QLabel *maxVisibleLabel = new QLabel;
maxVisibleLabel->setText(tr("Max Visible Items"));
maxVisibleSpinBox = new QSpinBox;
maxVisibleSpinBox->setRange(3,25);
maxVisibleSpinBox->setValue(10);
wrapCheckBox = new QCheckBox;
wrapCheckBox->setText(tr("Wrap around completions"));
wrapCheckBox->setChecked(true);contentsLabel 를 인스턴스화하고 그 크기 정책을 fixed 로 설정합니다. 그런 다음 콤보 박스의 activated() 신호를 각 슬롯에 연결합니다.
contentsLabel = new QLabel;
contentsLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
connect(modelCombo, &QComboBox::activated,
this, &MainWindow::changeModel);
connect(modeCombo, &QComboBox::activated,
this, &MainWindow::changeMode);
connect(caseCombo, &QComboBox::activated,
this, &MainWindow::changeCase);
connect(maxVisibleSpinBox, &QSpinBox::valueChanged,
this, &MainWindow::changeMaxVisible);lineEdit 가 설정된 후, QGridLayout 을 사용하여 모든 위젯을 배치합니다. completer 을 초기화하기 위해 changeModel() 함수가 호출됩니다.
lineEdit = new QLineEdit;
QGridLayout *layout = new QGridLayout;
layout->addWidget(modelLabel, 0, 0); layout->addWidget(modelCombo, 0, 1);
layout->addWidget(modeLabel, 1, 0); layout->addWidget(modeCombo, 1, 1);
layout->addWidget(caseLabel, 2, 0); layout->addWidget(caseCombo, 2, 1);
layout->addWidget(maxVisibleLabel, 3, 0); layout->addWidget(maxVisibleSpinBox, 3, 1);
layout->addWidget(wrapCheckBox, 4, 0);
layout->addWidget(contentsLabel, 5, 0, 1, 2);
layout->addWidget(lineEdit, 6, 0, 1, 2);
centralWidget->setLayout(layout);
setCentralWidget(centralWidget);
changeModel();
setWindowTitle(tr("Completer"));
lineEdit->setFocus();
}createMenu() 함수는 fileMenu 와 helpMenu 을 채우는 데 필요한 QAction 객체를 인스턴스화하는 데 사용됩니다. 액션의 triggered() 신호는 각각의 슬롯에 연결됩니다.
void MainWindow::createMenu()
{
QAction *exitAction = new QAction(tr("Exit"), this);
QAction *aboutAct = new QAction(tr("About"), this);
QAction *aboutQtAct = new QAction(tr("About Qt"), this);
connect(exitAction, &QAction::triggered, qApp, &QApplication::quit);
connect(aboutAct, &QAction::triggered, this, &MainWindow::about);
connect(aboutQtAct, &QAction::triggered, qApp, &QApplication::aboutQt);
QMenu *fileMenu = menuBar()->addMenu(tr("File"));
fileMenu->addAction(exitAction);
QMenu *helpMenu = menuBar()->addMenu(tr("About"));
helpMenu->addAction(aboutAct);
helpMenu->addAction(aboutQtAct);
}modelFromFile() 함수는 파일의 fileName 을 받아 그 내용에 따라 처리합니다.
먼저 file 을 검증하여 QFile::ReadOnly 모드로 열 수 있는지 확인합니다. 이 작업이 실패하면, 함수는 빈 QStringListModel 을 반환합니다.
QAbstractItemModel *MainWindow::modelFromFile(const QString &fileName)
{
QFile file(fileName);
if (!file.open(QFile::ReadOnly))
return new QStringListModel(completer);그런 다음 Qt::WaitCursor 로 마우스 커서를 재정의한 후, QStringList 객체( words)를 file 의 내용으로 채웁니다. 이 작업이 완료되면 마우스 커서를 원래대로 복원합니다.
#ifndef QT_NO_CURSOR
QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
#endif
QStringList words;
while (!file.atEnd()) {
QByteArray line = file.readLine();
if (!line.isEmpty())
words << QString::fromUtf8(line.trimmed());
}
#ifndef QT_NO_CURSOR
QGuiApplication::restoreOverrideCursor();
#endif앞서 언급했듯이, 리소스 파일에는 countries.txt와 words.txt라는 두 개의 파일이 포함되어 있습니다. file 에서 읽은 값이 words.txt인 경우, words 을 QStringList 로, completer 을 부모로 하는 QStringListModel 를 반환합니다.
if (!fileName.contains(QLatin1String("countries.txt")))
return new QStringListModel(words, completer);file 에서 countries.txt를 읽은 경우, words.count() 개의 행과 2개의 열을 가지며 completer 를 부모로 하는 QStandardItemModel 가 필요합니다.
QStandardItemModel *m = new QStandardItemModel(words.count(), 2, completer);countries.txt 파일의 표준 행은 다음과 같습니다.
Norway NO
따라서 QStandardItemModel 객체인 m 에 데이터를 채우려면 국가명과 그 약어를 분리해야 합니다. 이 작업이 완료되면 m 를 반환합니다.
for (int i = 0; i < words.count(); ++i) {
QModelIndex countryIdx = m->index(i, 0);
QModelIndex symbolIdx = m->index(i, 1);
QString country = words.at(i).mid(0, words[i].length() - 2).trimmed();
QString symbol = words.at(i).right(2);
m->setData(countryIdx, country);
m->setData(symbolIdx, symbol);
}
return m;
}changeMode() 함수는 index 의 값에 따라 completer 의 모드를 설정합니다.
void MainWindow::changeMode(int index)
{
QCompleter::CompletionMode mode;
if (index == 0)
mode = QCompleter::InlineCompletion;
else if (index == 1)
mode = QCompleter::PopupCompletion;
else
mode = QCompleter::UnfilteredPopupCompletion;
completer->setCompletionMode(mode);
}changeModel() 함수는 사용자가 선택한 모델에 따라 사용되는 항목 모델을 변경합니다.
switch 문은 modelCombo 의 인덱스를 기반으로 항목 모델을 변경하는 데 사용됩니다. case 가 0인 경우, 정렬되지 않은 QFileSystemModel 를 사용하여 드라이브 레이블이 제외된 파일 경로를 제공합니다.
void MainWindow::changeModel()
{
delete completer;
completer = new QCompleter(this);
completer->setMaxVisibleItems(maxVisibleSpinBox->value());
switch (modelCombo->currentIndex()) {
default:
case 0:
{ // Unsorted QFileSystemModel
QFileSystemModel *fsModel = new QFileSystemModel(completer);
fsModel->setRootPath(QString());
completer->setModel(fsModel);
contentsLabel->setText(tr("Enter file path"));
}
break;completer 을 상위 모델로 지정하여 모델을 생성하는 점에 유의하십시오. 이렇게 하면 기존 모델을 새 모델로 대체할 수 있습니다. completer 은 새 모델이 할당되는 즉시 기존 모델이 삭제되도록 보장합니다.
case 가 1인 경우, 앞서 정의한 DirModel 를 사용하여 파일의 전체 경로를 반환합니다.
case 1:
{ // FileSystemModel that shows full paths
FileSystemModel *fsModel = new FileSystemModel(completer);
completer->setModel(fsModel);
fsModel->setRootPath(QString());
contentsLabel->setText(tr("Enter file path"));
}
break;case 가 2인 경우, 국가 이름을 자동 완성하려고 시도합니다. 이를 위해서는 QTreeView 객체( treeView)가 필요합니다. 국가 이름은 countries.txt에서 추출되며, 자동 완성 결과를 표시하는 팝업은 treeView 로 설정됩니다.
case 2:
{ // Country List
completer->setModel(modelFromFile(":/resources/countries.txt"));
QTreeView *treeView = new QTreeView;
completer->setPopup(treeView);
treeView->setRootIsDecorated(false);
treeView->header()->hide();
treeView->header()->setStretchLastSection(false);
treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
treeView->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
contentsLabel->setText(tr("Enter name of your country"));
}
break;아래 스크린샷은 국가 목록 모델이 적용된 Completer를 보여줍니다.

case 가 3인 경우, 단어 자동 완성 기능을 시도합니다. 이는 words.txt에서 추출한 데이터를 포함하는 QStringListModel 를 사용하여 수행됩니다. 모델은 case insensitively 에 정렬되어 있습니다.
아래 스크린샷은 단어 목록 모델을 사용하는 Completer를 보여줍니다.

모델 유형이 선택되면, changeMode() 함수와 changeCase() 함수를 호출하고 wrap 옵션을 적절히 설정합니다. wrapCheckBox 의 clicked() 신호는 completer 의 setWrapAround() 슬롯에 연결됩니다.
case 3:
{ // Word list
completer->setModel(modelFromFile(":/resources/wordlist.txt"));
completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
contentsLabel->setText(tr("Enter a word"));
}
break;
}
changeMode(modeCombo->currentIndex());
changeCase(caseCombo->currentIndex());
completer->setWrapAround(wrapCheckBox->isChecked());
lineEdit->setCompleter(completer);
connect(wrapCheckBox, &QAbstractButton::clicked, completer, &QCompleter::setWrapAround);
}changeMaxVisible() 는 컴플리터의 최대 표시 항목 수를 업데이트합니다.
void MainWindow::changeMaxVisible(int max)
{
completer->setMaxVisibleItems(max);
}about() 함수는 예제에 대한 간략한 설명을 제공합니다.
void MainWindow::about()
{
QMessageBox::about(this, tr("About"), tr("This example demonstrates the "
"different features of the QCompleter class."));
}main() 함수
main() 함수는 QApplication 및 MainWindow 를 인스턴스화하고 show() 함수를 호출합니다.
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.