文章目录
- 非模式对话框
- 非模式对话框的特点
- 非模式对话框与QQ聊天窗口开发
- 非模态对话框(Modeless Dialog)和模态对话框(Modal Dialog)区别
- 记事本开发
- CFindReplaceDialog类的成员
- 查找替换(算法分析)
- 使用RichEdit控件 开发Goto(转到)功能
- 对话框颜色管理
- WM_CTLCOLOR控件
- 记事本中文字颜色和背景颜色功能开发
非模式对话框
非模式对话框的特点
a)调用CDialog::Create函数实现,例如:QQ的聊天框,记事本的查找等。
b)非阻塞,对象的生命期必须足够,否则就析构时摧毁了。
c)可以采用堆空间申请多例模式,也可以用全局或者成员。
d)EndDialog只对模式对话框有效,对非模式对话框无效,如果要摧毁调用DestroyWindow
(只是隐藏了窗口,不会摧毁窗口,ShowWindow还可以再重新显示)
e)如果要让非模式对话框与主窗口形成兄弟关系,在任务栏中有图标,
就在pParent参数中代入GetDesktopWindow()
非模式对话框与QQ聊天窗口开发
CChatceDlg.cpp
void CChatceDlg::OnBnClickedCancel()
{
DestroyWindow(); //真正的摧毁窗口
// EndDialog(IDCANCEL); //只对模式对话框有效,对非模式对话框无效,只是隐藏窗口,不会摧毁窗口showWindows可以再次显示出来
//CDialogEx::OnCancel();
}
void CChatceDlg::PostNcDestroy()
{
CDialogEx::PostNcDestroy();
//用于堆空间 delet this;
}
CMainDlg.h
#include "CChatceDlg.h"
class CMainDlg : public CDialogEx
{
// 构造
CChatceDlg m_dlgChat;
}
CMainDlg.cpp
拖动客户区
//在窗口过程中处理鼠标在非客户区(非工作区)的点击事件。
//它用于确定鼠标点击的位置位于窗口的哪个区域,比如标题栏、边框、系统菜单等
LRESULT CMainDlg::OnNcHitTest(CPoint point) //拖动客户区
{
ScreenToClient(&point);
if (point.y<30)
return HTCAPTION; //表示鼠标点击在标题栏上,用于移动窗口
return CDialogEx::OnNcHitTest(point);
}
OnNcHitTest()用于处理WM_NCHITTEST消息,该消息用于确定鼠标点击的位置。返回值可以是以下之一:
HTERROR:在窗口的错误区域
HTTRANSPARENT:在透明区域
HTNOWHERE:在窗口的非客户区
HTCLIENT:在窗口的客户区
HTCAPTION:在窗口的标题栏
HTSYSMENU:在窗口的系统菜单
HTMENU:在窗口的一般菜单
HTLEFT、HTTOP、HTRIGHT、HTBOTTOM:在窗口的边界区域
HTBOTTOMLEFT、HTTOPLEFT、HTBOTTOMRIGHT、HTTOPRIGHT:在窗口的角落区域
通过重写OnNcHitTest()函数,可以根据返回值来实现特定的行为,例如拖动窗口、更改窗口大小等。
#include "CAboutDlg.h"
void CMainDlg::OnBnClickedAbout()
{
CAboutDlg dlg;
dlg.DoModal(); //模式对话框
}
#include "CChatceDlg.h"
void CMainDlg::OnBnClickedChat() //非模式对话框 多例模式
{
//auto pDlg = new CChatceDlg; //加强了生命周期
//pDlg->Create(IDD_CHAT, this);
//pDlg->ShowWindow(SW_SHOW);
if(!m_dlgChat)
m_dlgChat.Create(IDD_CHAT, GetDesktopWindow());
// GetDesktopWindow()使用这个函数使得其和主窗口是一个父亲
m_dlgChat.ShowWindow(SW_SHOW);
}
//单例模式 对象只能有一个 可以用全局便利 成员变量里
非模态对话框(Modeless Dialog)和模态对话框(Modal Dialog)区别
-
控制权:模态对话框会阻塞用户与应用程序的其他部分进行交互,直到对话框关闭为止。而非模态对话框不会阻塞用户与应用程序的其他部分的交互,可以同时操作多个窗口或控件。
-
用户焦点:在模态对话框中,用户无法将焦点切换到其他应用程序的窗口或控件上,直到对话框关闭。而在非模态对话框中,用户可以在对话框和其他窗口或控件之间自由切换焦点。
-
程序控制:在模态对话框中,对话框被关闭后会返回到调用它的代码处,可以根据对话框的返回值或状态进行相应的处理。而在非模态对话框中,对话框关闭后不会立即返回到调用它的代码处,需要通过消息处理机制来处理对话框的事件和状态。
-
多任务处理:由于模态对话框阻塞了用户与应用程序的其他部分的交互,因此在处理耗时任务时可以使用模态对话框来防止用户对其他部分的操作。而非模态对话框通常用于需要同时操作多个窗口或控件的情况。
总的来说,模态对话框适合用于需要用户必须完成某个操作才能继续的情况,而非模态对话框适合用于需要用户可以同时进行其他操作的情况。选择使用哪种对话框类型要根据具体的应用场景和需求来决定。
记事本开发
CFindReplaceDialog类的成员
BOOL SearchDown() const; // 向下打勾
BOOL FindNext() const; // TRUE if command is find next
BOOL MatchCase() const; //大小写匹配
BOOL MatchWholeWord() const; // 全字匹配
BOOL ReplaceCurrent() const; // TRUE if replacing current string
BOOL ReplaceAll() const; // TRUE if replacing all occurrences
BOOL IsTerminating() const; // TRUE if terminating dialog
CString GetReplaceString() const;// get replacement string
CString GetFindString() const; // get find string
CFindReplaceDialog的按钮消息:
a)通过派生类截获消息,用Spy找到每个按钮ID
b)不通过派生类截获消息,用主窗口截获消息.
ON_REGISTERED_MESSAGE(WM_FINDREPLACE, &CMainDlg::OnFindReplace)
查找替换(算法分析)
获取选中的文字
CString CMainDlg::GetSelText()
{
CString str;
m_edit.GetWindowText(str);
int nStart, nEnd;
m_edit.GetSel(nStart, nEnd);
if(nEnd<=nStart)
return CString();
return str.Mid(nStart, nEnd - nStart);
}
创建CFindReplaceDialog
//虚函数基本都是重写 必须参数和基类一样 ,如果加了参数 不一致时它就不执行了 跟基类不同叫重定义
void CMainDlg::OnEditFind()
{
if (IsWindow(m_pFRDlg->GetSafeHwnd()))
m_pFRDlg->DestroyWindow();
m_pFRDlg = new CFindReplaceDialog;
m_pFRDlg->Create(TRUE,GetSelText());
}
void CMainDlg::OnEditReplace()
{
if (IsWindow(m_pFRDlg->GetSafeHwnd()))
m_pFRDlg->DestroyWindow();
m_pFRDlg = new CFindReplaceDialog;
m_pFRDlg->Create(FALSE, GetSelText());
}
查找替换
LRESULT CMainDlg::OnFindReplace(WPARAM wParam, LPARAM lParam){
if (m_pFRDlg->IsTerminating())
return false;
if (m_pFRDlg->ReplaceAll())
ReplaceAll();
if (m_pFRDlg->ReplaceCurrent()) {
ReplaceCurrent();
AfxMessageBox(_T("替换")); }
if (m_pFRDlg->FindNext())
if (m_pFRDlg->SearchDown())
SerachDown();
else
SerachUp();
return LRESULT();
}
向下查找算法
void CMainDlg::SerachDown(){
if (!IsWindow(m_pFRDlg->GetSafeHwnd()))
return;
CString sText;
m_edit.GetWindowText(sText);
CString str = m_pFRDlg->GetFindString();
int nStart, nEnd;
m_edit.GetSel(nStart, nEnd);
int n = sText.Find(str, nEnd);
if (n<0){
AfxMessageBox(_T("找不到 ") + str); return;
}
m_edit.SetSel(n, n + str.GetLength());
m_edit.GetFocus();
}
向上查找算法
void CMainDlg::SerachUp()
{
if (!IsWindow(m_pFRDlg->GetSafeHwnd()))
return;
CString sText;
m_edit.GetWindowText(sText);
CString str = m_pFRDlg->GetFindString();
if (!m_pFRDlg->MatchCase()) //区分大小写, 设置之后只能查找小写
{
str.MakeLower();
sText.MakeLower();
}
int nStart, nEnd;
m_edit.GetSel(nStart, nEnd)
str.MakeReverse();
sText.MakeReverse();
int nLen = sText.GetLength();
int n = sText.Find(str, nLen-nStart);
if (n < 0)
{
AfxMessageBox(_T("找不到 ") + str);
return;
}
nEnd = nLen - n;
nStart = nEnd - str.GetLength();
m_edit.SetSel(nStart, nEnd);
m_edit.GetFocus();
}
替换全部算法
void CMainDlg::ReplaceAll()
{
CString sText, sOld, sNew;
sOld = m_pFRDlg->GetFindString();
sNew = m_pFRDlg->GetReplaceString();
m_edit.GetWindowText(sText);
BOOL bMathCase = m_pFRDlg->MatchCase();
int nStart, nEnd;
m_edit.GetSel(nStart, nEnd);
if (bMathCase)
{
sText.Replace(sOld, sNew);
m_edit.SetWindowText(sText);
m_edit.SetSel(nStart, nEnd);
}
}
使用RichEdit控件 开发Goto(转到)功能
CGotoDlg
CGotoDlg.h
class CGotoDlg : public CDialogEx
{
DECLARE_DYNAMIC(CGotoDlg)
public:
CGotoDlg(CWnd* pParent = nullptr); // 标准构造函数
virtual ~CGotoDlg();
int m_nLine, m_nLines; //当前第几行,总共第几行
}
CGotoDlg.cpp
初始化对话框
BOOL CGotoDlg::OnInitDialog(){
CDialogEx::OnInitDialog();
SetDlgItemInt(IDC_LINE, m_nLine);
CString str;
str.Format(_T("行号(1-%d)(&L)"), m_nLines);
SetDlgItemText(IDC_LINES, str);
auto pEdit = (CRichEditCtrl*)GetDlgItem(IDC_LINE);
pEdit->SetEventMask(pEdit->GetEventMask() | ENM_CHANGE);
m_stop.SetParent(pEdit);
CRect rect;
pEdit->GetClientRect(rect);
rect.left = rect.right - rect.Height();
int nDiff = rect.Width() - 15;
if (nDiff > 1)
{
nDiff /= 2;
rect.DeflateRect(nDiff, nDiff);
}
m_stop.MoveWindow(rect, FALSE);
return TRUE; // return TRUE unless you set the focus to a control
}
当改变行号时,显示或者隐藏m_stop图标(判断行号是否越界)
void CGotoDlg::OnChangeLine()
{
int n = GetDlgItemInt(IDC_LINE);
BOOL bEnable = (n > 0 && n <= m_nLines);
m_stop.ShowWindow(bEnable ? SW_HIDE : SW_SHOW);
GetDlgItem(IDOK)->EnableWindow(bEnable);
}
点击ok获取当前行号
void CGotoDlg::OnBnClickedOk()
{
m_nLine = GetDlgItemInt(IDC_LINE);
EndDialog(IDOK);
}
跳转行号导航
void CMainDlg::OnEditGoto(){
CGotoDlg dlg;
int nStart, nEnd;
m_edit.GetSel(nStart, nEnd);
dlg.m_nLines = m_edit.GetLineCount();
dlg.m_nLine = m_edit.LineFromChar(nEnd)+1; //lineIndex LineFromChar获得选中的字符数进行转换
if (dlg.DoModal() == IDCANCEL)
return;
int nChar = m_edit.LineIndex(dlg.m_nLine)-1; //用于获取指定行的起始字符的索引。行号是从1开始的,而字符索引是从0开始的。因此,在使用返回的索引进行操作时,可能需要将其减去1以适应零基索引。
m_edit.SetSel(nChar, nChar);//设置编辑控件中的选定内容,两个参数分别是起始和结束位置的字符索引
}
/*要清除编辑控件中的选定内容,可以将起始位置和结束位置都设置为相同的值
m_edit.SetSel(-1, 0);
上述代码将选定内容的起始位置设置为-1,结束位置设置为0,这将导致编辑控件中的选定内容被清除。*/
对话框颜色管理
WM_CTLCOLOR控件
1、颜色管理:
a)COLORREF类型是4个字节,其中从低到高的3字节代表:Red Green Blub
b)把分量合成COLORREF类型:COLORREF col = RGB(88,99,222);
#define RGB(r,g,b) ((COLORREF)(((BYTE)®|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))
c)把COLORREF拆分成3个分量数值:
#define GetRValue(rgb) (LOBYTE(rgb))
#define GetGValue(rgb) (LOBYTE(((WORD)(rgb)) >> 8))
#define GetBValue(rgb) (LOBYTE((rgb)>>16))
2、通用控件颜色管理:WM_CTLCOLOR消息
a)此消息并非完全通用,只适合于附录1中的控件类型。
(按钮,编辑框,静态文字,列表框ListBox)
b)很多复杂的控件包括树形控件,ListCtrl不支持。
就如同CDateTimeCtrl调用SetWindowText不好使。
附录1:
WM_CTLCOLOR支持的种类(UINT nCtlColor )
Contains one of the following values, specifying the type of control:
CTLCOLOR_BTN Button control
CTLCOLOR_DLG Dialog box
CTLCOLOR_EDIT Edit control
CTLCOLOR_LISTBOX List-box control
CTLCOLOR_MSGBOX Message box
CTLCOLOR_SCROLLBAR Scroll-bar control
CTLCOLOR_STATIC Static control
static CBrush brButton(0xff00);
static CBrush brEdit1(RGB(255,255,0));
static CBrush brEdit2(RGB(0,255,255));
static CBrush brDlg(RGB(255,122,123));
HBRUSH CSetColrDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
switch (nCtlColor)
{
case CTLCOLOR_BTN:
pDC->SetTextColor(255);
return brButton;
case CTLCOLOR_DLG:
pDC->SetBkColor(RGB(255,0,255));
return brDlg;
case CTLCOLOR_EDIT:
if (pWnd->GetDlgCtrlID() ==IDC_EDIT1)
{
pDC->SetTextColor(0xff00);
pDC->SetBkColor(0xff0000);
return brEdit1;
}
if (pWnd->GetDlgCtrlID() == IDC_EDIT2)
{
pDC->SetTextColor(255); //文字背景颜色和文字前景色
pDC->SetBkColor(0x00ffff);
return brEdit2;
}
}
return hbr;
}
记事本中文字颜色和背景颜色功能开发
定义相应变量
加载注册表信息
void CMainDlg::LoadSetting()
{
m_clback = theApp.GetProfileInt(_T("SETTINGS"), _T("BACK_COLOR"), 0xffffff);
m_clText = theApp.GetProfileInt(_T("SETTINGS"), _T("TEXT_COLOR"), 0);
m_brBack.DeleteObject();
m_brBack.CreateSolidBrush(m_clback);
}
对文字进行设置颜色
void CMainDlg::OnFormatText()
{
CColorDialog dlg(m_clText, CC_FULLOPEN);
if (dlg.DoModal() == IDCANCEL)
return;
m_clText = dlg.GetColor();
theApp.WriteProfileInt(_T("SETTINGS"), _T("TEXT_COLOR"), m_clText);
}
设置背景色
void CMainDlg::OnFormatBack()
{
CColorDialog dlg(m_clback, CC_FULLOPEN);
if (dlg.DoModal() == IDCANCEL)
return;
COLORREF color = dlg.GetColor();
if (color!=m_clback)
{
m_clback = color;
m_brBack.DeleteObject();
m_brBack.CreateSolidBrush(m_clback);
theApp.WriteProfileInt(_T("SETTINGS"), _T("BACK_COLOR"),m_clback);
}
}
对IDC_TEXT设置背景色与文字颜色
HBRUSH CMainDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
if (pWnd->GetDlgCtrlID() ==IDC_TEXT)
{
pDC->SetTextColor(m_clText);
pDC->SetBkColor(m_clback);
return m_brBack;
}
return hbr;