ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

MFC实现Txt03之CRichEditView实现文本拖拽功能

2022-08-17 11:03:45  阅读:125  来源: 互联网

标签:文件 CRichEditView 函数 响应 MFC pRichEdit 文本 拖拽 Txt03


02实现了基本的Txt操作功能,现在还想加一个拖拽功能,即把一个Txt文本拖拽进来,然后自动打开该文本。(参考Txt拖拽,不理解的话就试一下,就是把另一个Txt拖到一个已打开的Txt中)


 (★★★★这里请千万注意,我们使用的RichEdit是视图继承的CRichEditView,而不是一个RichEdit控件,所以你会发现很多资料介绍的不适用,区别还是有的★★★★)


 知道需求了,那就去查资料呗,嘿,还真有这种功能,WM_DROPFILES消息------>>>>OnDropFiles函数;

这不就简单了,直接解决问题,开写代码,先写一个MessageBox来测试一下。。。。。显然失败了,无法弹出这个用做提示的对话框。。。。怎么办,难道不是这样的吗?---  CRichEditView如何实现文件的拖拽功能?

1 void CTxt0721View::OnDropFiles(HDROP hDropInfo)
2 {
3     // TODO: 在此添加消息处理程序代码和/或调用默认值
4     MessageBox(L"CTxt0721View    +     这不是为难老实人?");
5     CRichEditView::OnDropFiles(hDropInfo);
6 }

。。。难搞啊,然后又发现了一个EN_DROPFILES,这简直是救星,山重水复疑无路,屁用没有,还是不会响应。。。看一下这个消息对应的程序,它的使用提示告诉我们什么

void CTxt0721View::OnEnDropfiles(NMHDR *pNMHDR, LRESULT *pResult)
{
    ENDROPFILES *pEnDropFiles = reinterpret_cast<ENDROPFILES *>(pNMHDR);
    // TODO:  控件将不发送此通知,除非您重写
    // CRichEditView::OnInitDialog() 函数,以将 EM_SETEVENTMASK 消息发送
    // 到该控件,同时将 ENM_DROPFILES 标志“或”运算到 lParam 掩码中。

    // TODO:  在此添加控件通知处理程序代码

    *pResult = 0;
}

CRichEditView::OnInitDialog() 函数,OnInitDialog() 这是什么函数,。。。这不是对话框的初始化函数吗,。。在View怎么重写这个函数。。。。欸,又是走不通的路,真的是没办法。(这里反而透露出了如果在对话框中使用RichEdit控件该如何实现这个拖拽功能,但是对本文无用)


 后来我想,View不行,那我去MainFrame中试试,看看它能不能响应,

好家伙,CMainFrame中真的可以响应WM_DROPFILES消息,不过存在一点点BUG,那就是只能在框架处响应这个消息,在客户区还是无法响应,不过好歹算是解决了一部分问题,(关于怎么写函数OnDropFiles,以及怎么得到文件路径,自行百度,一堆),由于设计的文本路径 ,文本内容这些变量都是View中的成员变量,所以需要在MainFrame中获取到View指针,对这些数据进行操作,恰好有这个函数(CFrameWnd::GetActiveView ,  调用此成员函数以获取指向附加到框架窗口 (CFrameWnd) 的活动视图(如果有)的指针。)

 1 void CMainFrame::OnDropFiles(HDROP hDropInfo)
 2 {
 3     // TODO: 在此添加消息处理程序代码和/或调用默认值
 4 
 5 //    MessageBox(L"CMainFrame::      +     这不是为难老实人?");    
 6 //  获取文件路径
 7     wchar_t szFilePathName[_MAX_PATH + 1] = { 0 }; 
 8     UINT nNumOfFiles = DragQueryFile(hDropInfo, 0xFFFFFFFF, NULL, 0); //得到文件个数 
 9     if (nNumOfFiles > 1)
10     {
11         MessageBox(L"Only the first file is loaded!");
12     }
13     DragQueryFile(hDropInfo, 0, szFilePathName, _MAX_PATH);
14 //    MessageBox(szFilePathName);
15 
16     CTxt0721View * pView = (CTxt0721View *)GetActiveView();
17 //    MessageBox(L"我是文件内容" + pView->TxtFileString);
18     DragFinish(hDropInfo);
19 // ------------------------根据得到的文件路径调用 打开 函数即可
20     pView->DragAndDropOpenFile(szFilePathName);
21     pView->Number_QueryAccept = 0;            // 控制拖拽事件响应函数,框架处响应不一致,故而直接置零,控制视图处响应
22 
23     CFrameWndEx::OnDropFiles(hDropInfo);
24 }

。。。现在问题是怎么处理客户区拖拽问题。。。。。

找资料(虽然不知道怎么找资料,。。。。也不知道具体该查找什么关键字。。。反正就是找资料,广泛找,。。。皇天不负有心人,总算找到了(主要是不懂,就算找到了也可能因为看不懂而错过。。。。))

为什么CRichEditView 类无法响应OnDrop() OnDragOver()等拖放函数 急!通宵等答案 (和我一样的问题)

 既然提到了这个函数,那我们就去试试,反正什么思路都没有。。。发现问题了,这个函数确实在这中间起到了作用,拖拽过去会产生一个图标,而这个图标的产生就由QueryAcceptData控制,那是不是可以重写这个函数,截断它显示图标,改让他显示Txt的文本内容呢?理论上来说是可以的,于是从这个函数入手

通过研究,发现在一次拖拽过程中,这个函数会响应两次(当鼠标把文件拖到客户区时响应一次,当鼠标左键松开时,响应第二次)但是我们只需要它响应一次,这只能手动控制了,没办法

因此,在View.h中添加了一个变量int  Number_QueryAccept;用来专门记录调用了QueryAcceptData函数多少次,并设定,只有当Number_QueryAccept是偶数时,才做出响应,打开Txt文本。

问题又来了,前面不是在CMainFrame中响应了WM_DROPFILES消息,发现,如果是把文件拖拽到框架上,那么只会响应一次QueryAcceptData函数,这又给我们写代码的人添加工作了,由此根据这个特性,设定每次调用QueryAcceptData函数,标记Number_QueryAccept就自动加一,而当调用了CMainFrame::OnDropFiles函数时,标记Number_QueryAccept重置为0,这样解决了两者调用次数不同的问题。

事到如今,还有一个问题,怎么提取出文件路径,目前最有用的参数就是LPDATAOBJECT lpdataobj了,怎么提取出文件路径来呢?(查资料呗,我又不会)(求教怎么通过DoDragDrop参数获取源文件路径

照着抄当然时无法提取到文件路径的,其实当初这个地方查了很久,总是不知道查什么关键词。。。。不过最后还是找到了,然后我现在忘记了。。。。(真的找不到了。。。好难过。。。所以没有链接了,不是我不想给原作者链接。。。。。)

 QueryAcceptData函数:(调用DragAndDropOpenFile函数直接打开文本)

 1 /*
 2 重载函数CRichEditView::QueryAcceptData   
 3 QueryAcceptData由框架调用以将对象粘贴到丰富的编辑中。(文件拖拽功能
 4 1.文件拖到框架上,响应此处,然后会自动调用CMainFrame中OnDropFiles(HDROP hDropInfo)函数处理
 5 2.文件拖到视图上,响应此处,但不会调用函数处理
 6 */
 7 HRESULT CTxt0721View::QueryAcceptData(LPDATAOBJECT lpdataobj, CLIPFORMAT* lpcfFormat, DWORD dwReco, BOOL bReally, HGLOBAL hMetaFile)
 8 {
 9     // TODO: 在此添加专用代码和/或调用基类
10 
11     // 控制拖拽响应 Number_QueryAccept 偶数响应
12     Number_QueryAccept++;
13 
14     // 获取当前界面文字
15     pRichEdit->GetWindowText(TxtFileString);
16 
17     // 以下用于获取拖拽文件的文件路径
18     FORMATETC fmt = { CF_HDROP,0,DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
19     STGMEDIUM stgmed = { 0 };
20     if (SUCCEEDED(lpdataobj->GetData(&fmt, &stgmed)))
21     {
22         HDROP hDropInfo = (HDROP)::GlobalLock(stgmed.hGlobal);
23         wchar_t szFilePathName[_MAX_PATH + 1] = { 0 };
24         UINT nNumOfFiles = DragQueryFile(hDropInfo, 0xFFFFFFFF, NULL, 0); //得到文件个数 
25         DragQueryFile(hDropInfo, 0, szFilePathName, _MAX_PATH);
26         // 打开文件 与否
27         if (Number_QueryAccept % 2 == 0)                    // 控制一下,QueryAcceptData 会被调用两次,
28         {
29             if (DragAndDropOpenFile(szFilePathName) == false)
30             {
31                 // 是否正确打开拖拽文件 -- false 没有打开
32                 // 重新显示Txt文本 -- 干掉出现的那个图标
33                 pRichEdit->SetSel(0, -1);                    // 文本全选
34                 // 使用下面两行的目的是为了替换的时候不至于出现 文字全选而出现的颜色,
35                 pRichEdit->Clear();
36                 pRichEdit->SetSel(0, -1);
37                 // 替换选中的文本,即输入读取的文本信息
38                 pRichEdit->ReplaceSel(TxtFileString);
39 //                MessageBox(L"这么晚?");
40             }
41         }
42         GlobalUnlock(stgmed.hGlobal);
43         ReleaseStgMedium(&stgmed);
44 //        return S_OK;        // 会出现图标资源
45         return S_FALSE;        // 不会出现图标资源
46     }
47     else
48     {
49         // 当拖拽其他,如文字时,调用其原本的函数,用于响应,拖拽文件,手写函数响应
50         return CRichEditView::QueryAcceptData(lpdataobj, lpcfFormat, dwReco, bReally, hMetaFile);
51     }
52 }
 1 /*
 2 功能:实现文件拖拽时的打开文本的功能 --> 实现拖拽文本所需功能
 3 1.获取 并 保存--文件路径
 4 2.保存当前文本 -- 询问 保存与否 ,取消 -- 退出文件拖拽这个事件
 5 3.直接打开拖拽而来的文件
 6 */
 7 bool CTxt0721View::DragAndDropOpenFile(CString FileLoad)
 8 {
 9     // TODO: 在此添加命令处理程序代码
10     // CRichEditCtrl *pRichEdit = &GetRichEditCtrl();
11     // 保存当前文本
12     if (CTxt0721View::AskToSaveOrNot(pRichEdit) == false)
13         return false;
14 
15     CTxt0721View::InitCTxt0721View();            // 重置各种参数
16     TxtFileLoad = FileLoad;                        // 保存拖拽文件路径
17     IsFileNew = false;                            // 非新建文件
18     CTxt0721View::ReadFileContents();            // TxtFileString -- 读取文件内容,
19 
20     // 显示Txt文本
21     pRichEdit->SetSel(0, -1);                    // 文本全选
22     // 使用下面两行的目的是为了替换的时候不至于出现 文字全选而出现的颜色,
23     pRichEdit->Clear();
24     pRichEdit->SetSel(0, -1);
25     // 替换选中的文本,即输入读取的文本信息
26     pRichEdit->ReplaceSel(TxtFileString);
27     // 用于记录文本是否修改过,FALSE未修改,刚打开的文档默认未修改
28     pRichEdit->SetModify(FALSE);
29     return true;
30 }
View Code

关于从LPDATAOBJECT lpdataobj中获取到文件路径,真的找了很久,现在竟然找不到了。。。。真难过。。

不过至此,问题差不多就解决了,能够在整个界面上都可以实现拖拽,

解决完问题之后,才发现好多资料。。。真需要的时候找不到。。。这也是没办法,关键在于不知道应该查找什么内容,只知道大概查找方向而不是精确的点,这点就是问题所在了,可是没有广泛的了解又哪里找得到关键点。。。没办法喽,学习的必经之路


 总结:在CRichEditView中,无法使用WM_DROPFILES消息,但是在CMainFrame中还是可以正常使用的,但是功能只限于框架部分,不包括客户区;
可以通过调用QueryAcceptData函数来实现客户区的拖拽响应,利用LPDATAOBJECT lpdataobj来获取文件路径。

 

2022-08-17(0726.。。)

标签:文件,CRichEditView,函数,响应,MFC,pRichEdit,文本,拖拽,Txt03
来源: https://www.cnblogs.com/2015-16/p/16588316.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有