├── 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 | ![键盘演示](Other/chinese_input_demo.gif) 4 | 5 | # 实现初衷 6 | * 供大家交流学习; 7 | * 希望以轻量级(嵌入式设备)键盘为特点不断**发展**该键盘项目(**源码地址**在文末)。 8 | ![键盘界面](Other/chinese_input.jpg) 9 | 10 | # 项目预览 11 | * 文件**目录** 12 | ![文件目录](Other/file_dir.png) 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 | 微信公众号:Qt君 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 | --------------------------------------------------------------------------------