MFC如何在树形图边上添加动态小地图

https://www.jianshu.com/p/7b1d828bf5db (简书无法识别缩进的。。。早知道先在博客园发了)

(转载请注明出处)

作者:梦镜谷雨


萌新第一次写文章,请多多包涵。末尾附上相应代码(PS公司繁体系统所以部分注释繁体请别介意)。

第一次接触MFC时做的一个小项目上有做个树形图边上带小地图的需求。(IDE:VS2010)

大四刚实习时写的,当时网上没找到现成的,打算记录下来也算篇技术谈不上的思路吧。

快2019了打算开始试着以后多记录点东西,因为本人大学微电子专业不是软件方向想往这边发展的,代码里东西这时文章写到一半自己看着都感觉很糟糕(╯﹏╰),也算是记录个黑历史吧能实现功但糟糕就是糟糕。当时第一次学自绘没想着要写文章记录下来,参考了些网上教树形图自绘好像csdn看的但链接没记现在也忘了当时是参考哪一个了。在此感谢加抱歉。


一.思路:

Step1.自绘树形图控件(在树形图文字左边显示CImagelist里的图片)

Step2.创建个CBitmap动态保存需要的图片信息存入树形图关联的CImagelist中

二.最终效果(使用60*60符文3):

在画板上的改变(60*60符文3)能动态反映到左边树形图控件的对应项目(60*60符文3)上

三.重绘(我就多添加注释吧在注释里讲解。思路很简单):

1.创建个类CViewTree继承自CTreeCtrl

2.重载OnPaint使用双缓冲(防闪烁,双缓冲原理网上很多,后面创建小地图也是同个思路)

/*雙緩衝重繪樹形圖*/

void CViewTree::OnPaint()

{

CLED_NEWDoc* pDoc =(CLED_NEWDoc*)((CMainFrame*)AfxGetApp()->GetMainWnd())->GetActiveDocument();//以为单文档工程有些东西存在doc里

CPaintDC dc(this); // device context for painting

// TODO: 重绘树形图控件

// Do not call CTreeCtrl::OnPaint() for painting messages

GetClientRect(&m_ClientRect);

CBitmap bitmap;

CDC MemeDc;

MemeDc.CreateCompatibleDC(&dc);

bitmap.CreateCompatibleBitmap(&dc, m_ClientRect.Width(), m_ClientRect.Height());

CBitmap *pOldBitmap = MemeDc.SelectObject(&bitmap);

//繪圖部分

MemeDc.FillSolidRect(0, 0,m_ClientRect.Width(),m_ClientRect.Height(),RGB(255, 255, 255)); //填充背景

if (pDoc->m_CsFileName != _T(""))//如果有打開文件則可以畫樹形圖

DrawItem(&MemeDc);

//繪圖部分

dc.BitBlt( m_ClientRect.left, m_ClientRect.top, m_ClientRect.Width(), m_ClientRect.Height(), &MemeDc, 0, 0,SRCCOPY);

MemeDc.SelectObject(pOldBitmap);

MemeDc.DeleteDC();

}

3.画显示的项目

void CViewTree::DrawItem(CDC* pDc)

{

CLED_NEWDoc* pDoc =(CLED_NEWDoc*)((CMainFrame*)AfxGetApp()->GetMainWnd())->GetActiveDocument();

HTREEITEM currentItem;//当前的句柄

DWORD    treeStyle;// 数的类型

CRect    itemRect;//每一项的区域

int      itemState;//某项的状态

int itemImage;//圖片

int     Open_num=0;

int HScroll = GetScrollPos(SB_HORZ);

CImageList* imagelist = GetImageList(TVSIL_NORMAL);

treeStyle =:: GetWindowLong( m_hWnd, GWL_STYLE );

currentItem = GetFirstVisibleItem();//获取第一个课可见的项

//設置顯示字體

static CFont font;

font.DeleteObject();

font.CreatePointFont(100, _T("新宋体"));

pDc->SelectObject(&font);

do //beginwhile ((currentItem=GetNextVisibleItem(currentItem)) != NULL);

{

Open_num++;

//判斷是否為選擇狀態

if (Open_num + GetScrollPos(SB_VERT) == ((CMainFrame*)AfxGetApp()->GetMainWnd())->m_wndMaskView.Select)//选中是第几个数存在MaskView的Select里

pDc->SetBkColor(RGB(233,233,233));

else

pDc->SetBkColor(RGB(255,255,255));

CRect   fillRect(0,itemRect.top,m_ClientRect.right,itemRect.bottom);//填背景用的后来没删

itemState = GetItemState(currentItem,TVIF_STATE);

//每一項的位置和圖片

GetItemImage(currentItem,itemImage,itemImage);

GetItemRect(currentItem,itemRect,FALSE);

CPoint point;

point.y = itemRect.top;

point.x = itemRect.left-HScroll+(GetLevel(currentItem)-1)*42;//(以前写的时候多次用上的数字都没#define成英文。很糟糕,建议养成习惯)

if (itemRect.top>m_ClientRect.bottom)  //说明这一项已超出窗口的边界

{

break;

}

if ( GetChildItem(currentItem) != NULL )

{

if (ItemHasChildren(currentItem))//有子項則畫上對應三角形圖標

{

if (itemState & TVIS_EXPANDED )

{

imagelist->Draw(pDc,1,point,ILD_TRANSPARENT);

}

else

{

imagelist->Draw(pDc,0,point,ILD_TRANSPARENT);

}

}

}else{//無子項則畫上對應imagelist圖片

//imagelist->Draw(pDc,3,point,ILD_TRANSPARENT);

point.x = point.x + 50;

imagelist->Draw(pDc,itemImage,point,ILD_TRANSPARENT);

point.x = point.x - 50;

}

if ( GetLevel(currentItem) != 3 )//項目不為第三層就加藍色文件夾圖標

{

point.x = point.x + 42;

point.y = point.y + 5;

pDc->DrawIcon(point,AfxGetApp()->LoadIcon(IDI_ICON_PROJECT));//因為存imagelist無法有透明效果(现在这个能自己能花式解决吧。以前写的真糟糕,但是因为提供的是ICON资源载入到imagelist分辨率降了很多,看他只有一张于是就直接画了)

point.x = point.x - 42;

point.y = point.y - 5;

}

GetItemRect(currentItem,itemRect,TRUE);

if (Open_num == ((CMainFrame*)AfxGetApp()->GetMainWnd())->m_wndMaskView.Rename && pDoc->m_bFlagRenameShow == TRUE);

else

pDc->TextOut(itemRect.left ,itemRect.top+itemRect.Height()/2-6,GetItemText(currentItem));//输出树形图的文字

}while ((currentItem=GetNextVisibleItem(currentItem)) != NULL);

}//好了到此为止,以下不重要可以直接看四.

//现在忘了为什么加这个

BOOL CViewTree::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)

{

// TODO: Add your specialized code here and/or call the base class

return CTreeCtrl::OnWndMsg(message, wParam, lParam, pResult);

}

//这个现在也忘记了为什么加了

BOOL CViewTree::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)

{

BOOL bRes = CTreeCtrl::OnNotify(wParam, lParam, pResult);

NMHDR* pNMHDR = (NMHDR*)lParam;

ASSERT(pNMHDR != NULL);

if (pNMHDR && pNMHDR->code == TTN_SHOW && GetToolTips() != NULL)

{

GetToolTips()->SetWindowPos(&wndTop, -1, -1, -1, -1, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSIZE);

}

return bRes;

}

//不要擦除背景,会闪烁

BOOL CViewTree::OnEraseBkgnd(CDC* pDC)

{

// TODO: Add your message handler code here and/or call default

return TRUE;

}

//滚动时当然要刷新

void CViewTree::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)

{

// TODO: Add your message handler code here and/or call default

Invalidate();

CTreeCtrl::OnVScroll(nSBCode, nPos, pScrollBar);

}

//搬的砖,放在里面方便用

int CViewTree::GetLevel(HTREEITEM inputTree)

{

//獲得Item所在樹形圖層數

HTREEITEM temp;

temp = inputTree;

int level = 0;

while (temp != NULL)

{

temp = GetParentItem(temp);

++level;

}

return level;

}

四.创建CBitmap存入CImagelist(那时存class CMaskView : public CDockablePane):

创建自绘的树形图:CViewTree m_wndFileView;

创建图片列表:CImageList m_FileViewImages;

1.创建树形图

//vs创建单文档工程造着里面来就好了,树形图类相关操作msdn里面自查CTreeCtrl,添加删除重命名什么的网上很多就不写了

if (!m_wndFileView.Create(dwViewStyle, rectDummy, this, 4))

{

TRACE0("Failed to create file view\n");

return -1;      // fail to create

}//调整位置大小也是vs新建单文档工程时有悬浮窗就有看vs吧

2.创建图片并填充(在画树形图时每个项对应上Imagelist里的相应项就OK了)

void CMaskView::FillTreeImage()

{

/***********************///(和双缓冲同个思路,诶,现在看起来能写的简单整洁多的,怪当时理解不深,真糟糕)

CLED_NEWDoc* pDoc =(CLED_NEWDoc*)((CMainFrame*)AfxGetApp()->GetMainWnd())->GetActiveDocument();

CDC MemDC,MemDC2;

CDC * pDC;

CDC * pDC2;

pDC =GetDC();

pDC2=GetDC();

HTREEITEM hItem;

CBitmap bmp,bmp2;

UINT nFlags = ILC_MASK;

nFlags |= (theApp.m_bHiColorIcons) ? ILC_COLOR24 : ILC_COLOR4;

m_imagelist.DeleteImageList();//清除图片列表

m_imagelist.Create(m_iImageSize,m_iImageSize,nFlags,0,300);//创建图片列表

//m_wndFileView.SetImageList(&pDoc->m_imagelist, TVSIL_NORMAL);

MemDC.CreateCompatibleDC(pDC);

bmp.CreateCompatibleBitmap(pDC,60,60);

MemDC.SelectObject(&bmp);

MemDC2.CreateCompatibleDC(pDC2);

bmp2.CreateCompatibleBitmap(pDC2,m_iImageSize,m_iImageSize);

MemDC2.SelectObject(&bmp2);

MemDC.FillSolidRect(0,0,pDoc->SymImage.m_Column,pDoc->SymImage.m_Row,RGB(255, 255, 255));

/*/畫十字(未展開狀態圖標)

MemDC2.FillSolidRect(0,0,m_iImageSize,m_iImageSize,RGB(255, 255, 255));

MemDC2.FillSolidRect(m_iImageSize/2-10,m_iImageSize/2-1,20,2,RGB(0, 0, 0));

MemDC2.FillSolidRect(m_iImageSize/2-1,m_iImageSize/2-10,2,20,RGB(0, 0, 0));

m_imagelist.Add(&bmp2,RGB(255, 255, 255));

*/

//90度直角三角形

int start = m_iImageSize/3,end = m_iImageSize*2/3;

int H = m_iImageSize/2,mid = m_iImageSize/2;

int x,y;

MemDC2.FillSolidRect(0,0,m_iImageSize,m_iImageSize,RGB(255, 255, 255));

for (x = 0;x<m_iImageSize;x++)

for (y = 0;y<m_iImageSize;y++)

if(x>start && (x-start) < (y - mid + H/2) && -(x-start) > (y - mid - H/2))

MemDC2.SetPixel(x,y,RGB(0, 0, 0));

m_imagelist.Add(&bmp2,RGB(255, 255, 255));

/*/畫減號(展開狀態圖標)

MemDC2.FillSolidRect(0,0,m_iImageSize,m_iImageSize,RGB(255, 255, 255));

MemDC2.FillSolidRect(m_iImageSize/2-10,m_iImageSize/2-1,20,2,RGB(0, 0, 0));

m_imagelist.Add(&bmp2,RGB(255, 255, 255));

*/

//135直角三角形

MemDC2.FillSolidRect(0,0,m_iImageSize,m_iImageSize,RGB(255, 255, 255));

for (x = 0;x<m_iImageSize;x++)

for (y = 0;y<m_iImageSize;y++)

if(x < mid + 7*H/20 && y < mid + 7*H/20 && -(x - mid - 7*H/20) < y - mid + 7*H/20)

MemDC2.SetPixel(x,y,RGB(0, 0, 0));

m_imagelist.Add(&bmp2,RGB(255, 255, 255));

//涂白(未含有子顯圖標)

MemDC2.FillSolidRect(0,0,m_iImageSize,m_iImageSize,RGB(255, 255, 255));

m_imagelist.Add(&bmp2,RGB(255, 255, 255));

HICON hIcon[2];

hIcon[0] = AfxGetApp()->LoadIcon(IDI_ICON_FILE_SE);

m_imagelist.Add(hIcon[0]);

//bmp.LoadBitmapW(IDB_BITMAP_F1);

hIcon[1] = AfxGetApp()->LoadIcon(IDI_ICON_PROJECT);

m_imagelist.Add(hIcon[1]);

//給樹形圖對應imagelist插入自畫的圖片并設置每個項的對應

int n = 4;

hItem = m_wndFileView.GetRootItem();

hItem = m_wndFileView.GetChildItem(hItem);

while (hItem != NULL)//几个判断判断是否是第3层,因为当时只有第三层需要小地图,扫描他们

{

if(m_wndFileView.GetChildItem(hItem) != NULL)

{

hItem = m_wndFileView.GetChildItem(hItem);

while (hItem != NULL)

{

n++;

CString name;

name = m_wndFileView.GetItemText(hItem);

CString ParentItemName = m_wndFileView.GetItemText(m_wndFileView.GetParentItem(hItem));

if (ParentItemName == _T("5*8"))

pDoc->SymImage = pDoc->m_Array_List_Sym[pDoc->Finding_Sym_limit(name,5,8)];

else if (ParentItemName == _T("16*16"))

pDoc->SymImage = pDoc->m_Array_List_Sym[pDoc->Finding_Sym_limit(name,16,16)];

else if (ParentItemName == _T("32*32"))

pDoc->SymImage = pDoc->m_Array_List_Sym[pDoc->Finding_Sym_limit(name,32,32)];

else if

(ParentItemName == _T("其他") || ParentItemName == _T("Other"))

pDoc->SymImage = pDoc->m_Array_List_Sym[pDoc->Finding_Sym_for_another(name)];

//給圖片刷新背景

MemDC.FillSolidRect(0,0,pDoc->SymImage.m_Column,pDoc->SymImage.m_Row,pDoc->m_clrLedBK);

//按點填充圖案

for (x = 0;x<pDoc->SymImage.m_Column;x++)

for (y = 0;y<pDoc->SymImage.m_Row;y++)

if (pDoc->SymImage.led_data[x][y] == TRUE)

MemDC.SetPixel(x,y,pDoc->m_clrLed);//(根据已知信息绘制图,MemDC可以存其他图片,当时对CDC这些也理解不深)

MemDC2.StretchBlt(1,1,m_iImageSize-2,m_iImageSize-2,&MemDC,0,0,pDoc->SymImage.m_Column,pDoc->SymImage.m_Row,SRCCOPY);//缩放保存到MemDC2里,StretchBlt可能有失真

m_imagelist.Add(&bmp2,RGB(255,255,255));//添加到图片列表

m_wndFileView.SetItemImage(hItem,n,n);//设置对应图片

if (m_wndFileView.GetNextSiblingItem(hItem) == NULL)

break;

else

hItem = m_wndFileView.GetNextSiblingItem(hItem);

}//endwhile (hItem != NULL)

hItem = m_wndFileView.GetParentItem(hItem);

}

hItem = m_wndFileView.GetNextSiblingItem(hItem);

}//endwhile (hItem != NULL)

MemDC2.FillSolidRect(0,0,m_iImageSize,m_iImageSize,RGB(255, 255, 255));

m_imagelist.Add(&bmp2,RGB(0, 0, 0));

m_wndFileView.SetImageList(&m_imagelist, TVSIL_NORMAL);//关联图片列表

::ReleaseDC(this->m_hWnd, MemDC);

::ReleaseDC(this->m_hWnd, MemDC2);

/***********************************/

}

//就这样,树形图子项要对应的图片存到关联的CImagelist里,小地图需要变化时替换CImagelist里对应的项然后再刷新树形图就可以实现树形图旁边带着的小地图动态变换了。

五.结语:

这时写文章回顾这个代码写的真的很糟糕(负能量代码,抱歉),只是实现了功能。在博客园还是哪个地方看了篇技术观念的文章,嗯,深耕技术(这个词很喜欢)。希望未来我们都能做喜欢干的事情吧(希望终有一天能成为谷雨大神或雨神吧,嗯,希望),这算是记录下当时的思路(黑历史)的处女作吧,见谅。

MFC如何在树形图边上添加动态小地图的更多相关文章

  1. MFC List Control 控件添加单元格编辑,实现可编辑重写

    在实现随机生成四则运算的个人项目中,目前已经完成基本功能,想要把程序变成一个Windows界面的程序.原本以为学习过MFC,应该很快就能完成.但是由于以前用的都是VC6.0,这次用了VS2010,稍微 ...

  2. [UE4]更通用的接口,将UserWidget作为图标添加到小地图

    将图标改成UserWidget添加到小地图,UserWidget支持动画特效,更丰富小地图的功能. 一.在小地图图标结构体中,将Flag数据类型改成UserWidget,删除ImageWidget(类 ...

  3. springboot+shiro+redis(单机redis版)整合教程-续(添加动态角色权限控制)

    相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(单机redis版)整合教程 3. springboot+shiro+redis(集群re ...

  4. QT中添加 动态库(.so) 和 静态库 (.a) 的方法

    在QT 的Makefile文件中: 1 添加动态库,如lipcap.so 则,在LIBS一行中添加“-L/usr/local/lib -lpcap”,依据自己的情况修改libpcap.so的路径 2 ...

  5. vue微信分享链接添加动态参数

    微信分享时 分享链接携带参数可能不是固定的 需要在分享的前一刻才知道 这里就是动态设置分享链接的基本写法 代码不是那么详尽 但大致流程如下 1.安装引用jssdk npm install --save ...

  6. 关于React的require添加动态变化的路径

    关于React的require添加动态变化的路径 直接这样写显然是不会有错误的 let path = require('../images/girl.png'); 但是如果你尝试着 var gg = ...

  7. 如何利用腾讯云COS为静态博客添加动态相册

    前言 本文首发于个人网站Jianger's Blog,欢迎访问订阅.个人博客小站刚建站不久,想着除了主题里的功能外再添加上相册模块,于是半搜索半摸索把相册模块搞出来了,最后采用了利用腾讯云对象存储作图 ...

  8. Vue项目添加动态浏览器头部title

    0. 直接上 预览链接 + 效果图 Vue项目添加动态浏览器头部title 1. 实现思路 ( 1 ) 从路由router里面得到组件的title ( 2 ) title存vuex (本项目已经封装h ...

  9. MFC中给控件添加变量,DoDataExchange中

    DoDataExchange函数其实是一项数据动态绑定技术.比如你在写动态按钮过程中须对按钮添加变量时,怎么添加?控件类已经写好了,其变量是已经固定的.你要添加新的变量就要用到DoDataExchan ...

随机推荐

  1. day14带参装饰器,迭代器,可迭代对象 , 迭代器对象 ,for迭代器 , 枚举对象

    复习 ''' 函数的嵌套定义:在函数内部定义另一个函数 闭包:被嵌套的函数 -- 1.外层通过形参给内层函数传参 -- 2.验证执行 开放封闭原则: 功能可以拓展,但源代码与调用方式都不可以改变 装饰 ...

  2. Git操作手册(开发人员)

    一.git信息配置 1.1配置git账号信息 Window ->Preferences -> Team -> Git -> Configuration,在点击AddEntry… ...

  3. 用redis构建分布式锁

    单实例的实现 从2.6.12版本开始,redis为SET命令增加了一系列选项: EX seconds – 设置键key的过期时间,单位时秒 PX milliseconds – 设置键key的过期时间, ...

  4. SpringMVC成员变量并发状态下使用测试

    1.SpringMVC默认是单例的,使用成员变量在并发状态下该成员变量的值是被共享的 测试平台 我们目前正在开发的电商项目  (架构组成SpringCloud + SpringBoot + Sprin ...

  5. dp入门之01背包问题

    ...通过暴力手推得到的一点点感觉 动态规划是相对于贪心算法的一种取得最优解的算法,通过对每一步的取舍判断从 0 推到所拥有的第 n 件物品,每次判断可以列写出状态转移方程,通过记忆化相对暴力地取得最 ...

  6. 51nod 1405 树的距离之和 树形dp

    1405 树的距离之和 基准时间限制:1 秒 空间限制:131072 KB   收藏  关注 给定一棵无根树,假设它有n个节点,节点编号从1到n, 求任意两点之间的距离(最短路径)之和. Input ...

  7. 在webstorm中配置sass的自动编译,并且可以指定编译后的css的目录.

    参考: WebStorm-2018.2-Help-Sass, Less, and SCSS 作者:tobyDing链接:https://www.jianshu.com/p/0fe52f149cab來源 ...

  8. ieda 快捷键修改方法

    框中意思为: 1.增加快捷键 2.增加缩写

  9. [CQOI2014]数三角形

    [CQOI2014]数三角形 给定\(n\times m\)的网格,求三个点在其格点上的三角形个数,1<=m,n<=1000. 解 法一:直接 显然为组合计数问题,关键在于划分问题,注意到 ...

  10. CentOS7服务管理

    1.在/usr/lib/systemd/system目录下建立服务启动文件,文件格式:[root@Centos7 ]# cat /usr/lib/systemd/system/nginx.servic ...