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

2023-11-07 07:20

本文主要是介绍MFC如何在树形图边上添加动态小地图,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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里对应的项然后再刷新树形图就可以实现树形图旁边带着的小地图动态变换了。

五.结语:

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

转载于:https://www.cnblogs.com/MJGY/p/10198494.html

这篇关于MFC如何在树形图边上添加动态小地图的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/362094

相关文章

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d

LeetCode:64. 最大正方形 动态规划 时间复杂度O(nm)

64. 最大正方形 题目链接 题目描述 给定一个由 0 和 1 组成的二维矩阵,找出只包含 1 的最大正方形,并返回其面积。 示例1: 输入: 1 0 1 0 01 0 1 1 11 1 1 1 11 0 0 1 0输出: 4 示例2: 输入: 0 1 1 0 01 1 1 1 11 1 1 1 11 1 1 1 1输出: 9 解题思路 这道题的思路是使用动态规划

vue2实践:el-table实现由用户自己控制行数的动态表格

需求 项目中需要提供一个动态表单,如图: 当我点击添加时,便添加一行;点击右边的删除时,便删除这一行。 至少要有一行数据,但是没有上限。 思路 这种每一行的数据固定,但是不定行数的,很容易想到使用el-table来实现,它可以循环读取:data所绑定的数组,来生成行数据,不同的是: 1、table里面的每一个cell,需要放置一个input来支持用户编辑。 2、最后一列放置两个b

全英文地图/天地图和谷歌瓦片地图杂交/设备分布和轨迹回放/无需翻墙离线使用

一、前言说明 随着风云局势的剧烈变化,对我们搞软件开发的人员来说,影响也是越发明显,比如之前对美对欧的软件居多,现在慢慢的变成了对大鹅和中东以及非洲的居多,这两年明显问有没有俄语或者阿拉伯语的输入法的增多,这要是放在2019年以前,一年也遇不到一个人问这种需求场景的。 地图应用这块也是,之前的应用主要在国内,现在慢慢的多了一些外国的应用场景,这就遇到一个大问题,我们平时主要开发用的都是国内的地

MFC中Spin Control控件使用,同时数据在Edit Control中显示

实现mfc spin control 上下滚动,只需捕捉spin control 的 UDN_DELTAPOD 消息,如下:  OnDeltaposSpin1(NMHDR *pNMHDR, LRESULT *pResult) {  LPNMUPDOWN pNMUpDown = reinterpret_cast(pNMHDR);  // TODO: 在此添加控件通知处理程序代码    if

控制台和MFC中内存泄露工具vld的使用

最近想检测下项目中内存泄露的情况,选中了vld这款。在查找使用方法的时候,大都是控制台下的示例,添加到main函数所在的源文件上。换成MFC就纠结了,不知道添加到哪里去。本文记录控制台和MFC中的使用vld过程。    vld资源:    1)、大家可以移步下边的网址下载:     http://vld.codeplex.com/releases/view/82311    2

MFC中App,Doc,MainFrame,View各指针的互相获取

纸上得来终觉浅,为了熟悉获取方法,我建了个SDI。 首先说明这四个类的执行顺序是App->Doc->Main->View 另外添加CDialog类获得各个指针的方法。 多文档的获取有点小区别,有时间也总结一下。 //  App void CSDIApp::OnApp() {      //  App      //  Doc     CDocument *pD