玉兔远程控制 0.1.0-bate6
载入中...
搜索中...
未找到
AutoCompleteLineEdit.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include <QApplication>
4#include <QPainter>
5#include <QStyle>
6#include <QStyleOptionFrame>
7#include <QLoggingCategory>
8
9#include "AutoCompleteLineEdit.h"
10
11static Q_LOGGING_CATEGORY(log, "Web.LineEdit")
13 : QLineEdit(parent)
14{
15 initTimer();
16}
17
18CAutoCompleteLineEdit::CAutoCompleteLineEdit(const QString &contents, QWidget *parent)
19 : QLineEdit(contents, parent)
20{
21 initTimer();
22}
23
24void CAutoCompleteLineEdit::initTimer()
25{
26 // 设置定时器,避免频繁更新
27 m_updateTimer.setSingleShot(true);
28 m_updateTimer.setInterval(100); // 100ms延迟
29
30 connect(this, &QLineEdit::textChanged, this, [this]() {
31 m_updateTimer.start();
32 });
33
34 connect(&m_updateTimer, &QTimer::timeout, this, &CAutoCompleteLineEdit::updateCompletion);
35
36 QPalette palette = QApplication::palette();
37 m_suggestionColor = palette.color(QPalette::HighlightedText);
38 m_suggestionBackground = palette.color(QPalette::Highlight);
39}
40
41void CAutoCompleteLineEdit::setCompletions(const QStringList &completions)
42{
43 m_completions = completions;
44 m_currentSuggestion.clear();
45}
46
47void CAutoCompleteLineEdit::keyPressEvent(QKeyEvent *event)
48{
49 switch (event->key()) {
50 case Qt::Key_Tab:
51 case Qt::Key_Right:
52 // 按下Tab或右箭头接受建议
53 acceptSuggestion();
54 event->accept();
55 return;
56 case Qt::Key_Escape:
57 // ESC取消建议
58 hideSuggestion();
59 event->accept();
60 return;
61 default:
62 QLineEdit::keyPressEvent(event);
63 }
64}
65
66void CAutoCompleteLineEdit::focusInEvent(QFocusEvent *event)
67{
68 QLineEdit::focusInEvent(event);
69 if (!text().isEmpty()) {
70 updateCompletion();
71 }
72}
73
74void CAutoCompleteLineEdit::focusOutEvent(QFocusEvent *event)
75{
76 hideSuggestion();
77 QLineEdit::focusOutEvent(event);
78}
79
80void CAutoCompleteLineEdit::updateCompletion()
81{
82 QString input = text();
83
84 if (input.isEmpty()) {
85 hideSuggestion();
86 return;
87 }
88
89 QString suggestion = findBestMatch(input);
90 if (!suggestion.isEmpty() && suggestion != input) {
91 m_currentSuggestion = suggestion;
92 showSuggestion();
93 } else {
94 hideSuggestion();
95 }
96}
97
98QColor CAutoCompleteLineEdit::GetSuggestionColor() const
99{
100 return m_suggestionColor;
101}
102
103void CAutoCompleteLineEdit::SetSuggestionColor(const QColor &newSuggestionColor)
104{
105 m_suggestionColor = newSuggestionColor;
106}
107
108QColor CAutoCompleteLineEdit::GetSuggestionBackground() const
109{
110 return m_suggestionBackground;
111}
112
113void CAutoCompleteLineEdit::SetSuggestionBackground(const QColor &newSuggestionBackground)
114{
115 m_suggestionBackground = newSuggestionBackground;
116}
117
118QString CAutoCompleteLineEdit::findBestMatch(const QString &input) const
119{
120 if (m_completions.isEmpty()) {
121 return QString();
122 }
123
124 QString lowerInput = input.toLower();
125
126 // 1. 优先查找开头匹配的
127 for (const QString &completion : m_completions) {
128 if (completion.toLower().startsWith(lowerInput)) {
129 return completion;
130 }
131 }
132
133 // 2. 查找包含匹配的
134 for (const QString &completion : m_completions) {
135 if (completion.toLower().contains(lowerInput)) {
136 return completion;
137 }
138 }
139
140 return QString();
141}
142
143void CAutoCompleteLineEdit::showSuggestion()
144{
145 if (m_currentSuggestion.isEmpty() || m_currentSuggestion == text()) {
146 return;
147 }
148
149 QString currentText = text();
150 QString suggestion = m_currentSuggestion;
151
152 // 计算需要显示的补全部分
153 QString complement = suggestion.mid(currentText.length());
154
155 if (!complement.isEmpty()) {
156 // 设置带有建议的文本显示
157 QString displayText = currentText +
158 QString("<span style='color: gray; background-color: #f0f0f0;'>%1</span>")
159 .arg(complement.toHtmlEscaped());
160
161 // 这里我们使用paintEvent来绘制,稍后实现
162 update();
163 }
164}
165
166void CAutoCompleteLineEdit::hideSuggestion()
167{
168 m_currentSuggestion.clear();
169 update();
170}
171
172void CAutoCompleteLineEdit::acceptSuggestion()
173{
174 if (!m_currentSuggestion.isEmpty()) {
175 setText(m_currentSuggestion);
176 hideSuggestion();
177 emit editingFinished();
178 }
179}
180
181void CAutoCompleteLineEdit::paintEvent(QPaintEvent *event)
182{
183 // 先调用基类的绘制
184 QLineEdit::paintEvent(event);
185
186 if (m_currentSuggestion.isEmpty() || !hasFocus())
187 return;
188
189 QPainter painter(this);
190 painter.setRenderHint(QPainter::Antialiasing);
191
192 // 如果有建议,绘制背景补全
193 QString currentText = text();
194 if (currentText.isEmpty() || currentText == m_currentSuggestion) {
195 return;
196 }
197
198 // 计算补全部分
199 QString complement = m_currentSuggestion; //.mid(currentText.length());
200 if (complement.isEmpty()) {
201 return;
202 }
203
204 // 获取当前文本的位置和大小
205 QFontMetrics fm(font());
206 int textWidth = fm.horizontalAdvance(currentText);
207 int textHeight = fm.height();
208
209 // 计算光标位置
210 int cursorPos = cursorPosition();
211 QString textBeforeCursor = currentText.left(cursorPos);
212 int cursorX = fm.horizontalAdvance(textBeforeCursor);
213
214 // 计算补全文本的起始位置
215 QRect contentRect = contentsRect();
216
217 int leftMargin = 0;
218
219 // 获取文本对齐方式
220 Qt::Alignment alignment = this->alignment();
221 if (alignment & Qt::AlignHCenter) {
222 leftMargin = (contentRect.width() - fm.horizontalAdvance(currentText + complement)) / 2;
223 } else if (alignment & Qt::AlignRight) {
224 leftMargin = contentRect.width() - fm.horizontalAdvance(currentText + complement);
225 }
226
227 // 绘制背景补全文本
228 painter.save();
229
230 painter.setPen(m_suggestionColor);
231
232 int left = height()/*icon*/ + fm.horizontalAdvance("W") + leftMargin + textWidth;
233
234 // 如果使用背景色
235 QRect rBackground(left,
236 (height() - textHeight) / 2,
237 fm.horizontalAdvance(complement),
238 textHeight);
239 painter.fillRect(rBackground,
240 m_suggestionBackground);
241
242 qDebug(log) << "currentText width:" << textWidth << "; height:" << textHeight
243 << currentText << "Background:" << rBackground
244 << "; cursorX:" << cursorX << "; cursorPos:" << cursorPos;
245
246 painter.drawText(left,
247 (height() + fm.ascent() - fm.descent()) / 2,
248 complement);
249 painter.restore();
250
251}