文本编辑器——记事本类型的应用,可以打开、编辑、保存文本文档。可以增加单词高亮和其它的一些特性。
效果图:
//CGEditorDlg成员
public:
CString m_filename;//打开文件名
CRichEditCtrl m_richedit;//富文本框控件
CString m_text;//富文本框中的文本
std::set<std::wstring> blueText;//需要变蓝色的单词
std::set<std::wstring> redText;//需要变红色的单词
afx_msg void OnBnClickedOk();
afx_msg void OnBnClickedCancel();
afx_msg void OnBnClickedButtonsearch();//浏览按钮消息处理
afx_msg void OnEnChangeRichedit();//富文本框文本变化时消息处理
afx_msg void OnBnClickedButtonsave();//保存按钮消息处理
afx_msg void OnEnMsgfilterRichedit(NMHDR *pNMHDR, LRESULT *pResult);//筛选键盘消息,处理tab键
BOOL CGEditorDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
m_richedit.SetEventMask(m_richedit.GetEventMask() | ENM_CHANGE | ENM_KEYEVENTS);
blueText.clear();
blueText.insert(L"int");
blueText.insert(L"double");
blueText.insert(L"float");
blueText.insert(L"void");
blueText.insert(L"char");
redText.clear();
redText.insert(L"include");
redText.insert(L"using");
redText.insert(L"namespace");
redText.insert(L"return");
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CGEditorDlg::OnBnClickedButtonsearch()
{
// TODO: 在此添加控件通知处理程序代码
CFileDialog dlg(TRUE, TEXT("cpp"), TEXT("text"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
TEXT("C源文件(*.c)|*.c|C++源文件(*.cpp)|*.cpp|文本文件(*.txt)|*.txt||"));//open
if (IDOK == dlg.DoModal())
{
//MessageBox(dlg.GetPathName());
wifstream ifs(dlg.GetPathName().GetBuffer());
if (!ifs.is_open())
{
MessageBox(dlg.GetPathName(), TEXT("文件打开失败"));
}
ifs.imbue(std::locale("chs"));
istreambuf_iterator<wchar_t> beg(ifs), end;
wstring text(beg, end);
m_text = text.c_str();
m_text.Replace(TEXT("\t"), TEXT(" "));
m_text.Replace(TEXT("\n"), TEXT("\r\n"));
m_filename = dlg.GetPathName();
ifs.close();
UpdateData(FALSE);
OnEnChangeRichedit();
SetWindowText(dlg.GetPathName());
}
}
void CGEditorDlg::OnEnChangeRichedit()
{
// TODO: 如果该控件是 RICHEDIT 控件,它将不
// 发送此通知,除非重写 CDialogEx::OnInitDialog()
// 函数并调用 CRichEditCtrl().SetEventMask(),
// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
long start, end;
m_richedit.GetSel(start, end);//保存光标位置
CHARFORMAT2 fm1, fm2;
memset(&fm1, 0, sizeof(fm1));
memset(&fm2, 0, sizeof(fm2));
//CPoint pos = m_richedit.GetCaretPos();
m_richedit.GetDefaultCharFormat(fm1);
m_richedit.GetDefaultCharFormat(fm2);
m_richedit.SetSel(0, -1);
m_richedit.SetSelectionCharFormat(fm2);
fm1.cbSize = sizeof(fm1);
fm1.dwMask = CFM_COLOR;
fm1.dwEffects &= ~CFE_AUTOCOLOR;
setlocale(LC_ALL, "chs");
m_text.Replace(TEXT("\r\n"), TEXT("\n"));
wstring word;
wstring text(m_text.GetBuffer());
wstring::size_type index1 = 0;
wstring::size_type index2 = -1;
while ((index1 = text.find_first_of(L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", index1)) != wstring::npos)
{
index2 = text.find_first_not_of(L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", index1);
word = text.substr(index1, index2-index1);//切分出每个单词
if (blueText.find(word) != blueText.end())
{
fm1.crTextColor = RGB(0, 0, 255);
m_richedit.SetSel(index1,index2);
m_richedit.SetSelectionCharFormat(fm1);
}
else if (redText.find(word) != redText.end())
{
fm1.crTextColor = RGB(255, 0, 0);
m_richedit.SetSel(index1, index2);
m_richedit.SetSelectionCharFormat(fm1);
}
if (index2 == wstring::npos)
break;
else
index1 = index2 + 1;
}
//处理一下注释,因为这是后来加上去的,所以在这里处理,整体效率又被拖低了
index1 = index2 = 0;
while ((index1 = text.find(wstring(L"\/\/"), index1)) != wstring::npos)
{
index2 = text.find_first_of(L"\n", index1);
fm1.crTextColor = RGB(0, 255, 0);
m_richedit.SetSel(index1, index2);
m_richedit.SetSelectionCharFormat(fm1);
if (index2 == wstring::npos)
break;
else
index1 = index2;
}
m_richedit.SetSel(start, end);
//m_richedit.SetCaretPos(pos);
//m_richedit.SetSelectionCharFormat(fm2);//???
}
void CGEditorDlg::OnBnClickedButtonsave()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
if (IDOK == MessageBox(TEXT("确定保存?"), TEXT("保存")))
{
ofstream ofs(m_filename.GetBuffer(),ios::trunc);
if (!ofs.is_open())
{
MessageBox(TEXT("文件保存失败!"));
ofs.close();
return;
}
m_text.Replace(TEXT("\r\n"),TEXT("\n"));
m_text.Replace(TEXT(" "), TEXT("\t"));
setlocale(LC_ALL, "chs");
ofs.write(CStringA(m_text).GetBuffer(), wcstombs(NULL,m_text.GetBuffer(),NULL));
ofs.close();
}
}
void CGEditorDlg::OnEnMsgfilterRichedit(NMHDR *pNMHDR, LRESULT *pResult)
{
MSGFILTER *pMsgFilter = reinterpret_cast<MSGFILTER *>(pNMHDR);
// TODO: 控件将不发送此通知,除非您重写
// CDialogEx::OnInitDialog() 函数,以将 EM_SETEVENTMASK 消息发送
// 到该控件,同时将 ENM_KEYEVENTS 或 ENM_MOUSEEVENTS 标志
//“或”运算到 lParam 掩码中。
// TODO: 在此添加控件通知处理程序代码
if (pMsgFilter->msg == WM_KEYDOWN && pMsgFilter->wParam == VK_TAB)
{
UpdateData(TRUE);
long start, end;
m_richedit.GetSel(start, end);
//CPoint pos = m_richedit.GetCaretPos();
m_text += TEXT(" ");
UpdateData(FALSE);//原来这里会改变光标的位置!!!
//m_richedit.SetCaretPos(pos);
m_richedit.SetSel(start+4, end+4);
OnEnChangeRichedit();
*pResult = 1;
}
else
*pResult = 0;
}