├── app.ico
├── Other
├── 1.png
├── 2.png
├── 3.png
├── file_dir.png
├── QtKeyboard.gif
├── QtKeyboard.mp4
├── chinese_input.jpg
└── chinese_input_demo.gif
├── Resources
├── Image
│ ├── caplock.png
│ ├── enter.png
│ ├── pack_up.png
│ ├── space.png
│ └── backspace.png
├── Font
│ └── wqy-microhei.ttc
├── Font.qrc
├── GoogleChineseLib
│ ├── dict_pinyin.dat
│ ├── valid_utf16.txt
│ ├── rawdict_utf16_65105_freq.txt
│ ├── rawdict_utf16_65105_freq_sort.txt
│ └── sort.h
├── ChineseLib.qrc
├── ChinesePhraseLib.qrc
├── GoogleChineseLib.qrc
└── Image.qrc
├── .gitignore
├── Keyboard
├── NumberKeyboard.h
├── AbstractKeyboard.h
├── KeyButton.h
├── Keyboard.h
├── NumberKeyboard.cpp
├── KeyButton.cpp
└── Keyboard.cpp
├── LICENSE
├── QtKeyboard.pro
├── main.cpp
└── README.md
/app.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/app.ico
--------------------------------------------------------------------------------
/Other/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Other/1.png
--------------------------------------------------------------------------------
/Other/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Other/2.png
--------------------------------------------------------------------------------
/Other/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Other/3.png
--------------------------------------------------------------------------------
/Other/file_dir.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Other/file_dir.png
--------------------------------------------------------------------------------
/Other/QtKeyboard.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Other/QtKeyboard.gif
--------------------------------------------------------------------------------
/Other/QtKeyboard.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Other/QtKeyboard.mp4
--------------------------------------------------------------------------------
/Other/chinese_input.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Other/chinese_input.jpg
--------------------------------------------------------------------------------
/Resources/Image/caplock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Resources/Image/caplock.png
--------------------------------------------------------------------------------
/Resources/Image/enter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Resources/Image/enter.png
--------------------------------------------------------------------------------
/Resources/Image/pack_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Resources/Image/pack_up.png
--------------------------------------------------------------------------------
/Resources/Image/space.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Resources/Image/space.png
--------------------------------------------------------------------------------
/Other/chinese_input_demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Other/chinese_input_demo.gif
--------------------------------------------------------------------------------
/Resources/Image/backspace.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Resources/Image/backspace.png
--------------------------------------------------------------------------------
/Resources/Font/wqy-microhei.ttc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Resources/Font/wqy-microhei.ttc
--------------------------------------------------------------------------------
/Resources/Font.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | Font/wqy-microhei.ttc
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Resources/GoogleChineseLib/dict_pinyin.dat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Resources/GoogleChineseLib/dict_pinyin.dat
--------------------------------------------------------------------------------
/Resources/GoogleChineseLib/valid_utf16.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Resources/GoogleChineseLib/valid_utf16.txt
--------------------------------------------------------------------------------
/Resources/ChineseLib.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | ChineseLib/pinyin.txt
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Resources/ChinesePhraseLib.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | ChinesePhraseLib/pinyin_phrase.txt
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Resources/GoogleChineseLib/rawdict_utf16_65105_freq.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Resources/GoogleChineseLib/rawdict_utf16_65105_freq.txt
--------------------------------------------------------------------------------
/Resources/GoogleChineseLib/rawdict_utf16_65105_freq_sort.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aeagean/QtKeyboard/HEAD/Resources/GoogleChineseLib/rawdict_utf16_65105_freq_sort.txt
--------------------------------------------------------------------------------
/Resources/GoogleChineseLib.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | GoogleChineseLib/rawdict_utf16_65105_freq_sort.txt
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Resources/Image.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | Image/backspace.png
4 | Image/enter.png
5 | Image/space.png
6 | Image/caplock.png
7 | Image/pack_up.png
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Compiled Object files
5 | *.slo
6 | *.lo
7 | *.o
8 | *.obj
9 |
10 | # Precompiled Headers
11 | *.gch
12 | *.pch
13 |
14 | # Compiled Dynamic libraries
15 | *.so
16 | *.dylib
17 | *.dll
18 |
19 | # Fortran module files
20 | *.mod
21 | *.smod
22 |
23 | # Compiled Static libraries
24 | *.lai
25 | *.la
26 | *.a
27 | *.lib
28 |
29 | # Executables
30 | *.exe
31 | *.out
32 | *.app
33 |
--------------------------------------------------------------------------------
/Keyboard/NumberKeyboard.h:
--------------------------------------------------------------------------------
1 | /**********************************************************
2 | #Author: Qtjun
3 | #WeChat Official Accounts: qthub_com
4 | #QQ Group: 732271126
5 | #Email: 2088201923@qq.com
6 | **********************************************************/
7 |
8 | #ifndef NUMBERKEYBOARD_H
9 | #define NUMBERKEYBOARD_H
10 |
11 | #include "AbstractKeyboard.h"
12 | #include "KeyButton.h"
13 | #include
14 | #include
15 |
16 | namespace AeaQt {
17 |
18 | class NumberKeyboard : public AbstractKeyboard
19 | {
20 | Q_OBJECT
21 | public:
22 | NumberKeyboard(QWidget *parent = NULL);
23 |
24 | KeyButton *createButton(QList modes);
25 |
26 | private slots:
27 | void onButtonPressed(const int &code, const QString &text);
28 | };
29 |
30 | }
31 |
32 | #endif // NUMBERKEYBOARD_H
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 aeagean
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/QtKeyboard.pro:
--------------------------------------------------------------------------------
1 | #**********************************************************
2 | #Author: Qtjun
3 | #Qt君公众号
4 | #官网:www.qthub.com
5 | #QQ群: 732271126
6 | #Email: 2088201923@qq.com
7 | #**********************************************************
8 | QT += core gui
9 |
10 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
11 |
12 | TARGET = QtKeyboard
13 | TEMPLATE = app
14 | QMAKE_CXXFLAGS += -std=c++0x
15 |
16 | CONFIG += c++11
17 |
18 | win32: RC_ICONS += app.ico
19 |
20 | INCLUDEPATH = Keyboard
21 |
22 | SOURCES += main.cpp \
23 | Keyboard/KeyButton.cpp \
24 | Keyboard/Keyboard.cpp \
25 | Keyboard/NumberKeyboard.cpp
26 |
27 | HEADERS += \
28 | Keyboard/AbstractKeyboard.h \
29 | Keyboard/KeyButton.h \
30 | Keyboard/Keyboard.h \
31 | Keyboard/NumberKeyboard.h
32 |
33 | RESOURCES += Resources/Image.qrc
34 |
35 | # 可启用下列宏
36 | # 启用汉字库
37 | # ENABLED_CHINESE_LIB
38 |
39 | # 启用词组汉字库
40 | # ENABLED_CHINESE_PHRASE_LIB
41 |
42 | # 启用谷歌汉字库(推荐使用)
43 | # ENABLED_GOOGLE_CHINESE_LIB
44 |
45 | # 启用文泉驿字体库
46 | # ENABLED_WQY_FONT
47 |
48 | DEFINES += ENABLED_GOOGLE_CHINESE_LIB
49 |
50 | contains(DEFINES, ENABLED_CHINESE_LIB) {
51 | RESOURCES += Resources/ChineseLib.qrc
52 | }
53 |
54 | contains(DEFINES, ENABLED_CHINESE_PHRASE_LIB) {
55 | RESOURCES += Resources/ChinesePhraseLib.qrc
56 | }
57 |
58 | contains(DEFINES, ENABLED_GOOGLE_CHINESE_LIB) {
59 | RESOURCES += Resources/GoogleChineseLib.qrc
60 | }
61 |
62 | contains(DEFINES, ENABLED_WQY_FONT) {
63 | RESOURCES += Resources/Font.qrc
64 | }
65 |
--------------------------------------------------------------------------------
/Keyboard/AbstractKeyboard.h:
--------------------------------------------------------------------------------
1 | /**********************************************************
2 | #Author: Qtjun
3 | #WeChat Official Accounts: qthub_com
4 | #QQ Group: 732271126
5 | #Email: 2088201923@qq.com
6 | **********************************************************/
7 |
8 | #ifndef AEA_ABSTRACT_KEYBOARD_H
9 | #define AEA_ABSTRACT_KEYBOARD_H
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | namespace AeaQt {
17 |
18 | class AbstractKeyboard : public QWidget
19 | {
20 | Q_OBJECT
21 | public:
22 | AbstractKeyboard(QWidget *parent = 0) : QWidget(parent) {
23 |
24 | }
25 | ~AbstractKeyboard() { }
26 |
27 | const QString name() { return m_name; }
28 | void setName(const QString &name) { m_name = name; }
29 |
30 | public slots:
31 | virtual void update(const QString &text) { Q_UNUSED(text); }
32 |
33 | void onKeyPressed(int key, QString value)
34 | {
35 | qDebug() << "key: " << key << "Value: " << value;
36 | QWidget *receiver = QApplication::focusWidget();
37 | if (!receiver)
38 | return;
39 |
40 | QKeyEvent keyPress(QEvent::KeyPress, key, Qt::NoModifier, value);
41 | QKeyEvent keyRelease(QEvent::KeyRelease, key, Qt::NoModifier, value);
42 |
43 | QApplication::sendEvent(receiver, &keyPress);
44 | QApplication::sendEvent(receiver, &keyRelease);
45 | }
46 |
47 | signals:
48 | void keyPressed(int key, QString value);
49 |
50 | private:
51 | QString m_name;
52 | };
53 |
54 | }
55 | #endif // AEA_ABSTRACT_KEYBOARD_H
56 |
--------------------------------------------------------------------------------
/Keyboard/KeyButton.h:
--------------------------------------------------------------------------------
1 | /**********************************************************
2 | #Author: Qtjun
3 | #WeChat Official Accounts: qthub_com
4 | #QQ Group: 732271126
5 | #Email: 2088201923@qq.com
6 | **********************************************************/
7 |
8 | #ifndef AEA_KEY_BUTTON_H
9 | #define AEA_KEY_BUTTON_H
10 |
11 | #include
12 | #include
13 |
14 | namespace AeaQt {
15 |
16 | class KeyButton : public QPushButton
17 | {
18 | Q_OBJECT
19 | public:
20 | enum Type { Auto = 0, LowerCase, UpperCase, SpecialChar };
21 |
22 | struct Mode {
23 | Mode() { }
24 | Mode(int _key, QString _value, QVariant _display = QString(), Type _type = Auto)
25 | {
26 | key = _key;
27 | value = _value;
28 | display = _display;
29 | type = _type;
30 | }
31 |
32 | int key; /* Qt::Key */
33 | QString value; /* text */
34 | QVariant display; /* display text or icon */
35 | Type type; /* default: Auto */
36 | };
37 |
38 | KeyButton(const QList modes = QList(), QWidget *parent = NULL);
39 | Mode mode();
40 |
41 | void onReponse(const QObject* receiverObj, const QString &receiver);
42 |
43 | void switchCapsLock();
44 | void switchSpecialChar();
45 | void switching(); /* Cycle switch. */
46 |
47 | signals:
48 | void pressed(int key, QString value);
49 |
50 | private slots:
51 | void onPressed();
52 |
53 | private:
54 | Type find(const QString &value);
55 | Mode find(Type type);
56 | Mode findNext();
57 | void setDisplayContent(const QVariant &content);
58 |
59 | private:
60 | Mode m_preMode;
61 | Mode m_mode;
62 | QList m_modes;
63 | };
64 |
65 | }
66 | #endif // AEA_KEY_BUTTON_H
67 |
--------------------------------------------------------------------------------
/Keyboard/Keyboard.h:
--------------------------------------------------------------------------------
1 | /**********************************************************
2 | #Author: Qtjun
3 | #WeChat Official Accounts: qthub_com
4 | #QQ Group: 732271126
5 | #Email: 2088201923@qq.com
6 | **********************************************************/
7 |
8 | #ifndef AEA_KEYBOARD_H
9 | #define AEA_KEYBOARD_H
10 |
11 | #include "AbstractKeyboard.h"
12 | #include "KeyButton.h"
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | namespace AeaQt {
20 |
21 | class ChineseWidget : public QListWidget {
22 | Q_OBJECT
23 | public:
24 | ChineseWidget(QWidget *parent = NULL);
25 | void setText(const QString &text);
26 |
27 | signals:
28 | void pressedChanged(const int &code, const QString &text);
29 |
30 | private slots:
31 | void onItemClicked(QListWidgetItem *item);
32 |
33 | private:
34 | void addOneItem(const QString &text);
35 | void loadChineseLib();
36 | void loadChinesePhraseLib();
37 | void loadGoogleChineseLib();
38 |
39 | private:
40 | QMap > > m_data;
41 | };
42 |
43 | class Keyboard : public AbstractKeyboard
44 | {
45 | Q_OBJECT
46 | public:
47 | Keyboard(QWidget *parent = NULL);
48 |
49 | protected:
50 | void resizeEvent(QResizeEvent *e);
51 |
52 | private slots:
53 | void switchCapsLock();
54 | void switchSpecialChar();
55 | void switchEnOrCh();
56 | void onButtonPressed(const int &code, const QString &text);
57 | void clearBufferText();
58 |
59 | private:
60 | KeyButton *createButton(QList modes);
61 |
62 | QWidget *createBar(const QList > &modes);
63 | QWidget *chineseBar();
64 | QHBoxLayout *h1();
65 | QHBoxLayout *h2();
66 | QHBoxLayout *h3();
67 | QHBoxLayout *h4();
68 | QWidget *candidateList();
69 |
70 | void resizeButton();
71 |
72 |
73 | private:
74 | bool m_isChinese;
75 | ChineseWidget *m_chineseWidget;
76 | QString m_bufferText;
77 | };
78 |
79 | }
80 | #endif // AEA_KEYBOARD_H
81 |
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
1 | /**********************************************************
2 | Author: Qt君
3 | 微信公众号: Qt君(首发)
4 | QQ群: 732271126
5 | Email: 2088201923@qq.com
6 | **********************************************************/
7 | #include "Keyboard.h"
8 | #include "NumberKeyboard.h"
9 |
10 | #include
11 | #include
12 | #include
13 |
14 | using namespace AeaQt;
15 |
16 | static const QString qss = " \
17 | QLineEdit { \
18 | border-style: none; \
19 | padding: 3px; \
20 | border-radius: 5px; \
21 | border: 1px solid #dce5ec; \
22 | font-size: 30px; \
23 | } \
24 | ";
25 |
26 | int main(int argc, char *argv[])
27 | {
28 | QApplication a(argc, argv);
29 |
30 | #ifdef ENABLED_WQY_FONT
31 | int fontId = QFontDatabase::addApplicationFont(":/Font/wqy-microhei.ttc");
32 | QStringList stringList = QFontDatabase::applicationFontFamilies(fontId);
33 | QFont font(stringList.first());
34 | a.setFont(font);
35 | #endif
36 |
37 | QWidget window;
38 |
39 | window.setWindowTitle(QStringLiteral("QtKeyboard by Qt君"));
40 | window.resize(850, 370);
41 |
42 | Keyboard keyboard;
43 | keyboard.show();
44 |
45 | QLineEdit textInput(&keyboard);
46 | textInput.setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
47 | textInput.setStyleSheet(qss);
48 |
49 | QVBoxLayout *v = new QVBoxLayout;
50 | v->addWidget(&textInput, 1);
51 | v->addWidget(&keyboard, 5);
52 |
53 | window.setLayout(v);
54 | window.show();
55 |
56 | ///////////////////////////////
57 | QWidget window2;
58 | window2.setWindowTitle(QStringLiteral("数字键盘 by Qt君"));
59 | window2.resize(450, 370);
60 |
61 | NumberKeyboard keyboard2;
62 | keyboard2.show();
63 |
64 | QLineEdit textInput2(&keyboard2);
65 | textInput2.setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
66 | textInput2.setStyleSheet(qss);
67 |
68 | QVBoxLayout *v2 = new QVBoxLayout;
69 | v2->addWidget(&textInput2, 1);
70 | v2->addWidget(&keyboard2, 5);
71 |
72 | window2.setLayout(v2);
73 | window2.show();
74 |
75 | return a.exec();
76 | }
77 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > 本文介绍Qt君最近编写的一个Qt键盘,该键盘主要功能有大小写切换,中英文切换,实现数字输入,符号输入等基本功能,未来还会支持换肤,手写功能。
2 |
3 | 
4 |
5 | # 实现初衷
6 | * 供大家交流学习;
7 | * 希望以轻量级(嵌入式设备)键盘为特点不断**发展**该键盘项目(**源码地址**在文末)。
8 | 
9 |
10 | # 项目预览
11 | * 文件**目录**
12 | 
13 |
14 | * 基类键盘**AbstractKeyboard**
15 | ```cpp
16 | class AbstractKeyboard : public QWidget
17 | {
18 | Q_OBJECT
19 | public:
20 | AbstractKeyboard(QWidget *parent = 0);
21 | ~AbstractKeyboard();
22 |
23 | const QString name();
24 | void setName(const QString &name);
25 |
26 | public slots:
27 | virtual void update(const QString &text);
28 | void onKeyPressed(int key, QString value);
29 |
30 | signals:
31 | void keyPressed(int key, QString value);
32 | };
33 | ```
34 |
35 | * 实现类键盘**Keyboard**
36 | ```cpp
37 | class Keyboard : public AbstractKeyboard
38 | {
39 | Q_OBJECT
40 | public:
41 | Keyboard(QWidget *parent = NULL);
42 |
43 | protected:
44 | void resizeEvent(QResizeEvent *e);
45 |
46 | private slots:
47 | void switchCapsLock();
48 | void switchSpecialChar();
49 | void switchEnOrCh();
50 | };
51 | ```
52 |
53 | * 键盘按钮**KeyButton**
54 | ```cpp
55 | class KeyButton : public QPushButton
56 | {
57 | Q_OBJECT
58 | public:
59 | enum Type { Auto = 0, LowerCase, UpperCase, SpecialChar };
60 |
61 | struct Mode {
62 | int key; /* Qt::Key */
63 | QString value; /* text */
64 | QString display; /* display text */
65 | Type type; /* default: Auto */
66 | };
67 |
68 | KeyButton(const QList modes = QList(), QWidget *parent = NULL);
69 | Mode mode();
70 |
71 | void onReponse(const QObject* receiverObj, const QString &receiver);
72 |
73 | void switchCapsLock();
74 | void switchSpecialChar();
75 | void switching(); /* Cycle switch. */
76 |
77 | signals:
78 | void pressed(int key, QString value);
79 | };
80 | ```
81 |
82 | # 文章更新
83 | * 轻量级Qt键盘-介绍篇
84 | * 轻量级Qt键盘-原理篇
85 | * 轻量级Qt键盘-实现篇
86 | * 轻量级Qt键盘-中文输入
87 | * 后续会不定期更新关于主要新增功能介绍文章。
88 |
89 | # 关于更多
90 | * **源码地址**:
91 | ```
92 | https://github.com/aeagean/QtKeyboard
93 | ```
94 |
95 | * 本文首发公众号:**Qt君**
96 |
97 |
98 |
Qt君
99 |
100 |
--------------------------------------------------------------------------------
/Keyboard/NumberKeyboard.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | #Author: Qtjun
3 | #WeChat Official Accounts: qthub_com
4 | #QQ Group: 732271126
5 | #Email: 2088201923@qq.com
6 | */
7 |
8 | #include "NumberKeyboard.h"
9 | #include "KeyButton.h"
10 | #include
11 |
12 | using namespace AeaQt;
13 |
14 | typedef QList Modes;
15 | typedef QList ModesList;
16 |
17 | static const QString s_backspace_icon = ":/Image/backspace.png";
18 | static const QString s_space_icon = ":/Image/space.png";
19 | static const QString s_pack_up_icon = ":/Image/pack_up.png";
20 |
21 | NumberKeyboard::NumberKeyboard(QWidget *parent) : AbstractKeyboard(parent)
22 | {
23 | QVBoxLayout *layout = new QVBoxLayout(this);
24 | layout->setSizeConstraint(QLayout::SetNoConstraint);
25 | layout->setSpacing(0);
26 | layout->setMargin(0);
27 |
28 |
29 | auto createLayout = [&](ModesList list){
30 | QHBoxLayout *h = new QHBoxLayout;
31 | h->setSizeConstraint(QLayout::SetNoConstraint);
32 |
33 | foreach (Modes iter, list) {
34 | KeyButton *button = createButton(iter);
35 | h->addWidget(button);
36 | }
37 |
38 | layout->addLayout(h);
39 | };
40 |
41 | const QList modeListBar1 = {
42 | {{Qt::Key_1, "1"}},
43 | {{Qt::Key_2, "2"}},
44 | {{Qt::Key_3, "3"}},
45 | {{Qt::Key_Backspace, "", QIcon(s_backspace_icon)}},
46 | };
47 |
48 | const QList modeListBar2 = {
49 | {{Qt::Key_4, "4"}},
50 | {{Qt::Key_5, "5"}},
51 | {{Qt::Key_6, "6"}},
52 | {{Qt::Key_Escape, "", QIcon(s_pack_up_icon)}},
53 | };
54 |
55 | const QList modeListBar3 = {
56 | {{Qt::Key_7, "7"}},
57 | {{Qt::Key_8, "8"}},
58 | {{Qt::Key_9, "9"}},
59 | {{Qt::Key_Minus, ","}},
60 | };
61 |
62 | const QList modeListBar4 = {
63 | {{Qt::Key_unknown, "."}},
64 | {{Qt::Key_0, "0"}},
65 | {{Qt::Key_Space, " ", QIcon(s_space_icon)}},
66 | {{Qt::Key_unknown, ":"}},
67 | };
68 |
69 | createLayout(modeListBar1);
70 | createLayout(modeListBar2);
71 | createLayout(modeListBar3);
72 | createLayout(modeListBar4);
73 |
74 | this->setLayout(layout);
75 | }
76 |
77 | KeyButton *NumberKeyboard::createButton(QList modes)
78 | {
79 | KeyButton *button = new KeyButton(modes, this);
80 | button->onReponse(this, SLOT(onButtonPressed(const int&, const QString&)));
81 | button->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
82 | return button;
83 | }
84 |
85 | void NumberKeyboard::onButtonPressed(const int &code, const QString &text)
86 | {
87 | onKeyPressed(code, text);
88 | }
89 |
--------------------------------------------------------------------------------
/Keyboard/KeyButton.cpp:
--------------------------------------------------------------------------------
1 | /**********************************************************
2 | #Author: Qtjun
3 | #WeChat Official Accounts: qthub_com
4 | #QQ Group: 732271126
5 | #Email: 2088201923@qq.com
6 | **********************************************************/
7 |
8 | #include "KeyButton.h"
9 | #include
10 |
11 | using namespace AeaQt;
12 |
13 | const QString DEFAULT_STYLE_SHEET = "AeaQt--KeyButton { background: #4395ff; border-radius: 5px;" \
14 | "margin: 5px;" \
15 | "font-size: 26px; color: white;}" \
16 | "AeaQt--KeyButton:pressed { background: #01ddfd }";
17 |
18 | KeyButton::Type KeyButton::find(const QString &value)
19 | {
20 | QRegExp rx("[a-z]");
21 | if (rx.exactMatch(value))
22 | return KeyButton::LowerCase;
23 |
24 | rx = QRegExp("[A-Z]");
25 | if (rx.exactMatch(value))
26 | return KeyButton::UpperCase;
27 |
28 | return KeyButton::SpecialChar;
29 | }
30 |
31 | KeyButton::Mode KeyButton::find(KeyButton::Type type)
32 | {
33 | foreach (KeyButton::Mode mode, m_modes) {
34 | if (mode.type == type)
35 | return mode;
36 | }
37 |
38 | return m_modes.first();
39 | }
40 |
41 | KeyButton::Mode KeyButton::findNext()
42 | {
43 | for(int i = 0; i < m_modes.count(); i++) {
44 | KeyButton::Mode mode = m_modes[i];
45 | if (mode.display == m_mode.display) {
46 | if (i+1 < m_modes.count())
47 | return m_modes.at(i+1);
48 | else
49 | return m_modes.first();
50 | }
51 | }
52 |
53 | return m_modes.first();
54 | }
55 |
56 | void KeyButton::setDisplayContent(const QVariant &content)
57 | {
58 | if (content.type() == QVariant::String) {
59 | const QString &text = content.toString().toStdString().data();
60 | this->setText(text);
61 | }
62 | else if (content.type() == QVariant::Icon) {
63 | const QIcon &icon = content.value();
64 | this->setIcon(icon);
65 | this->setIconSize(QSize(1.2 * width(), 1.2 * height()));
66 | }
67 | }
68 |
69 | KeyButton::KeyButton(const QList modes, QWidget *parent) :
70 | QPushButton(parent)
71 | {
72 | Q_ASSERT(!modes.isEmpty());
73 | this->setFocusPolicy(Qt::NoFocus);
74 | this->setStyleSheet(DEFAULT_STYLE_SHEET);
75 | this->setAutoRepeat(true);
76 |
77 | foreach (Mode mode, modes) {
78 | if (mode.type == Auto) {
79 | mode.type = find(mode.value);
80 | }
81 |
82 | if (mode.display.isNull())
83 | mode.display = mode.value;
84 |
85 | m_modes.append(mode);
86 | }
87 |
88 | if (!modes.isEmpty()) {
89 | m_preMode = m_mode = m_modes.first();
90 | setDisplayContent(m_mode.display);
91 | }
92 |
93 | connect(this, SIGNAL(pressed()), this, SLOT(onPressed()));
94 | }
95 |
96 | KeyButton::Mode KeyButton::mode()
97 | {
98 | return m_mode;
99 | }
100 |
101 | void KeyButton::onReponse(const QObject *receiverObj, const QString &receiver) {
102 | connect(this, SIGNAL(pressed(int,QString)), receiverObj, receiver.toStdString().c_str());
103 | }
104 |
105 | void KeyButton::switchCapsLock()
106 | {
107 | if (m_mode.type == SpecialChar)
108 | return;
109 |
110 | m_preMode = m_mode;
111 | m_mode = find(m_mode.type == LowerCase ? UpperCase : LowerCase);
112 | setDisplayContent(m_mode.display);
113 | }
114 |
115 | void KeyButton::switchSpecialChar()
116 | {
117 | if (m_mode.type == SpecialChar) {
118 | m_mode = m_preMode;
119 | }
120 | else {
121 | m_preMode = m_mode;
122 | m_mode = find(SpecialChar);
123 | }
124 |
125 | setDisplayContent(m_mode.display);
126 | }
127 |
128 | void KeyButton::switching()
129 | {
130 | m_mode = findNext();
131 | setDisplayContent(m_mode.display);
132 | }
133 |
134 | void KeyButton::onPressed()
135 | {
136 | emit pressed(m_mode.key, m_mode.value);
137 | }
138 |
--------------------------------------------------------------------------------
/Resources/GoogleChineseLib/sort.h:
--------------------------------------------------------------------------------
1 | static void mySort()
2 | {
3 | QList > processingList;
4 | processingList << QMap();
5 | processingList << QMap();
6 | processingList << QMap();
7 | processingList << QMap();
8 |
9 | QFile file(":/GoogleChineseLib/rawdict_utf16_65105_freq.txt");
10 | if (! file.open(QIODevice::ReadOnly)) {
11 | qDebug() << "Open pinyin file failed!" << file.fileName();
12 | return;
13 | }
14 |
15 | QTextStream in(&file);
16 | in.setCodec("UTF-16"); // change the file codec to UTF-16.
17 |
18 | QStringList lines = in.readAll().split("\n");
19 |
20 | for (QString each : lines) {
21 | QRegExp re(R"RX((\S+).((?:-?\d+)(?:\.\d+)).((?:-?\d+)(?:\.\d+)?).(.*))RX");
22 | int pos = 0;
23 |
24 | bool isMatching = false;
25 | while ((pos = re.indexIn(each, pos)) != -1) {
26 | pos += re.matchedLength();
27 | if (re.captureCount() != 4)
28 | continue;
29 |
30 | isMatching = true;
31 | QString hanzi = re.cap(1); // 汉字
32 | QString weight = re.cap(2); // 权重
33 | QString tmp = re.cap(3); // 未知
34 | QString pinyin = re.cap(4); // 拼音(可能是词组)
35 |
36 | bool ok = false;
37 | double weightF = weight.toDouble(&ok);
38 | if (!ok) {
39 | qDebug() << each << "weight convert failed!";
40 | }
41 |
42 | QStringList pinyins = pinyin.split(" "); // 分隔词组
43 | QString abb;
44 | for (int i = 0; i < pinyins.count(); i++) {
45 | /* 获得拼音词组的首字母(用于缩写匹配) */
46 | abb += pinyins.at(i).left(1);
47 | }
48 |
49 | if (pinyins.count() >= 1 && pinyins.count() <= 4) {
50 | QMap &needProcessingMap = processingList[pinyins.count() - 1];
51 |
52 | // 如果不存在则创建一个空的索引
53 | if (!needProcessingMap.contains(abb)) {
54 | needProcessingMap[abb] = QStringList();
55 | }
56 |
57 | // 存放每一行字符串
58 | QStringList &tmp = needProcessingMap[abb];
59 | tmp.append(each);
60 | }
61 | else {
62 | qDebug() << "error in " << __LINE__ << "pinyins is empty.";
63 | }
64 |
65 | }
66 |
67 | if (!isMatching)
68 | qDebug() << each;
69 | }
70 |
71 | auto stringToDouble = [](QString string) -> double {
72 | QRegExp re(R"RX((\S+).((?:-?\d+)(?:\.\d+)).((?:-?\d+)(?:\.\d+)?).(.*))RX");
73 | int pos = 0;
74 |
75 | bool isMatching = false;
76 | while ((pos = re.indexIn(string, pos)) != -1) {
77 | pos += re.matchedLength();
78 | if (re.captureCount() != 4)
79 | continue;
80 |
81 | isMatching = true;
82 | QString hanzi = re.cap(1); // 汉字
83 | QString weight = re.cap(2); // 权重
84 | QString tmp = re.cap(3); // 未知
85 | QString pinyin = re.cap(4); // 拼音(可能是词组)
86 |
87 | bool ok = false;
88 | double weightF = weight.toDouble(&ok);
89 | if (!ok) {
90 | qDebug() << string << "weight convert failed!";
91 | return 0;
92 | }
93 |
94 | return weightF;
95 |
96 | }
97 |
98 | return 0;
99 | };
100 |
101 | const int checkCount = 65105;
102 | int count = 0;
103 | QFile outputFile("rawdict_utf16_65105_freq_sort.txt");
104 | if (!outputFile.open(QIODevice::WriteOnly)) {
105 | qDebug() << outputFile.fileName() << "open failed!";
106 | return;
107 | }
108 |
109 | QTextStream out(&outputFile);
110 | out.setGenerateByteOrderMark(true);
111 | out.setCodec("UTF-16");
112 | QString outString;
113 |
114 | for (auto needProcessingMap: processingList) {
115 | for (QStringList &iter : needProcessingMap) {
116 | count += iter.count();
117 | std::sort(iter.begin(), iter.end(), [&](QString l, QString r){
118 | return stringToDouble(l) > stringToDouble(r);
119 | });
120 |
121 | QString string = iter.join("\n");
122 | outString += string + "\n";
123 | }
124 | }
125 |
126 | out << outString;
127 |
128 | Q_ASSERT(count == checkCount);
129 | qDebug() << "count: " << count;
130 |
131 | file.close();
132 |
133 | return;
134 | }
--------------------------------------------------------------------------------
/Keyboard/Keyboard.cpp:
--------------------------------------------------------------------------------
1 | /**********************************************************
2 | #Author: Qtjun
3 | #WeChat Official Accounts: qthub_com
4 | #QQ Group: 732271126
5 | #Email: 2088201923@qq.com
6 | **********************************************************/
7 |
8 | #include "Keyboard.h"
9 | #include "KeyButton.h"
10 | #include
11 | #include
12 |
13 | #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
14 | #include
15 | #endif
16 |
17 | #include
18 | #include
19 |
20 | using namespace AeaQt;
21 |
22 | typedef QList Modes;
23 | typedef QList ModesList;
24 |
25 | const int NORMAL_BUTTON_WIDTH = 55;
26 | const int NORMAL_BUTTON_HEIGHT = 45;
27 |
28 | const QString BACKSPACE_ICON = ":/Image/backspace.png";
29 | const QString ENTER_ICON = ":/Image/enter.png";
30 | const QString SPACE_ICON = ":/Image/space.png";
31 | const QString CAPLOCK_ICON = ":/Image/caplock.png";
32 |
33 | const double BUTTON_SPACING_RATIO = 0.030;
34 | const double BUTTON_WIDTH_RATIO = 0.09;
35 | const double BUTTON_HEIGHT_RATIO = 0.2;
36 |
37 | const QList modeListBar1 = {
38 | {{Qt::Key_Q, "q"}, {Qt::Key_Q, "Q"}, {Qt::Key_1, "1"}},
39 | {{Qt::Key_W, "w"}, {Qt::Key_W, "W"}, {Qt::Key_2, "2"}},
40 | {{Qt::Key_E, "e"}, {Qt::Key_E, "E"}, {Qt::Key_3, "3"}},
41 | {{Qt::Key_R, "r"}, {Qt::Key_R, "R"}, {Qt::Key_4, "4"}},
42 | {{Qt::Key_T, "t"}, {Qt::Key_T, "T"}, {Qt::Key_5, "5"}},
43 | {{Qt::Key_Y, "y"}, {Qt::Key_Y, "Y"}, {Qt::Key_6, "6"}},
44 | {{Qt::Key_U, "u"}, {Qt::Key_U, "U"}, {Qt::Key_7, "7"}},
45 | {{Qt::Key_I, "i"}, {Qt::Key_I, "I"}, {Qt::Key_8, "8"}},
46 | {{Qt::Key_O, "o"}, {Qt::Key_O, "O"}, {Qt::Key_9, "9"}},
47 | {{Qt::Key_P, "p"}, {Qt::Key_P, "P"}, {Qt::Key_0, "0"}},
48 | };
49 |
50 | const QList modeListBar2 = {
51 | {{Qt::Key_A, "a"}, {Qt::Key_A, "A"}, {Qt::Key_unknown, "."}},
52 | {{Qt::Key_S, "s"}, {Qt::Key_S, "S"}, {Qt::Key_unknown, "?"}},
53 | {{Qt::Key_D, "d"}, {Qt::Key_D, "D"}, {Qt::Key_At, "!"}},
54 | {{Qt::Key_F, "f"}, {Qt::Key_F, "F"}, {Qt::Key_NumberSign, "*"}},
55 | {{Qt::Key_G, "g"}, {Qt::Key_G, "G"}, {Qt::Key_Percent, "#"}},
56 | {{Qt::Key_H, "h"}, {Qt::Key_H, "H"}, {Qt::Key_unknown, "\""}},
57 | {{Qt::Key_J, "j"}, {Qt::Key_J, "J"}, {Qt::Key_unknown, "&", "&&"}},
58 | {{Qt::Key_K, "k"}, {Qt::Key_K, "K"}, {Qt::Key_unknown, "%"}},
59 | {{Qt::Key_L, "l"}, {Qt::Key_L, "L"}, {Qt::Key_unknown, "@"}},
60 | };
61 |
62 | const QList modeListBar3 = {
63 | {{Qt::Key_CapsLock, "", ""/*大小写切换*/}},
64 | {{Qt::Key_Z, "z"}, {Qt::Key_Z, "Z"}, {Qt::Key_ParenLeft, "("}},
65 | {{Qt::Key_X, "x"}, {Qt::Key_X, "X"}, {Qt::Key_ParenLeft, ")"}},
66 | {{Qt::Key_C, "c"}, {Qt::Key_C, "C"}, {Qt::Key_Minus, "-"}},
67 | {{Qt::Key_V, "v"}, {Qt::Key_V, "V"}, {Qt::Key_unknown, "_"}},
68 | {{Qt::Key_B, "b"}, {Qt::Key_B, "B"}, {Qt::Key_unknown, ":"}},
69 | {{Qt::Key_N, "n"}, {Qt::Key_N, "N"}, {Qt::Key_Semicolon, ";"}},
70 | {{Qt::Key_M, "m"}, {Qt::Key_M, "M"}, {Qt::Key_Slash, "/"}},
71 | {{Qt::Key_Backspace, "", ""/*退格*/}}
72 | };
73 |
74 | const QList modeListBar4 = {
75 | {{Qt::Key_Mode_switch, "", "?123"}},
76 | {{Qt::Key_Context1, "", "En"}, {Qt::Key_Context1, "", QStringLiteral("中")}},
77 | {{Qt::Key_Space, " ", ""/*空格*/}},
78 | {{Qt::Key_Enter, "", ""/*换行*/}}
79 | };
80 |
81 | Keyboard::Keyboard(QWidget *parent) :
82 | AbstractKeyboard(parent),
83 | m_isChinese(false)
84 | {
85 | m_chineseWidget = new ChineseWidget(this);
86 | setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
87 | resize(850, 320);
88 | resizeButton();
89 |
90 | QVBoxLayout *layout = new QVBoxLayout(this);
91 | layout->setSizeConstraint(QLayout::SetNoConstraint);
92 | layout->setSpacing(0);
93 | layout->setMargin(0);
94 |
95 | layout->addWidget(chineseBar(), 12);
96 | layout->addLayout(h1(), 15);
97 | layout->addLayout(h2(), 15);
98 | layout->addLayout(h3(), 15);
99 | layout->addLayout(h4(), 15);
100 |
101 | setLayout(layout);
102 |
103 | connect(m_chineseWidget, SIGNAL(pressedChanged(const int &, const QString &)),
104 | this, SLOT(onKeyPressed(const int &, const QString &)));
105 |
106 | connect(m_chineseWidget, SIGNAL(pressedChanged(const int &, const QString &)), this, SLOT(clearBufferText()));
107 | }
108 |
109 | void Keyboard::resizeEvent(QResizeEvent *e)
110 | {
111 | resizeButton();
112 | }
113 |
114 | void Keyboard::switchCapsLock()
115 | {
116 | QList buttons = findChildren();
117 | foreach(KeyButton *button, buttons)
118 | button->switchCapsLock();
119 | }
120 |
121 | void Keyboard::switchSpecialChar()
122 | {
123 | QList buttons = findChildren();
124 | foreach(KeyButton *button, buttons)
125 | button->switchSpecialChar();
126 | }
127 |
128 | void Keyboard::switchEnOrCh()
129 | {
130 | m_isChinese = !m_isChinese;
131 | QList buttons = findChildren();
132 | foreach(KeyButton *button, buttons) {
133 | if (button->mode().key == Qt::Key_Context1) {
134 | button->switching();
135 | }
136 | }
137 | }
138 |
139 | void Keyboard::onButtonPressed(const int &code, const QString &text)
140 | {
141 |
142 | if (! m_isChinese) {
143 | onKeyPressed(code, text);
144 | m_bufferText.clear();
145 | return;
146 | }
147 |
148 | QRegExp rx("[a-zA-Z]");
149 | if (!rx.exactMatch(text) && m_bufferText.isEmpty()) {
150 | onKeyPressed(code, text);
151 | return;
152 | }
153 |
154 | if (code == Qt::Key_Backspace)
155 | m_bufferText.chop(1);
156 | else
157 | m_bufferText.append(text);
158 | m_chineseWidget->setText(m_bufferText);
159 | }
160 |
161 | void Keyboard::clearBufferText()
162 | {
163 | m_bufferText.clear();
164 | }
165 |
166 | KeyButton *Keyboard::createButton(QList modes)
167 | {
168 | KeyButton *button = new KeyButton(modes, this);
169 | button->onReponse(this, SLOT(onButtonPressed(const int&, const QString&)));
170 | button->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
171 | return button;
172 | }
173 |
174 | QWidget *Keyboard::createBar(const QList > &modes)
175 | {
176 | QWidget *widget = new QWidget;
177 |
178 | QHBoxLayout *h = new QHBoxLayout;
179 | for (int i = 0; i < modes.count(); i++) {
180 | KeyButton *button = createButton(modes.at(i));
181 | h->addWidget(button);
182 | }
183 |
184 | widget->setLayout(h);
185 | return widget;
186 | }
187 |
188 | QWidget *Keyboard::chineseBar()
189 | {
190 | m_chineseWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
191 | return m_chineseWidget;
192 | }
193 |
194 | QHBoxLayout *Keyboard::h1()
195 | {
196 | QHBoxLayout *h = new QHBoxLayout;
197 | h->setSizeConstraint(QLayout::SetNoConstraint);
198 | for (int i = 0; i < modeListBar1.count(); i++) {
199 | KeyButton *button = createButton(modeListBar1.at(i));
200 | h->addWidget(button);
201 | }
202 |
203 | return h;
204 | }
205 |
206 | QHBoxLayout *Keyboard::h2()
207 | {
208 | QHBoxLayout *h = new QHBoxLayout;
209 | h->addSpacing(20);
210 | for (int i = 0; i < modeListBar2.count(); i++) {
211 | KeyButton *button = createButton(modeListBar2.at(i));
212 | h->addWidget(button);
213 | }
214 | h->addSpacing(20);
215 |
216 | return h;
217 | }
218 |
219 | QHBoxLayout *Keyboard::h3()
220 | {
221 | QHBoxLayout *h = new QHBoxLayout;
222 | h->setSpacing(0);
223 | for (int i = 0; i < modeListBar3.count(); i++) {
224 | KeyButton *button = createButton(modeListBar3.at(i));
225 | if (i == 0 || i == (modeListBar3.count() - 1))
226 | h->addWidget(button, 70);
227 | else
228 | h->addWidget(button, 69);
229 | }
230 |
231 | return h;
232 | }
233 |
234 | QHBoxLayout *Keyboard::h4()
235 | {
236 | QHBoxLayout *h = new QHBoxLayout;
237 | h->setSpacing(0);
238 | for (int i = 0; i < modeListBar4.count(); i++) {
239 | KeyButton *button = createButton(modeListBar4.at(i));
240 | if (i == 0)
241 | h->addWidget(button, 12);
242 |
243 | if (i == 1)
244 | h->addWidget(button, 10);
245 |
246 | if (i == 2)
247 | h->addWidget(button, 56);
248 |
249 | if (i == 3)
250 | h->addWidget(button, 22);
251 | }
252 |
253 | return h;
254 | }
255 |
256 | QWidget *Keyboard::candidateList()
257 | {
258 | return m_chineseWidget;
259 | }
260 |
261 | void Keyboard::resizeButton()
262 | {
263 | foreach (KeyButton *button, findChildren()) {
264 | int fixedWidth = width()*BUTTON_WIDTH_RATIO;
265 | int fixedHeight = height()*BUTTON_HEIGHT_RATIO;
266 | button->setIconSize(QSize(2*fixedWidth/3, 2*fixedHeight/3));
267 |
268 | switch (button->mode().key) {
269 | case Qt::Key_Backspace:
270 | button->setIcon(QIcon(BACKSPACE_ICON));
271 | break;
272 | case Qt::Key_CapsLock:
273 | button->setIcon(QIcon(CAPLOCK_ICON));
274 | connect(button, SIGNAL(pressed()), this, SLOT(switchCapsLock()), Qt::UniqueConnection);
275 | break;
276 | case Qt::Key_Mode_switch:
277 | connect(button, SIGNAL(pressed()), this, SLOT(switchSpecialChar()), Qt::UniqueConnection);
278 | break;
279 | case Qt::Key_Context1:
280 | connect(button, SIGNAL(pressed()), this, SLOT(switchEnOrCh()), Qt::UniqueConnection);
281 | break;
282 | case Qt::Key_Enter:
283 | button->setIcon(QIcon(ENTER_ICON));
284 | break;
285 | case Qt::Key_Space:
286 | button->setIcon(QIcon(SPACE_ICON));
287 | break;
288 | default:
289 | break;
290 | }
291 | }
292 | }
293 |
294 | ChineseWidget::ChineseWidget(QWidget *parent) :
295 | QListWidget(parent)
296 | {
297 | #ifdef ENABLED_CHINESE_LIB
298 | loadChineseLib();
299 | #endif
300 |
301 | #ifdef ENABLED_CHINESE_PHRASE_LIB
302 | loadChinesePhraseLib();
303 | #endif
304 |
305 | #ifdef ENABLED_GOOGLE_CHINESE_LIB
306 | loadGoogleChineseLib();
307 | #endif
308 |
309 | setFocusPolicy(Qt::NoFocus);
310 | /* 设置为列表显示模式 */
311 | setViewMode(QListView::ListMode);
312 |
313 | /* 从左往右排列 */
314 | setFlow(QListView::LeftToRight);
315 |
316 | /* 屏蔽水平滑动条 */
317 | setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
318 |
319 | /* 屏蔽垂直滑动条 */
320 | setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
321 |
322 | /* 设置为像素滚动 */
323 | setHorizontalScrollMode(QListWidget::ScrollPerPixel);
324 |
325 | #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
326 | /* 设置鼠标左键拖动 */
327 | QScroller::grabGesture(this, QScroller::LeftMouseButtonGesture);
328 | #endif
329 |
330 | /* 设置样式 */
331 | setStyleSheet(" \
332 | QListWidget { outline: none; border:1px solid #00000000; color: black; } \
333 | QListWidget::Item { width: 50px; height: 50px; } \
334 | QListWidget::Item:hover { background: #4395ff; color: white; } \
335 | QListWidget::item:selected { background: #4395ff; color: black; } \
336 | QListWidget::item:selected:!active { background: #00000000; color: black; } \
337 | ");
338 |
339 | connect(this, SIGNAL(itemClicked(QListWidgetItem *)), this, SLOT(onItemClicked(QListWidgetItem *)));
340 | }
341 |
342 | void ChineseWidget::setText(const QString &text)
343 | {
344 | for (int i = 0; i < count(); i++) {
345 | QListWidgetItem *item = takeItem(i);
346 | delete item;
347 | item = NULL;
348 | }
349 |
350 | clear();
351 |
352 | addOneItem(text);
353 |
354 | if (! m_data.contains(text.left(1))) {
355 | return;
356 | }
357 |
358 | /* 通过获取首字母索引词库内容,用于加快匹配词(组)。 */
359 | const QList > &tmp = m_data[text.left(1)];
360 | for (int i = 0; i < tmp.count(); i++) {
361 | const QPair &each = tmp.at(i);
362 | /* 模糊匹配 */
363 | if (each.first.left(text.count()) != text)
364 | continue;
365 |
366 | /* 添加到候选栏, 并限制数量 */
367 | if (this->count() <= 30) {
368 | addOneItem(each.second);
369 | }
370 | else {
371 | break;
372 | }
373 | }
374 | }
375 |
376 | void ChineseWidget::onItemClicked(QListWidgetItem *item)
377 | {
378 | emit pressedChanged(-1, item->text());
379 | setText("");
380 | }
381 |
382 | void ChineseWidget::addOneItem(const QString &text)
383 | {
384 | QListWidgetItem *item = new QListWidgetItem(text, this);
385 | QFont font;
386 | font.setPointSize(18);
387 | font.setBold(true);
388 | font.setWeight(50);
389 | item->setFont(font);
390 |
391 | /* 设置文字居中 */
392 | item->setTextAlignment(Qt::AlignCenter);
393 | bool isChinese = QRegExp("^[\u4E00-\u9FA5]+").indexIn(text.left(1)) != -1;
394 |
395 | int width = font.pointSize();
396 | if (isChinese)
397 | width += text.count()*font.pointSize()*1.5;
398 | else
399 | width += text.count()*font.pointSize()*2/3;
400 |
401 | item->setSizeHint(QSize(width, 50));
402 | addItem(item);
403 | }
404 |
405 | void ChineseWidget::loadChineseLib()
406 | {
407 | QFile pinyin(":/ChineseLib/pinyin.txt");
408 | if (! pinyin.open(QIODevice::ReadOnly)) {
409 | qDebug() << "Open pinyin file failed!";
410 | return;
411 | }
412 |
413 | while (! pinyin.atEnd()) {
414 | QString buf = QString::fromUtf8(pinyin.readLine()).trimmed();
415 | QRegExp regExp("^[\u4E00-\u9FA5]+");
416 |
417 | int index = regExp.indexIn(buf);
418 | if (index == -1)
419 | continue;
420 |
421 | QString first = buf.right(buf.size() - regExp.matchedLength());
422 | QString second = buf.mid(index, regExp.matchedLength());
423 |
424 | QList > &tmp = m_data[first.left(1)];
425 | tmp.append(qMakePair(first, second));
426 | }
427 |
428 | pinyin.close();
429 | }
430 |
431 | void ChineseWidget::loadChinesePhraseLib()
432 | {
433 | /* 加载词组字库内容 */
434 | QFile pinyin(":/ChinesePhraseLib/pinyin_phrase.txt");
435 | if (! pinyin.open(QIODevice::ReadOnly)) {
436 | qDebug() << "Open pinyin file failed!";
437 | return;
438 | }
439 |
440 | /* 按行读取内容 */
441 | while (! pinyin.atEnd()) {
442 | QString buf = QString::fromUtf8(pinyin.readLine()).trimmed();
443 | if (buf.isEmpty())
444 | continue;
445 |
446 | /* 去除#号后的注释内容 */
447 | if (buf.left(1) == "#")
448 | continue;
449 |
450 | /* 正则匹配词组内容并通过组捕获获取'词组'和'拼音' */
451 | QRegExp regExp("(\\S+): ([\\S ]+)");
452 | int pos = 0;
453 | while ((pos = regExp.indexIn(buf, pos)) != -1) {
454 | pos += regExp.matchedLength();
455 | QString second = regExp.cap(1); /* 词组 */
456 | QString first = regExp.cap(2); /* 拼音 */
457 |
458 | QStringList strList = first.split(" ");
459 | QString abb;
460 | for (int i = 0; i < strList.count(); i++) {
461 | /* 获得拼音词组的首字母(用于缩写匹配) */
462 | abb += strList.at(i).left(1);
463 | }
464 | QList > &tmp = m_data[first.left(1)];
465 | /* 将'拼音(缩写)'和'词组'写入匹配容器 */
466 | tmp.append(qMakePair(abb, second));
467 | /* 将'拼音(全拼)'和'词组'写入匹配容器 */
468 | tmp.append(qMakePair(first.remove(" "), second));
469 | }
470 | }
471 |
472 | pinyin.close();
473 | }
474 |
475 | void ChineseWidget::loadGoogleChineseLib()
476 | {
477 | QFile file(":/GoogleChineseLib/rawdict_utf16_65105_freq_sort.txt");
478 | if (! file.open(QIODevice::ReadOnly)) {
479 | qDebug() << "Open pinyin file failed!" << file.fileName();
480 | return;
481 | }
482 |
483 | QTextStream in(&file);
484 | in.setCodec("UTF-16"); // change the file codec to UTF-16.
485 |
486 | QStringList lines = in.readAll().split("\n");
487 |
488 | for (QString each : lines) {
489 | QRegExp re(R"RX((\S+).((?:-?\d+)(?:\.\d+)).((?:-?\d+)(?:\.\d+)?).(.*))RX");
490 | int pos = 0;
491 |
492 | bool isMatching = false;
493 | while ((pos = re.indexIn(each, pos)) != -1) {
494 | pos += re.matchedLength();
495 | if (re.captureCount() != 4)
496 | continue;
497 |
498 | isMatching = true;
499 | QString hanzi = re.cap(1); // 汉字
500 | QString weight = re.cap(2); // 权重
501 | QString tmp = re.cap(3); // 未知
502 | QString pinyin = re.cap(4); // 拼音(可能是词组)
503 |
504 | QStringList strList = pinyin.split(" ");
505 | QString abb;
506 | for (int i = 0; i < strList.count(); i++) {
507 | /* 获得拼音词组的首字母(用于缩写匹配) */
508 | abb += strList.at(i).left(1);
509 | }
510 |
511 | QList > &list = m_data[pinyin.left(1)];
512 | if (strList.count() > 1) {
513 | /* 将'拼音(缩写)'和'词组'写入匹配容器 */
514 | list.append(qMakePair(abb, hanzi));
515 | }
516 | /* 将'拼音(全拼)'和'词组'写入匹配容器 */
517 | list.append(qMakePair(pinyin.remove(" "), hanzi));
518 | }
519 |
520 | if (!isMatching)
521 | qDebug() << each;
522 | }
523 |
524 | file.close();
525 | }
526 |
--------------------------------------------------------------------------------