├── .gitattributes ├── AbortDialog.cpp ├── AbortDialog.h ├── AppConfig.cpp ├── AppConfig.h ├── FindDialog.cpp ├── FindDialog.h ├── MainWindow.h ├── MainWindowUI.cpp ├── Notepad.pro ├── README.md ├── ReplaceDialog.cpp ├── ReplaceDialog.h ├── Res.qrc ├── logo.ico ├── logo.rc ├── main.cpp ├── mainwindowslots.cpp ├── pic ├── copy.png ├── cut.png ├── find.png ├── font.png ├── goto.png ├── logo.png ├── new.png ├── open.png ├── paste.png ├── print.png ├── redo.png ├── replace.png ├── save.png ├── saveas.png ├── status.png ├── tool.png ├── undo.png └── wrap.png └── qm └── qt_zh_CN.qm /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /AbortDialog.cpp: -------------------------------------------------------------------------------- 1 | #include "AbortDialog.h" 2 | #include 3 | #include 4 | 5 | AbortDialog::AbortDialog(QWidget* parent) : QDialog(parent, Qt::Drawer | Qt::Desktop) 6 | { 7 | initControl(); 8 | connectSlot(); 9 | } 10 | 11 | void AbortDialog::initControl() 12 | { 13 | QPixmap pm(":/Res/pic/logo.png"); 14 | 15 | pm = pm.scaled(84, 88, Qt::KeepAspectRatio); 16 | 17 | m_logoLbl.setParent(this); 18 | m_logoLbl.setPixmap(pm); 19 | m_logoLbl.move(14, 19); 20 | m_logoLbl.resize(84, 88); 21 | 22 | m_VersionLbl.setParent(this); 23 | m_VersionLbl.move(115, 29); 24 | m_VersionLbl.resize(218, 20); 25 | m_VersionLbl.setText("NotePad v2.3.1.1 (32-bit) "); 26 | 27 | m_authotLbl.setParent(this); 28 | m_authotLbl.move(44, 132); 29 | m_authotLbl.resize(54, 20); 30 | m_authotLbl.setText("作 者 :"); 31 | 32 | m_authotUrlLbl.setParent(this); 33 | m_authotUrlLbl.move(127, 132); 34 | m_authotUrlLbl.resize(113, 20); 35 | m_authotUrlLbl.setText("D.T.TianSong"); 36 | 37 | m_mailLbl.setParent(this); 38 | m_mailLbl.move(44, 162); 39 | m_mailLbl.resize(81, 19); 40 | m_mailLbl.setText("邮 箱 :"); 41 | 42 | m_mailUrlLbl.setParent(this); 43 | m_mailUrlLbl.move(127, 162); 44 | m_mailUrlLbl.resize(146, 19); 45 | m_mailUrlLbl.setText("1508539502@qq.com"); 46 | 47 | m_homeLbl.setParent(this); 48 | m_homeLbl.move(44, 199); 49 | m_homeLbl.resize(81, 19); 50 | m_homeLbl.setText("主 页 :"); 51 | 52 | m_homeUrlLbl.setParent(this); 53 | m_homeUrlLbl.move(127, 199); 54 | m_homeUrlLbl.resize(235, 19); 55 | m_homeUrlLbl.setOpenExternalLinks(true); 56 | m_homeUrlLbl.setText("https://segmentfault.com/u/tiansong"); 57 | 58 | m_okBtn.setParent(this); 59 | m_okBtn.move(156, 379); 60 | m_okBtn.resize(88, 24); 61 | m_okBtn.setText("确定"); 62 | 63 | m_edit.setParent(this); 64 | m_edit.move(24, 235); 65 | m_edit.resize(377, 115); 66 | m_edit.setReadOnly(true); 67 | m_edit.insertPlainText("开发平台: Qt 5.11.2\n\n构建时间: 2019.03.03 - 00:33:41\n\n" 68 | "开源计划: https://segmentfault.com/u/tiansong\n\n" 69 | "Copyright © 2018-2019 D.T. TianSong"); 70 | 71 | QPalette p = palette(); 72 | p.setColor(QPalette::Active, QPalette::Background, Qt::white); 73 | p.setColor(QPalette::Inactive, QPalette::Background, Qt::white); 74 | setPalette(p); 75 | 76 | setWindowTitle("关于 - 记事本"); 77 | setFixedSize(420, 427); 78 | } 79 | 80 | void AbortDialog::connectSlot() 81 | { 82 | connect(&m_okBtn, SIGNAL(clicked()), this, SLOT(onOKClicked())); 83 | } 84 | 85 | void AbortDialog::onOKClicked() 86 | { 87 | close(); 88 | } 89 | -------------------------------------------------------------------------------- /AbortDialog.h: -------------------------------------------------------------------------------- 1 | #ifndef ABORTDIALOG_H 2 | #define ABORTDIALOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class AbortDialog : public QDialog 10 | { 11 | Q_OBJECT 12 | 13 | protected: 14 | QLabel m_logoLbl; 15 | QLabel m_VersionLbl; 16 | 17 | QLabel m_authotLbl; 18 | QLabel m_authotUrlLbl; 19 | 20 | QLabel m_homeLbl; 21 | QLabel m_homeUrlLbl; 22 | 23 | QLabel m_mailLbl; 24 | QLabel m_mailUrlLbl; 25 | 26 | QPlainTextEdit m_edit; 27 | 28 | QPushButton m_okBtn; 29 | 30 | void initControl(); 31 | void connectSlot(); 32 | 33 | protected slots: 34 | void onOKClicked(); 35 | 36 | public: 37 | AbortDialog(QWidget* parent); 38 | }; 39 | 40 | #endif // ABORTDIALOG_H 41 | -------------------------------------------------------------------------------- /AppConfig.cpp: -------------------------------------------------------------------------------- 1 | #include "AppConfig.h" 2 | #include 3 | #include 4 | #include 5 | 6 | AppConfig::AppConfig(QObject *parent) : QObject(parent) 7 | { 8 | m_isVilid = restore(); 9 | } 10 | 11 | AppConfig::AppConfig(QFont font, QSize size, QPoint point, bool isWrap, bool tbvisible, bool sbVisible, QObject *parent) : QObject(parent) 12 | { 13 | m_editFont = font; 14 | m_mainWindowSize = size; 15 | m_mainWindowPoint = point; 16 | m_isAutoWrap = isWrap; 17 | m_isToolBarVisible = tbvisible; 18 | m_isStatusVisible = sbVisible; 19 | 20 | m_isVilid = true; 21 | } 22 | 23 | bool AppConfig::restore() 24 | { 25 | bool ret = true; 26 | QFile file(QApplication::applicationDirPath() + "/app.config"); 27 | 28 | if( file.open(QIODevice::ReadOnly) ) 29 | { 30 | QDataStream in(&file); 31 | 32 | in >> m_editFont; 33 | in >> m_mainWindowSize; 34 | in >> m_mainWindowPoint; 35 | in >> m_isAutoWrap; 36 | in >> m_isToolBarVisible; 37 | in >> m_isStatusVisible; 38 | 39 | file.close(); 40 | } 41 | else 42 | { 43 | ret = false; 44 | } 45 | 46 | return ret; 47 | } 48 | 49 | bool AppConfig::store() 50 | { 51 | bool ret = true; 52 | QFile file(QApplication::applicationDirPath() + "/app.config"); 53 | 54 | if( file.open(QIODevice::WriteOnly) ) 55 | { 56 | QDataStream out(&file); 57 | 58 | out << m_editFont; 59 | out << m_mainWindowSize; 60 | out << m_mainWindowPoint; 61 | out << m_isAutoWrap; 62 | out << m_isToolBarVisible; 63 | out << m_isStatusVisible; 64 | 65 | file.close(); 66 | } 67 | else 68 | { 69 | ret = false; 70 | } 71 | 72 | return ret; 73 | } 74 | 75 | QFont AppConfig::editFont() 76 | { 77 | return m_editFont; 78 | } 79 | 80 | QSize AppConfig::mainWindowSize() 81 | { 82 | return m_mainWindowSize; 83 | } 84 | 85 | QPoint AppConfig::mainWindowPoint() 86 | { 87 | return m_mainWindowPoint; 88 | } 89 | 90 | bool AppConfig::isAutoWrap() 91 | { 92 | return m_isAutoWrap; 93 | } 94 | 95 | bool AppConfig::isToolBarVisible() 96 | { 97 | return m_isToolBarVisible; 98 | } 99 | 100 | bool AppConfig::isStatusVisible() 101 | { 102 | return m_isStatusVisible; 103 | } 104 | 105 | bool AppConfig::isVilid() 106 | { 107 | return m_isVilid; 108 | } 109 | -------------------------------------------------------------------------------- /AppConfig.h: -------------------------------------------------------------------------------- 1 | #ifndef APPCONFIG_H 2 | #define APPCONFIG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class AppConfig : public QObject 10 | { 11 | 12 | protected: 13 | QFont m_editFont; 14 | QSize m_mainWindowSize; 15 | QPoint m_mainWindowPoint; 16 | bool m_isAutoWrap; 17 | bool m_isToolBarVisible; 18 | bool m_isStatusVisible; 19 | bool m_isVilid; 20 | 21 | bool restore(); 22 | 23 | public: 24 | explicit AppConfig(QObject *parent = nullptr); 25 | explicit AppConfig(QFont font, QSize size, QPoint point, bool isWrap, bool tbvisible, bool sbVisible, QObject *parent = nullptr); 26 | bool store(); 27 | QFont editFont(); 28 | QSize mainWindowSize(); 29 | QPoint mainWindowPoint(); 30 | bool isAutoWrap(); 31 | bool isToolBarVisible(); 32 | bool isStatusVisible(); 33 | bool isVilid(); 34 | }; 35 | 36 | #endif // APPCONFIG_H 37 | -------------------------------------------------------------------------------- /FindDialog.cpp: -------------------------------------------------------------------------------- 1 | #include "FindDialog.h" 2 | #include 3 | #include 4 | #include 5 | 6 | FindDialog::FindDialog(QWidget* parent, QPlainTextEdit* pText) : QDialog (parent, Qt::WindowCloseButtonHint | Qt::Drawer) 7 | { 8 | initControl(); 9 | connectSlot(); 10 | 11 | setLayout(&m_layout); 12 | setFixedSize(450, 120); 13 | setWindowTitle("查找"); 14 | 15 | setPlainTextEdit(pText); 16 | } 17 | 18 | void FindDialog::initControl() 19 | { 20 | m_findLbl.setText("查找目标:"); 21 | m_findBtn.setText("查找下一个(&F)"); 22 | m_cancelBtn.setText("取消"); 23 | m_matchChkBx.setText("区分大小写(&C)"); 24 | m_radioGrpBx.setTitle("方向"); 25 | m_upwardBtn.setText("向上(&U)"); 26 | m_downwardBtn.setText("向下(&D)"); 27 | m_downwardBtn.setChecked(true); 28 | 29 | m_hbLayout.addWidget(&m_upwardBtn); 30 | m_hbLayout.addWidget(&m_downwardBtn); 31 | m_radioGrpBx.setLayout(&m_hbLayout); 32 | 33 | m_layout.addWidget(&m_findLbl, 0, 0); 34 | m_layout.addWidget(&m_findEdit, 0, 1); 35 | m_layout.addWidget(&m_findBtn, 0, 2); 36 | 37 | m_layout.addWidget(&m_matchChkBx, 1, 0); 38 | m_layout.addWidget(&m_radioGrpBx, 1, 1); 39 | m_layout.addWidget(&m_cancelBtn, 1, 2); 40 | } 41 | 42 | void FindDialog::connectSlot() 43 | { 44 | connect(&m_findBtn, SIGNAL(clicked()), this, SLOT(onFindClicked())); 45 | connect(&m_cancelBtn, SIGNAL(clicked()), this, SLOT(onCancelClicked())); 46 | } 47 | 48 | void FindDialog::setPlainTextEdit(QPlainTextEdit* pText) 49 | { 50 | m_pText = pText; 51 | } 52 | 53 | QPlainTextEdit* FindDialog::getPlainTextEdit() 54 | { 55 | return m_pText; 56 | } 57 | 58 | void FindDialog::onFindClicked() 59 | { 60 | QString target = m_findEdit.text(); 61 | 62 | if( (m_pText != nullptr) && (target != "") ) 63 | { 64 | QString text = m_pText->toPlainText(); 65 | QTextCursor c = m_pText->textCursor(); 66 | int index = -1; 67 | 68 | if( m_downwardBtn.isChecked() ) 69 | { 70 | index = text.indexOf(target, c.position(), m_matchChkBx.isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive); 71 | 72 | if( index >= 0 ) 73 | { 74 | c.setPosition(index); 75 | c.setPosition(index + target.length(), QTextCursor::KeepAnchor); 76 | 77 | m_pText->setTextCursor(c); 78 | } 79 | } 80 | 81 | if( m_upwardBtn.isChecked() ) 82 | { 83 | index = text.lastIndexOf(target, c.position() - text.length() - 1, m_matchChkBx.isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive); 84 | 85 | if( index >=0 ) 86 | { 87 | c.setPosition(index + target.length()); 88 | c.setPosition(index, QTextCursor::KeepAnchor); 89 | 90 | m_pText->setTextCursor(c); 91 | } 92 | } 93 | 94 | if( index < 0 ) 95 | { 96 | QMessageBox msg(this); 97 | 98 | msg.setWindowTitle("记事本"); 99 | msg.setText(QString("找不到 ") + "\"" + target + "\""); 100 | msg.setWindowFlag(Qt::Drawer); 101 | msg.setIcon(QMessageBox::Information); 102 | msg.setStandardButtons(QMessageBox::Ok); 103 | 104 | msg.exec(); 105 | } 106 | } 107 | } 108 | 109 | void FindDialog::onCancelClicked() 110 | { 111 | close(); 112 | } 113 | 114 | bool FindDialog::event(QEvent* e) 115 | { 116 | if( e->type() == QEvent::Close ) 117 | { 118 | hide(); 119 | 120 | return true; 121 | } 122 | 123 | return QDialog::event(e); 124 | } 125 | 126 | FindDialog::~FindDialog() 127 | { 128 | 129 | } 130 | -------------------------------------------------------------------------------- /FindDialog.h: -------------------------------------------------------------------------------- 1 | #ifndef FINDDIALOG_H 2 | #define FINDDIALOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | class FindDialog : public QDialog 17 | { 18 | Q_OBJECT 19 | 20 | protected: 21 | QGroupBox m_radioGrpBx; 22 | 23 | QGridLayout m_layout; 24 | QHBoxLayout m_hbLayout; 25 | 26 | QLabel m_findLbl; 27 | QLineEdit m_findEdit; 28 | QPushButton m_findBtn; 29 | QPushButton m_cancelBtn; 30 | QCheckBox m_matchChkBx; 31 | QRadioButton m_upwardBtn; 32 | QRadioButton m_downwardBtn; 33 | 34 | QPointer m_pText; 35 | 36 | void initControl(); 37 | void connectSlot(); 38 | 39 | public slots: 40 | void onFindClicked(); 41 | void onCancelClicked(); 42 | 43 | public: 44 | FindDialog(QWidget* parent = nullptr, QPlainTextEdit* pText = nullptr); 45 | void setPlainTextEdit(QPlainTextEdit* pText); 46 | QPlainTextEdit* getPlainTextEdit(); 47 | bool event(QEvent* e); 48 | ~FindDialog(); 49 | }; 50 | 51 | #endif // FINDDIALOG_H 52 | -------------------------------------------------------------------------------- /MainWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "FindDialog.h" 16 | #include "ReplaceDialog.h" 17 | #include "AbortDialog.h" 18 | #include "AppConfig.h" 19 | 20 | class MainWindow : public QMainWindow 21 | { 22 | Q_OBJECT 23 | 24 | private: 25 | QPlainTextEdit mainEditor; 26 | QLabel statusCursorLabel; 27 | QLabel statusLabel; 28 | QString m_filePath; 29 | bool m_isTextChanged; 30 | 31 | QSharedPointer m_pFindDlg; 32 | QSharedPointer m_pReplaceDlg; 33 | QSharedPointer m_pPageSetupDlg; 34 | 35 | MainWindow(); 36 | MainWindow(const MainWindow&); 37 | MainWindow& operator = (const MainWindow); 38 | 39 | bool construct(); 40 | 41 | bool initMenuBar(); 42 | bool initFileMenu(QMenuBar* mb); 43 | bool initEditMenu(QMenuBar* mb); 44 | bool initFormatMenu(QMenuBar* mb); 45 | bool initViewMenu(QMenuBar* mb); 46 | bool initHelpMenu(QMenuBar* mb); 47 | bool makeAction(QAction*& action, QWidget* parent, QString text, int key); 48 | 49 | bool initToolBar(); 50 | bool initFileToolItem(QToolBar* tb); 51 | bool initEditToolItem(QToolBar* tb); 52 | bool initFormatToolItem(QToolBar* tb); 53 | bool initViewToolItem(QToolBar* tb); 54 | bool makeAction(QAction*& action, QWidget* parent, QString tip, QString icon); 55 | 56 | bool initStatusBar(); 57 | bool initMainEditor(); 58 | 59 | QString showFileDialog(QFileDialog::AcceptMode mode, QString title, QString icon); 60 | void showErrorMessage(QString message); 61 | int showQueryMessage(QString message); 62 | QString saveCurrentData(QString title = "", QString path = ""); 63 | void preEditChange(); 64 | void openFileEditor(QString path); 65 | 66 | QAction* findMenuBarAction(QString text); 67 | QAction* findToolBarAction(QString text); 68 | 69 | protected: 70 | void closeEvent(QCloseEvent *event); 71 | void dragEnterEvent(QDragEnterEvent* event); 72 | void dropEvent(QDropEvent* event); 73 | 74 | private slots: 75 | void onFileNew(); 76 | void onFileOpen(); 77 | void onFileSave(); 78 | void onFileSaveAs(); 79 | void onFilePageSetup(); 80 | void onFilePrint(); 81 | 82 | void onTextChanged(); 83 | void onEditDelete(); 84 | void onEditFind(); 85 | void onEditFindNext(); 86 | void onEditReplace(); 87 | void onEditGoto(); 88 | void onEditSelectAll(); 89 | void onEditDate(); 90 | void onEditCalculator(); 91 | void onEditmspaint(); 92 | 93 | void FormatFont(); 94 | void FormatWrap(); 95 | 96 | void onViewToolBar(); 97 | void onViewStatusBar(); 98 | 99 | void onHelpManual(); 100 | void onHelpAbort(); 101 | 102 | void onCopyAvailable(bool available); 103 | void onRedoAvailable(bool available); 104 | void onUndoAvailable(bool available); 105 | 106 | void onCursorPositionChanged(); 107 | 108 | public: 109 | static MainWindow* NewInstance(); 110 | QToolBar* toolBar(); 111 | void openFile(QString path); 112 | ~MainWindow(); 113 | }; 114 | 115 | #endif // MAINWINDOW_H 116 | -------------------------------------------------------------------------------- /MainWindowUI.cpp: -------------------------------------------------------------------------------- 1 | #include "MainWindow.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | MainWindow::MainWindow() : 12 | m_pFindDlg(new FindDialog(this, &mainEditor)), 13 | m_pReplaceDlg(new ReplaceDialog(this, &mainEditor)), 14 | m_pPageSetupDlg(new QPageSetupDialog(this)) 15 | { 16 | m_filePath = ""; 17 | m_isTextChanged = false; 18 | } 19 | 20 | bool MainWindow::construct() 21 | { 22 | bool ret = true; 23 | AppConfig config; 24 | 25 | ret = ret && initMenuBar(); 26 | ret = ret && initToolBar(); 27 | ret = ret && initStatusBar(); 28 | ret = ret && initMainEditor(); 29 | 30 | setWindowTitle("新建文本文档 - 记事本"); 31 | setWindowIcon(QIcon(":/Res/pic/logo.png")); 32 | setAcceptDrops(true); 33 | 34 | if( ret && config.isVilid() ) 35 | { 36 | mainEditor.setFont(config.editFont()); 37 | 38 | if( !config.isAutoWrap() ) 39 | { 40 | mainEditor.setLineWrapMode(QPlainTextEdit::NoWrap); 41 | 42 | findMenuBarAction("自动换行")->setChecked(false); 43 | findToolBarAction("自动换行")->setChecked(false); 44 | } 45 | 46 | if( !config.isToolBarVisible() ) 47 | { 48 | toolBar()->setVisible(false); 49 | 50 | findMenuBarAction("工具栏")->setChecked(false); 51 | findToolBarAction("工具栏")->setChecked(false); 52 | } 53 | 54 | if( !config.isStatusVisible() ) 55 | { 56 | statusBar()->setVisible(false); 57 | 58 | findMenuBarAction("状态栏")->setChecked(false); 59 | findToolBarAction("状态栏")->setChecked(false); 60 | } 61 | 62 | move(config.mainWindowPoint()); 63 | resize(config.mainWindowSize()); 64 | } 65 | 66 | return ret; 67 | } 68 | 69 | MainWindow* MainWindow::NewInstance() 70 | { 71 | MainWindow* ret = new MainWindow(); 72 | 73 | if( (ret == nullptr) || !ret->construct() ) 74 | { 75 | delete ret; 76 | 77 | ret = nullptr; 78 | } 79 | 80 | return ret; 81 | } 82 | 83 | //----------------------------- 84 | bool MainWindow::initMenuBar() 85 | { 86 | QMenuBar* mb = menuBar(); 87 | bool ret = (mb != nullptr); 88 | 89 | ret = ret && initFileMenu(mb); 90 | ret = ret && initEditMenu(mb); 91 | ret = ret && initFormatMenu(mb); 92 | ret = ret && initViewMenu(mb); 93 | ret = ret && initHelpMenu(mb); 94 | 95 | return ret; 96 | } 97 | 98 | bool MainWindow::initFileMenu(QMenuBar* mb) 99 | { 100 | QMenu* menu = new QMenu("文件(&F)", mb); 101 | bool ret = (menu != nullptr); 102 | 103 | if( ret ) 104 | { 105 | QAction* action = nullptr; 106 | 107 | ret = ret && makeAction(action, menu, "新建(&N)", Qt::CTRL + Qt::Key_N); 108 | if( ret ) 109 | { 110 | connect(action, SIGNAL(triggered()), this, SLOT(onFileNew())); 111 | menu->addAction(action); 112 | } 113 | 114 | ret = ret && makeAction(action, menu, "打开(&O)...", Qt::CTRL + Qt::Key_O); 115 | if( ret ) 116 | { 117 | connect(action, SIGNAL(triggered()), this, SLOT(onFileOpen())); 118 | menu->addAction(action); 119 | } 120 | 121 | ret = ret && makeAction(action, menu, "保存(&S)", Qt::CTRL + Qt::Key_S); 122 | if( ret ) 123 | { 124 | connect(action, SIGNAL(triggered()), this, SLOT(onFileSave())); 125 | menu->addAction(action); 126 | } 127 | 128 | ret = ret && makeAction(action, menu, "另存为(&A)...", 0); 129 | if( ret ) 130 | { 131 | connect(action, SIGNAL(triggered()), this, SLOT(onFileSaveAs())); 132 | menu->addAction(action); 133 | } 134 | 135 | menu->addSeparator(); 136 | 137 | ret = ret && makeAction(action, menu, "页面设置(&U)...", Qt::CTRL + Qt::Key_U); 138 | if( ret ) 139 | { 140 | connect(action, SIGNAL(triggered()), this, SLOT(onFilePageSetup())); 141 | menu->addAction(action); 142 | } 143 | 144 | ret = ret && makeAction(action, menu, "打印(&P)...", Qt::CTRL + Qt::Key_P); 145 | if( ret ) 146 | { 147 | connect(action, SIGNAL(triggered()), this, SLOT(onFilePrint())); 148 | menu->addAction(action); 149 | } 150 | 151 | menu->addSeparator(); 152 | 153 | ret = ret && makeAction(action, menu, "退出(&X)", 0); 154 | if( ret ) 155 | { 156 | menu->addAction(action); 157 | } 158 | } 159 | 160 | if( ret ) 161 | { 162 | mb->addMenu(menu); 163 | } 164 | else 165 | { 166 | delete menu; 167 | } 168 | 169 | return ret; 170 | } 171 | 172 | bool MainWindow::initEditMenu(QMenuBar* mb) 173 | { 174 | QMenu* menu = new QMenu("编辑(&E)", mb); 175 | bool ret = (menu != nullptr); 176 | 177 | if( ret ) 178 | { 179 | QAction* action = nullptr; 180 | 181 | ret = ret && makeAction(action, menu, "撤销(&U)", Qt::CTRL + Qt::Key_Z); 182 | if( ret ) 183 | { 184 | connect(action, SIGNAL(triggered()), &mainEditor, SLOT(undo())); 185 | action->setEnabled(false); 186 | menu->addAction(action); 187 | } 188 | 189 | ret = ret && makeAction(action, menu, "剪切(&T)", Qt::CTRL + Qt::Key_X); 190 | if( ret ) 191 | { 192 | connect(action, SIGNAL(triggered()), &mainEditor, SLOT(redo())); 193 | action->setEnabled(false); 194 | menu->addAction(action); 195 | } 196 | 197 | ret = ret && makeAction(action, menu, "复制(&C)", Qt::CTRL + Qt::Key_C); 198 | if( ret ) 199 | { 200 | connect(action, SIGNAL(triggered()), &mainEditor, SLOT(copy())); 201 | action->setEnabled(false); 202 | menu->addAction(action); 203 | } 204 | 205 | ret = ret && makeAction(action, menu, "粘贴(&P)", Qt::CTRL + Qt::Key_V); 206 | if( ret ) 207 | { 208 | connect(action, SIGNAL(triggered()), &mainEditor, SLOT(paste())); 209 | menu->addAction(action); 210 | } 211 | 212 | ret = ret && makeAction(action, menu, "删除(&L)....", Qt::Key_Delete); 213 | if( ret ) 214 | { 215 | connect(action, SIGNAL(triggered()), this, SLOT(onEditDelete())); 216 | menu->addAction(action); 217 | } 218 | 219 | menu->addSeparator(); 220 | 221 | ret = ret && makeAction(action, menu, "查找(&F)...", Qt::CTRL + Qt::Key_F); 222 | if( ret ) 223 | { 224 | connect(action, SIGNAL(triggered()), this, SLOT(onEditFind())); 225 | menu->addAction(action); 226 | } 227 | 228 | ret = ret && makeAction(action, menu, "查找下一个(&N)", Qt::Key_F3); 229 | if( ret ) 230 | { 231 | connect(action, SIGNAL(triggered()), this, SLOT(onEditFindNext())); 232 | menu->addAction(action); 233 | } 234 | 235 | ret = ret && makeAction(action, menu, "替换(&R)...", Qt::CTRL + Qt::Key_H); 236 | if( ret ) 237 | { 238 | connect(action, SIGNAL(triggered()), this, SLOT(onEditReplace())); 239 | menu->addAction(action); 240 | } 241 | 242 | ret = ret && makeAction(action, menu, "转到(&G)...", Qt::CTRL + Qt::Key_G); 243 | if( ret ) 244 | { 245 | connect(action, SIGNAL(triggered()), this, SLOT(onEditGoto())); 246 | menu->addAction(action); 247 | } 248 | 249 | menu->addSeparator(); 250 | 251 | ret = ret && makeAction(action, menu, "全选(&A)", Qt::CTRL + Qt::Key_A); 252 | if( ret ) 253 | { 254 | connect(action, SIGNAL(triggered()), this, SLOT(onEditSelectAll())); 255 | menu->addAction(action); 256 | } 257 | 258 | ret = ret && makeAction(action, menu, "时间/日期(&D)", Qt::Key_F5); 259 | if( ret ) 260 | { 261 | connect(action, SIGNAL(triggered()), this, SLOT(onEditDate())); 262 | menu->addAction(action); 263 | } 264 | 265 | menu->addSeparator(); 266 | 267 | ret = ret && makeAction(action, menu, "计算器...", 0); 268 | if( ret ) 269 | { 270 | connect(action, SIGNAL(triggered()), this, SLOT(onEditCalculator())); 271 | menu->addAction(action); 272 | } 273 | 274 | ret = ret && makeAction(action, menu, "画图...", 0); 275 | if( ret ) 276 | { 277 | connect(action, SIGNAL(triggered()), this, SLOT(onEditmspaint())); 278 | menu->addAction(action); 279 | } 280 | } 281 | 282 | if( ret ) 283 | { 284 | mb->addMenu(menu); 285 | } 286 | else 287 | { 288 | delete menu; 289 | } 290 | 291 | return ret; 292 | } 293 | 294 | bool MainWindow::initFormatMenu(QMenuBar* mb) 295 | { 296 | QMenu* menu = new QMenu("格式(&O)", mb); 297 | bool ret = (menu != nullptr); 298 | 299 | if( ret ) 300 | { 301 | QAction* action = nullptr; 302 | 303 | ret = ret && makeAction(action, menu, "自动换行(&W)", 0); 304 | if( ret ) 305 | { 306 | action->setCheckable(true); 307 | action->setChecked(true); 308 | connect(action, SIGNAL(triggered()), this, SLOT(FormatWrap())); 309 | menu->addAction(action); 310 | } 311 | 312 | ret = ret && makeAction(action, menu, "字体(&F)...", 0); 313 | if( ret ) 314 | { 315 | connect(action, SIGNAL(triggered()), this, SLOT(FormatFont())); 316 | menu->addAction(action); 317 | } 318 | } 319 | 320 | if( ret ) 321 | { 322 | mb->addMenu(menu); 323 | } 324 | else 325 | { 326 | delete menu; 327 | } 328 | 329 | return ret; 330 | } 331 | 332 | bool MainWindow::initViewMenu(QMenuBar* mb) 333 | { 334 | QMenu* menu = new QMenu("查看(&V)", mb); 335 | bool ret = (menu != nullptr); 336 | 337 | if( ret ) 338 | { 339 | QAction* action = nullptr; 340 | 341 | ret = ret && makeAction(action, menu, "工具栏(&T)", 0); 342 | if( ret ) 343 | { 344 | action->setCheckable(true); 345 | action->setChecked(true); 346 | connect(action, SIGNAL(triggered()), this, SLOT(onViewToolBar())); 347 | 348 | menu->addAction(action); 349 | } 350 | 351 | ret = ret && makeAction(action, menu, "状态栏(&S)", 0); 352 | if( ret ) 353 | { 354 | action->setCheckable(true); 355 | action->setChecked(true); 356 | connect(action, SIGNAL(triggered()), this, SLOT(onViewStatusBar())); 357 | 358 | menu->addAction(action); 359 | } 360 | } 361 | 362 | if( ret ) 363 | { 364 | mb->addMenu(menu); 365 | } 366 | else 367 | { 368 | delete menu; 369 | } 370 | 371 | return ret; 372 | } 373 | 374 | bool MainWindow::initHelpMenu(QMenuBar* mb) 375 | { 376 | QMenu* menu = new QMenu("帮助(&H)", mb); 377 | bool ret = (menu != nullptr); 378 | 379 | if( ret ) 380 | { 381 | QAction* action = nullptr; 382 | 383 | ret = ret && makeAction(action, menu, "查看帮助(&H)", 0); 384 | if( ret ) 385 | { 386 | connect(action, SIGNAL(triggered()), this, SLOT(onHelpManual())); 387 | menu->addAction(action); 388 | } 389 | 390 | ret = ret && makeAction(action, menu, "关于记事本(&A)", 0); 391 | if( ret ) 392 | { 393 | connect(action, SIGNAL(triggered()), this, SLOT(onHelpAbort())); 394 | menu->addAction(action); 395 | } 396 | } 397 | 398 | if( ret ) 399 | { 400 | mb->addMenu(menu); 401 | } 402 | else 403 | { 404 | delete menu; 405 | } 406 | 407 | return ret; 408 | } 409 | 410 | bool MainWindow::makeAction(QAction*& action, QWidget* parent, QString text, int key) 411 | { 412 | bool ret = true; 413 | 414 | action = new QAction(text, parent); 415 | 416 | if( action != nullptr ) 417 | { 418 | action->setShortcut(QKeySequence(key)); 419 | } 420 | else 421 | { 422 | ret = false; 423 | } 424 | 425 | return ret; 426 | } 427 | 428 | //------------------------------ 429 | bool MainWindow::initToolBar() 430 | { 431 | QToolBar* tb = addToolBar("工具栏"); 432 | bool ret = true; 433 | 434 | tb->setIconSize(QSize(16, 16)); 435 | tb->setFloatable(false); 436 | tb->setMovable(false); 437 | 438 | ret = ret && initFileToolItem(tb); 439 | 440 | tb->addSeparator(); 441 | 442 | ret = ret && initEditToolItem(tb); 443 | 444 | tb->addSeparator(); 445 | 446 | ret = ret && initFormatToolItem(tb); 447 | 448 | tb->addSeparator(); 449 | 450 | ret = ret && initViewToolItem(tb); 451 | 452 | return ret; 453 | } 454 | 455 | bool MainWindow::initFileToolItem(QToolBar* tb) 456 | { 457 | QAction* action = nullptr; 458 | bool ret = true; 459 | 460 | ret = ret && makeAction(action, tb, "新建", ":/Res/pic/new.png"); 461 | if( ret ) 462 | { 463 | connect(action, SIGNAL(triggered()), this, SLOT(onFileNew())); 464 | tb->addAction(action); 465 | } 466 | 467 | ret = ret && makeAction(action, tb, "打开", ":/Res/pic/open.png"); 468 | if( ret ) 469 | { 470 | connect(action, SIGNAL(triggered()), this, SLOT(onFileOpen())); 471 | tb->addAction(action); 472 | } 473 | 474 | ret = ret && makeAction(action, tb, "保存", ":/Res/pic/save.png"); 475 | if( ret ) 476 | { 477 | connect(action, SIGNAL(triggered()), this, SLOT(onFileSave())); 478 | tb->addAction(action); 479 | } 480 | 481 | ret = ret && makeAction(action, tb, "另存为", ":/Res/pic/saveas.png"); 482 | if( ret ) 483 | { 484 | connect(action, SIGNAL(triggered()), this, SLOT(onFileSaveAs())); 485 | tb->addAction(action); 486 | } 487 | 488 | ret = ret && makeAction(action, tb, "打印", ":/Res/pic/print.png"); 489 | if( ret ) 490 | { 491 | connect(action, SIGNAL(triggered()), this, SLOT(onFilePrint())); 492 | tb->addAction(action); 493 | } 494 | 495 | return ret; 496 | } 497 | 498 | bool MainWindow::initEditToolItem(QToolBar* tb) 499 | { 500 | QAction* action = nullptr; 501 | bool ret = true; 502 | 503 | ret = ret && makeAction(action, tb, "撤销", ":/Res/pic/undo.png"); 504 | if( ret ) 505 | { 506 | connect(action, SIGNAL(triggered()), &mainEditor, SLOT(undo())); 507 | action->setEnabled(false); 508 | tb->addAction(action); 509 | } 510 | 511 | ret = ret && makeAction(action, tb, "恢复", ":/Res/pic/redo.png"); 512 | if( ret ) 513 | { 514 | connect(action, SIGNAL(triggered()), &mainEditor, SLOT(redo())); 515 | action->setEnabled(false); 516 | tb->addAction(action); 517 | } 518 | 519 | ret = ret && makeAction(action, tb, "剪切", ":/Res/pic/cut.png"); 520 | if( ret ) 521 | { 522 | connect(action, SIGNAL(triggered()), &mainEditor, SLOT(cut())); 523 | action->setEnabled(false); 524 | tb->addAction(action); 525 | } 526 | 527 | ret = ret && makeAction(action, tb, "复制", ":/Res/pic/paste.png"); 528 | if( ret ) 529 | { 530 | connect(action, SIGNAL(triggered()), &mainEditor, SLOT(copy())); 531 | action->setEnabled(false); 532 | tb->addAction(action); 533 | } 534 | 535 | ret = ret && makeAction(action, tb, "粘贴", ":/Res/pic/paste.png"); 536 | if( ret ) 537 | { 538 | connect(action, SIGNAL(triggered()), &mainEditor, SLOT(paste())); 539 | tb->addAction(action); 540 | } 541 | 542 | ret = ret && makeAction(action, tb, "查找", ":/Res/pic/find.png"); 543 | if( ret ) 544 | { 545 | connect(action, SIGNAL(triggered()), this, SLOT(onEditFind())); 546 | tb->addAction(action); 547 | } 548 | 549 | ret = ret && makeAction(action, tb, "替换", ":/Res/pic/replace.png"); 550 | if( ret ) 551 | { 552 | connect(action, SIGNAL(triggered()), this, SLOT(onEditReplace())); 553 | tb->addAction(action); 554 | } 555 | 556 | ret = ret && makeAction(action, tb, "转到", ":/Res/pic/goto.png"); 557 | if( ret ) 558 | { 559 | connect(action, SIGNAL(triggered()), this, SLOT(onEditGoto())); 560 | tb->addAction(action); 561 | } 562 | 563 | return ret; 564 | } 565 | 566 | bool MainWindow::initFormatToolItem(QToolBar* tb) 567 | { 568 | QAction* action = nullptr; 569 | bool ret = true; 570 | 571 | ret = ret && makeAction(action, tb, "自动换行", ":/Res/pic/wrap.png"); 572 | if( ret ) 573 | { 574 | action->setCheckable(true); 575 | action->setChecked(true); 576 | connect(action, SIGNAL(triggered()), this, SLOT(FormatWrap())); 577 | tb->addAction(action); 578 | } 579 | 580 | ret = ret && makeAction(action, tb,"字体", ":/Res/pic/font.png"); 581 | if( ret ) 582 | { 583 | connect(action, SIGNAL(triggered()), this, SLOT(FormatFont())); 584 | tb->addAction(action); 585 | } 586 | 587 | return ret; 588 | } 589 | 590 | bool MainWindow::initViewToolItem(QToolBar* tb) 591 | { 592 | QAction* action = nullptr; 593 | bool ret = true; 594 | 595 | ret = ret && makeAction(action, tb,"工具栏", ":/Res/pic/tool.png"); 596 | if( ret ) 597 | { 598 | action->setCheckable(true); 599 | action->setChecked(true); 600 | connect(action, SIGNAL(triggered()), this, SLOT(onViewToolBar())); 601 | tb->addAction(action); 602 | } 603 | 604 | ret = ret && makeAction(action, tb,"状态栏", ":/Res/pic/status.png"); 605 | if( ret ) 606 | { 607 | action->setCheckable(true); 608 | action->setChecked(true); 609 | connect(action, SIGNAL(triggered()), this, SLOT(onViewStatusBar())); 610 | tb->addAction(action); 611 | } 612 | 613 | return ret; 614 | } 615 | 616 | bool MainWindow::makeAction(QAction*& action, QWidget* parent, QString tip, QString icon) 617 | { 618 | bool ret = true; 619 | 620 | action = new QAction("", parent); 621 | 622 | if( action != nullptr ) 623 | { 624 | action->setToolTip(tip); 625 | action->setIcon(QIcon(icon)); 626 | } 627 | else 628 | { 629 | ret = false; 630 | } 631 | 632 | return ret; 633 | } 634 | 635 | //----------------------------------- 636 | bool MainWindow::initStatusBar() 637 | { 638 | QStatusBar* sb = statusBar(); 639 | QLabel* label = new QLabel("D.T.TianSong"); 640 | bool ret = true; 641 | 642 | if( label != nullptr ) 643 | { 644 | sb->addPermanentWidget(new QLabel()); 645 | 646 | statusLabel.setMinimumWidth(150); 647 | statusLabel.setAlignment(Qt::AlignCenter); 648 | statusLabel.setText("length: " + QString::number(0) + " lines: " + QString::number(1)); 649 | sb->addPermanentWidget(&statusLabel); 650 | 651 | statusCursorLabel.setMinimumWidth(150); 652 | statusCursorLabel.setAlignment(Qt::AlignCenter); 653 | statusCursorLabel.setText("Ln: " + QString::number(1) + " Col: " + QString::number(1)); 654 | sb->addPermanentWidget(&statusCursorLabel); 655 | 656 | label->setMinimumWidth(150); 657 | label->setAlignment(Qt::AlignCenter); 658 | sb->addPermanentWidget(label); 659 | } 660 | else 661 | { 662 | ret = false; 663 | } 664 | 665 | return ret; 666 | } 667 | 668 | //--------------------------------- 669 | bool MainWindow::initMainEditor() 670 | { 671 | bool ret = true; 672 | 673 | QPalette p = mainEditor.palette(); 674 | p.setColor(QPalette::Inactive, QPalette::Highlight, p.color(QPalette::Active, QPalette::Highlight)); 675 | p.setColor(QPalette::Inactive, QPalette::HighlightedText, p.color(QPalette::Active, QPalette::HighlightedText)); 676 | mainEditor.setPalette(p); 677 | 678 | mainEditor.setParent(this); 679 | mainEditor.setAcceptDrops(false); 680 | setCentralWidget(&mainEditor); 681 | 682 | connect(&mainEditor, SIGNAL(textChanged()), this, SLOT(onTextChanged())); 683 | connect(&mainEditor, SIGNAL(copyAvailable(bool)), this, SLOT(onCopyAvailable(bool))); 684 | connect(&mainEditor, SIGNAL(redoAvailable(bool)), this, SLOT(onRedoAvailable(bool))); 685 | connect(&mainEditor, SIGNAL(undoAvailable(bool)), this, SLOT(onUndoAvailable(bool))); 686 | connect(&mainEditor, SIGNAL(cursorPositionChanged()), this, SLOT(onCursorPositionChanged())); 687 | 688 | return ret; 689 | } 690 | 691 | QToolBar* MainWindow::toolBar() 692 | { 693 | QToolBar* ret = nullptr; 694 | 695 | const QObjectList& list = children(); 696 | 697 | for(int i=0; i(list[i]); 700 | 701 | if( toolBar != nullptr ) 702 | { 703 | ret =toolBar; 704 | break; 705 | } 706 | } 707 | 708 | return ret; 709 | } 710 | 711 | MainWindow::~MainWindow() 712 | { 713 | } 714 | -------------------------------------------------------------------------------- /Notepad.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2019-02-22T16:20:07 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | QT += printsupport 9 | 10 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 11 | 12 | TARGET = Notepad 13 | TEMPLATE = app 14 | 15 | # The following define makes your compiler emit warnings if you use 16 | # any feature of Qt which has been marked as deprecated (the exact warnings 17 | # depend on your compiler). Please consult the documentation of the 18 | # deprecated API in order to know how to port your code away from it. 19 | DEFINES += QT_DEPRECATED_WARNINGS 20 | 21 | # You can also make your code fail to compile if you use deprecated APIs. 22 | # In order to do so, uncomment the following line. 23 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 24 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 25 | 26 | CONFIG += c++11 27 | 28 | SOURCES += \ 29 | main.cpp \ 30 | MainWindowUI.cpp \ 31 | MainwindowSlots.cpp \ 32 | FindDialog.cpp \ 33 | ReplaceDialog.cpp \ 34 | AbortDialog.cpp \ 35 | AppConfig.cpp 36 | 37 | HEADERS += \ 38 | MainWindow.h \ 39 | FindDialog.h \ 40 | ReplaceDialog.h \ 41 | AbortDialog.h \ 42 | AppConfig.h 43 | 44 | # Default rules for deployment. 45 | qnx: target.path = /tmp/$${TARGET}/bin 46 | else: unix:!android: target.path = /opt/$${TARGET}/bin 47 | !isEmpty(target.path): INSTALLS += target 48 | 49 | RESOURCES += \ 50 | Res.qrc 51 | 52 | RC_FILE = logo.rc 53 | 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qt_Notepad 2 | 3 | 详细参考:https://segmentfault.com/a/1190000018507340 4 | -------------------------------------------------------------------------------- /ReplaceDialog.cpp: -------------------------------------------------------------------------------- 1 | #include "ReplaceDialog.h" 2 | 3 | ReplaceDialog::ReplaceDialog(QWidget* parent, QPlainTextEdit* pText) : FindDialog (parent, pText) 4 | { 5 | initControl(); 6 | connectSlot(); 7 | } 8 | 9 | void ReplaceDialog::initControl() 10 | { 11 | m_replaceLbl.setText("替换为:"); 12 | m_replaceBtn.setText("替换(&R)"); 13 | m_replaceAllBtn.setText("全部替换(&A)"); 14 | 15 | m_layout.removeWidget(&m_matchChkBx); 16 | m_layout.removeWidget(&m_radioGrpBx); 17 | m_layout.removeWidget(&m_cancelBtn); 18 | 19 | m_layout.addWidget(&m_replaceLbl, 1, 0); 20 | m_layout.addWidget(&m_replaceEdit, 1, 1); 21 | m_layout.addWidget(&m_replaceBtn, 1, 2); 22 | 23 | m_layout.addWidget(&m_matchChkBx, 2, 0); 24 | m_layout.addWidget(&m_radioGrpBx, 2, 1); 25 | m_layout.addWidget(&m_replaceAllBtn, 2, 2); 26 | 27 | m_layout.addWidget(&m_cancelBtn, 3, 2); 28 | 29 | setFixedSize(450, 170); 30 | setWindowTitle("替换"); 31 | } 32 | 33 | void ReplaceDialog::connectSlot() 34 | { 35 | connect(&m_replaceBtn, SIGNAL(clicked()), this, SLOT(onReplaceClicked())); 36 | connect(&m_replaceAllBtn, SIGNAL(clicked()), this, SLOT(onReplaceAllClicked())); 37 | } 38 | 39 | void ReplaceDialog::onReplaceClicked() 40 | { 41 | QString target = m_findEdit.text(); 42 | QString to = m_replaceEdit.text(); 43 | 44 | if( (m_pText != nullptr) && (target != "") && (to != "") ) 45 | { 46 | QString selText = m_pText->textCursor().selectedText(); 47 | 48 | if( selText == target ) 49 | { 50 | m_pText->insertPlainText(to); 51 | } 52 | 53 | onFindClicked(); 54 | } 55 | } 56 | 57 | void ReplaceDialog::onReplaceAllClicked() 58 | { 59 | QString target = m_findEdit.text(); 60 | QString to = m_replaceEdit.text(); 61 | 62 | if( (m_pText != nullptr) && (target != "") && (to != "") ) 63 | { 64 | QString text = m_pText->toPlainText(); 65 | 66 | text.replace(target, to, m_matchChkBx.isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive); 67 | 68 | m_pText->clear(); 69 | 70 | m_pText->insertPlainText(text); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /ReplaceDialog.h: -------------------------------------------------------------------------------- 1 | #ifndef REPLACEDIALOG_H 2 | #define REPLACEDIALOG_H 3 | 4 | #include "FindDialog.h" 5 | 6 | class ReplaceDialog : public FindDialog 7 | { 8 | Q_OBJECT 9 | protected: 10 | QLabel m_replaceLbl; 11 | QLineEdit m_replaceEdit; 12 | QPushButton m_replaceBtn; 13 | QPushButton m_replaceAllBtn; 14 | 15 | void initControl(); 16 | void connectSlot(); 17 | 18 | protected slots: 19 | void onReplaceClicked(); 20 | void onReplaceAllClicked(); 21 | 22 | public: 23 | ReplaceDialog(QWidget* parent = nullptr, QPlainTextEdit* pText = nullptr); 24 | }; 25 | 26 | #endif // REPLACEDIALOG_H 27 | -------------------------------------------------------------------------------- /Res.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | pic/copy.png 4 | pic/cut.png 5 | pic/find.png 6 | pic/font.png 7 | pic/goto.png 8 | pic/new.png 9 | pic/open.png 10 | pic/paste.png 11 | pic/print.png 12 | pic/redo.png 13 | pic/replace.png 14 | pic/save.png 15 | pic/saveas.png 16 | pic/status.png 17 | pic/tool.png 18 | pic/undo.png 19 | pic/wrap.png 20 | pic/logo.png 21 | qm/qt_zh_CN.qm 22 | 23 | 24 | -------------------------------------------------------------------------------- /logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/logo.ico -------------------------------------------------------------------------------- /logo.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "logo.ico" -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "MainWindow.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | int main(int argc, char *argv[]) 9 | { 10 | QApplication a(argc, argv); 11 | 12 | // 方式 1 加载添加到工程中的资源文件 13 | QTranslator t; 14 | if( t.load(":/Res/qm/qt_zh_CN.qm") ) 15 | { 16 | a.installTranslator(&t); 17 | } 18 | 19 | // 方式 2 记载 qt 库实例的信息 20 | // QTranslator t; 21 | // if( t.load("qt_zh_CN.qm", QLibraryInfo::location(QLibraryInfo::TranslationsPath)) ) 22 | // { 23 | // a.installTranslator(&t); 24 | // } 25 | 26 | MainWindow* w = MainWindow::NewInstance(); 27 | int ret = -1; 28 | 29 | if( w != nullptr ) 30 | { 31 | if( argc > 1 ) 32 | { 33 | QFileInfo fi(argv[1]); 34 | 35 | if( fi.exists() ) 36 | { 37 | w->openFile(argv[1]); 38 | } 39 | } 40 | 41 | w->show(); 42 | 43 | ret = a.exec(); 44 | 45 | delete w; 46 | } 47 | 48 | return ret; 49 | } 50 | -------------------------------------------------------------------------------- /mainwindowslots.cpp: -------------------------------------------------------------------------------- 1 | #include "MainWindow.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | 39 | QString MainWindow::showFileDialog(QFileDialog::AcceptMode mode, QString title, QString icon) 40 | { 41 | QFileDialog fd(this); 42 | QStringList filters; 43 | QMap map; 44 | const char* filterArray[][2] = 45 | { 46 | {"文本文档(*.txt)", ".txt"}, 47 | {"所有文件(*.*)" , ".*" }, 48 | {nullptr , nullptr} 49 | }; 50 | QString ret = ""; 51 | 52 | for(int i=0; filterArray[i][0]!=nullptr; i++) 53 | { 54 | filters.append(filterArray[i][0]); 55 | map.insert(filterArray[i][0], filterArray[i][1]); 56 | } 57 | 58 | fd.setWindowTitle(title); 59 | fd.setWindowIcon(QIcon(icon)); 60 | fd.setAcceptMode(QFileDialog::AcceptOpen); 61 | fd.setNameFilters(filters); 62 | 63 | if( mode == QFileDialog::AcceptOpen ) 64 | { 65 | fd.setFileMode(QFileDialog::ExistingFile); 66 | } 67 | 68 | if( fd.exec() == QFileDialog::Accepted ) 69 | { 70 | ret = fd.selectedFiles()[0]; 71 | 72 | if( mode == QFileDialog::AcceptSave ) 73 | { 74 | QString postfix = map[fd.selectedNameFilter()]; 75 | 76 | if( (postfix != ".*") && !ret.endsWith(postfix) ) 77 | { 78 | ret = ret + postfix; 79 | } 80 | } 81 | } 82 | 83 | return ret; 84 | } 85 | 86 | void MainWindow::showErrorMessage(QString message) 87 | { 88 | QMessageBox msg(this); 89 | 90 | msg.setWindowTitle("记事本"); 91 | msg.setWindowFlag(Qt::Drawer); 92 | msg.setIcon(QMessageBox::Critical); 93 | msg.setText(message); 94 | msg.setStandardButtons(QMessageBox::Ok); 95 | 96 | msg.exec(); 97 | } 98 | 99 | int MainWindow::showQueryMessage(QString message) 100 | { 101 | QMessageBox msg(this); 102 | 103 | msg.setIcon(QMessageBox::Question); 104 | msg.setWindowTitle("记事本"); 105 | msg.setWindowFlag(Qt::Drawer); 106 | msg.setText(message); 107 | msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); 108 | 109 | return msg.exec(); 110 | } 111 | 112 | void MainWindow::preEditChange() 113 | { 114 | if( m_isTextChanged ) 115 | { 116 | QString path = (m_filePath != "") ? m_filePath : "无标题"; 117 | int r = showQueryMessage(QString("是否将更改保存到\n") + "\"" + path + "\" ?"); 118 | 119 | switch ( r ) 120 | { 121 | case QMessageBox::Yes: 122 | saveCurrentData("保存", m_filePath); 123 | break; 124 | case QMessageBox::No: 125 | m_isTextChanged = false; 126 | break; 127 | case QMessageBox::Cancel: 128 | break; 129 | } 130 | } 131 | } 132 | 133 | void MainWindow::openFileEditor(QString path) 134 | { 135 | if( path != "" ) 136 | { 137 | QFile file(path); 138 | 139 | if( file.open(QIODevice::ReadOnly | QIODevice::Text) ) 140 | { 141 | QTextStream in(&file); 142 | in.setCodec("GBK"); 143 | 144 | mainEditor.setPlainText(in.readAll()); 145 | 146 | file.close(); 147 | 148 | m_filePath = path; 149 | 150 | m_isTextChanged = false; 151 | 152 | setWindowTitle(m_filePath + "- 记事本"); 153 | } 154 | else 155 | { 156 | showErrorMessage(QString("打开文件失败!\n\n") + "\"" + path + "\"。"); 157 | } 158 | } 159 | } 160 | 161 | void MainWindow::openFile(QString path) 162 | { 163 | preEditChange(); 164 | 165 | if( !m_isTextChanged ) 166 | { 167 | openFileEditor(path); 168 | } 169 | } 170 | 171 | void MainWindow::onFileOpen() 172 | { 173 | preEditChange(); 174 | 175 | if( !m_isTextChanged ) 176 | { 177 | QString path = showFileDialog(QFileDialog::AcceptOpen, "打开", ":/Res/pic/logo.png"); 178 | 179 | openFileEditor(path); 180 | } 181 | } 182 | 183 | QString MainWindow::saveCurrentData(QString title, QString path) 184 | { 185 | QString ret = path; 186 | 187 | if( ret == "" ) 188 | { 189 | ret = showFileDialog(QFileDialog::AcceptSave, title, ":/Res/pic/logo.png"); 190 | } 191 | 192 | if( ret != "" ) 193 | { 194 | QFile file(ret); 195 | 196 | if( file.open(QIODevice::WriteOnly | QIODevice::Text) ) 197 | { 198 | QTextStream out(&file); 199 | 200 | out << mainEditor.toPlainText(); 201 | 202 | file.close(); 203 | 204 | setWindowTitle(ret + " - 记事本"); 205 | 206 | m_isTextChanged = false; 207 | } 208 | else 209 | { 210 | showErrorMessage(QString("保存文件失败!\n\n") + "\"。" + ret + "\""); 211 | } 212 | } 213 | 214 | return ret; 215 | } 216 | 217 | void MainWindow::onFileSave() 218 | { 219 | QString path = saveCurrentData("保存", m_filePath); 220 | 221 | if( path != "" ) 222 | { 223 | m_filePath = path; 224 | } 225 | } 226 | 227 | void MainWindow::onFileSaveAs() 228 | { 229 | QString path = saveCurrentData("另存为"); 230 | 231 | if( path != "" ) 232 | { 233 | m_filePath = path; 234 | } 235 | } 236 | 237 | void MainWindow::onFileNew() 238 | { 239 | preEditChange(); 240 | 241 | if( !m_isTextChanged ) 242 | { 243 | mainEditor.clear(); 244 | 245 | m_isTextChanged = false; 246 | 247 | setWindowTitle("新建文本文档 - 记事本"); 248 | } 249 | } 250 | 251 | void MainWindow::onFilePageSetup() 252 | { 253 | m_pPageSetupDlg->exec(); 254 | } 255 | 256 | void MainWindow::onFilePrint() 257 | { 258 | QPrintDialog dlg(this); 259 | 260 | dlg.setWindowTitle("打印"); 261 | 262 | if( dlg.exec() == QPrintDialog::Accepted ) 263 | { 264 | QPrinter* p = dlg.printer(); 265 | 266 | p->setPageLayout(m_pPageSetupDlg->printer()->pageLayout()); 267 | 268 | mainEditor.document()->print(p); 269 | } 270 | } 271 | 272 | void MainWindow::onTextChanged() 273 | { 274 | if( !m_isTextChanged ) 275 | { 276 | setWindowTitle("* " + windowTitle()); 277 | } 278 | 279 | m_isTextChanged = true; 280 | 281 | statusLabel.setText("length: " + QString::number(mainEditor.toPlainText().length()) + " lines: " + QString::number(mainEditor.document()->lineCount())); 282 | } 283 | 284 | void MainWindow::onEditDelete() 285 | { 286 | QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Delete, Qt::NoModifier); 287 | QKeyEvent keyRelease(QEvent::KeyPress, Qt::Key_Delete, Qt::NoModifier); 288 | 289 | QApplication::sendEvent(&mainEditor, &keyPress); 290 | QApplication::sendEvent(&mainEditor, &keyRelease); 291 | } 292 | 293 | void MainWindow::onEditFind() 294 | { 295 | m_pFindDlg->show(); 296 | } 297 | 298 | void MainWindow::onEditFindNext() 299 | { 300 | m_pFindDlg->onFindClicked(); 301 | } 302 | 303 | void MainWindow::onEditReplace() 304 | { 305 | m_pReplaceDlg->show(); 306 | } 307 | 308 | void MainWindow::onEditGoto() 309 | { 310 | bool ok = false; 311 | int ln = QInputDialog::getInt(this, "转到", "行号:", 1, 1, mainEditor.document()->lineCount(), 1, &ok, 312 | Qt::WindowCloseButtonHint | Qt::Drawer); 313 | if( ok ) 314 | { 315 | QString text = mainEditor.toPlainText(); 316 | QTextCursor c = mainEditor.textCursor(); 317 | int pos = 0; 318 | int next = -1; 319 | 320 | for(int i=0; isetChecked(true); 384 | findToolBarAction("自动换行")->setChecked(true); 385 | } 386 | else 387 | { 388 | mainEditor.setLineWrapMode(QPlainTextEdit::NoWrap); 389 | 390 | findMenuBarAction("自动换行")->setChecked(false); 391 | findToolBarAction("自动换行")->setChecked(false); 392 | } 393 | } 394 | 395 | void MainWindow::onViewToolBar() 396 | { 397 | QToolBar* tb = toolBar(); 398 | 399 | bool visible = tb->isVisible(); 400 | 401 | tb->setVisible(!visible); 402 | 403 | findMenuBarAction("工具栏")->setChecked(!visible); 404 | findToolBarAction("工具栏")->setChecked(!visible); 405 | } 406 | 407 | void MainWindow::onViewStatusBar() 408 | { 409 | QStatusBar* sb = statusBar(); 410 | bool visible = sb->isVisible(); 411 | 412 | sb->setVisible(!visible); 413 | 414 | findMenuBarAction("状态栏")->setChecked(!visible); 415 | findToolBarAction("状态栏")->setChecked(!visible); 416 | } 417 | 418 | void MainWindow::onHelpManual() 419 | { 420 | QDesktopServices::openUrl(QUrl("https://segmentfault.com/u/tiansong")); 421 | } 422 | 423 | void MainWindow::onHelpAbort() 424 | { 425 | AbortDialog(this).exec(); 426 | } 427 | 428 | void MainWindow::onCopyAvailable(bool available) 429 | { 430 | findMenuBarAction("复制")->setEnabled(available); 431 | findToolBarAction("复制")->setEnabled(available); 432 | findMenuBarAction("剪切")->setEnabled(available); 433 | findToolBarAction("剪切")->setEnabled(available); 434 | } 435 | 436 | void MainWindow::onRedoAvailable(bool available) 437 | { 438 | findToolBarAction("恢复")->setEnabled(available); 439 | } 440 | 441 | void MainWindow::onUndoAvailable(bool available) 442 | { 443 | findMenuBarAction("撤销")->setEnabled(available); 444 | findToolBarAction("撤销")->setEnabled(available); 445 | } 446 | 447 | void MainWindow::onCursorPositionChanged() 448 | { 449 | int col = 0; 450 | int ln = 0; 451 | int flg = -1; 452 | int pos = mainEditor.textCursor().position(); 453 | QString text = mainEditor.toPlainText(); 454 | 455 | for(int i=0; iisCheckable() && findToolBarAction("工具栏")->isChecked()); 480 | bool sbVisible = (findMenuBarAction("状态栏")->isCheckable() && findToolBarAction("状态栏")->isChecked()); 481 | AppConfig config(mainEditor.font(), size(), pos(), isWrap, tbVisible, sbVisible, this); 482 | 483 | config.store(); 484 | 485 | QMainWindow::closeEvent(event); 486 | } 487 | else 488 | { 489 | event->ignore(); 490 | } 491 | } 492 | 493 | void MainWindow::dragEnterEvent(QDragEnterEvent* event) 494 | { 495 | if( event->mimeData()->hasUrls() ) 496 | { 497 | event->acceptProposedAction(); 498 | } 499 | else 500 | { 501 | event->ignore(); 502 | } 503 | } 504 | 505 | void MainWindow::dropEvent(QDropEvent* event) 506 | { 507 | if( event->mimeData()->hasUrls() ) 508 | { 509 | QList list = event->mimeData()->urls(); 510 | QString path = list[0].toLocalFile(); 511 | QFileInfo fi(path); 512 | 513 | if( fi.isFile() ) 514 | { 515 | preEditChange(); 516 | 517 | if( !m_isTextChanged ) 518 | { 519 | openFileEditor(path); 520 | } 521 | } 522 | else 523 | { 524 | showErrorMessage(QString("对 ") + "\"" + path + "\" 的访问被拒绝。"); 525 | } 526 | } 527 | else 528 | { 529 | event->ignore(); 530 | } 531 | } 532 | 533 | QAction* MainWindow::findMenuBarAction(QString text) 534 | { 535 | QAction* ret = nullptr; 536 | const QObjectList& list = menuBar()->children(); 537 | 538 | for(int i=0; i(list[i]); 541 | 542 | if( men != nullptr ) 543 | { 544 | QList actions = men->actions(); 545 | 546 | for(int j=0; jtext().startsWith(text) ) 549 | { 550 | ret = actions[j]; 551 | 552 | break; 553 | } 554 | } 555 | } 556 | } 557 | 558 | return ret; 559 | } 560 | 561 | QAction* MainWindow::findToolBarAction(QString text) 562 | { 563 | QAction* ret = nullptr; 564 | 565 | QList actions = toolBar()->actions(); 566 | 567 | for(int j=0; jtoolTip().startsWith(text) ) 570 | { 571 | ret = actions[j]; 572 | break; 573 | } 574 | } 575 | 576 | return ret; 577 | } 578 | -------------------------------------------------------------------------------- /pic/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/copy.png -------------------------------------------------------------------------------- /pic/cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/cut.png -------------------------------------------------------------------------------- /pic/find.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/find.png -------------------------------------------------------------------------------- /pic/font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/font.png -------------------------------------------------------------------------------- /pic/goto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/goto.png -------------------------------------------------------------------------------- /pic/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/logo.png -------------------------------------------------------------------------------- /pic/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/new.png -------------------------------------------------------------------------------- /pic/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/open.png -------------------------------------------------------------------------------- /pic/paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/paste.png -------------------------------------------------------------------------------- /pic/print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/print.png -------------------------------------------------------------------------------- /pic/redo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/redo.png -------------------------------------------------------------------------------- /pic/replace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/replace.png -------------------------------------------------------------------------------- /pic/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/save.png -------------------------------------------------------------------------------- /pic/saveas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/saveas.png -------------------------------------------------------------------------------- /pic/status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/status.png -------------------------------------------------------------------------------- /pic/tool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/tool.png -------------------------------------------------------------------------------- /pic/undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/undo.png -------------------------------------------------------------------------------- /pic/wrap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/pic/wrap.png -------------------------------------------------------------------------------- /qm/qt_zh_CN.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocowts/Qt_Notepad/a953d4e8ccdd567c04a34fa520e89f559b0eda37/qm/qt_zh_CN.qm --------------------------------------------------------------------------------