MFC TreeControl简单应用

对于TreeControl常用操作,做如下介绍。

1. TreeControl添加节点

  1. 在界面种选择TreeControl控件,点击右键,在弹出的菜单种选择【添加变量】,在弹出的界面中输入变量名 "m_list”
  2. 点击界面右键,在弹出的菜单中选择【类向导】,选中“虚函数”选项卡,选择其中的“OnInitDialog”函数,然后点击【添加函数按钮】,然后点击确定。
  3. 将TreeControl控件中的属性“Has Buttons”、”Line at root“和“Has Line”后改为 “True”,如果相实现双击更改其值的功能,则将”Edit Labels“改为”True“
  4. 如果想要在树节点前添加图标,则需要导入*.icon的图标文件。具体方法为:
    选择资源视图,在资源视图中点击右键,在弹出的菜单中选择【添加资源】,在弹出的界面中点击【导入】按钮,然后选择.icon的文件。此图标导入后的名称为”IDI_ICON1“

  5. 在初始化函数中添加节点代码
//在.h文件中添加如下代码
CImageList m_imageList1;
//修改初始化函数
BOOL TreeTest::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    m_list.SetBkColor(RGB(230,230,230));//设置树的颜色

    m_imageList1.Create(16,16,ILC_COLOR8|ILC_MASK,0,4);//第五个参数为图标的总数
    m_imageList1.Add(AfxGetApp()->LoadIconW(IDI_ICON1));//将图标添加到imageList中

    m_list.SetImageList(&m_imageList1,TVSIL_NORMAL);//将图标进行加载

    
    HTREEITEM root = m_list.InsertItem(_T("root"));//插入根节点
    HTREEITEM hChild1 = m_list.InsertItem(_T("child1"),root);//在根节点下插入子节点
    HTREEITEM hChild2 = m_list.InsertItem(_T("child2"),root);//在根节点下插入子节点
    HTREEITEM hChild3 = m_list.InsertItem(_T("child3"),root);//在根节点下插入子节点

    m_list.SetItemImage(root,0,0);//设置根节点图标
    m_list.SetItemImage(hChild1,0,0);
    m_list.SetItemImage(hChild2,0,0);
    m_list.SetItemImage(hChild3,0,0);//设置子节点图标,注意:第一个参数为要设置的节点、第二个参数为默认状态下的图标、第三个值为选中后的图标。


    return TRUE;  // return TRUE unless you set the focus to a control

}

2. TreeControl菜单

  1. 新建一个菜单,内容为”增加“、”删除“、”重命名“
  2. 选中Tree控件,点击右键,在弹出的菜单中选择”类向导“;在弹出的界面中选择【命令】、对象下选择”IDC_TREE1“,在消息中选择右键消息”NM_RCLICK“,然后点击【添加处理程序】按钮。
  3. 选中节点后才可以加载菜单,具体代码如下:
void TreeTest::OnRclickTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
    CPoint ScreenPt;
    GetCursorPos(&ScreenPt);

    CPoint pt =GetCurrentMessage()->pt;//获取当前鼠标点击消息的坐标点
    m_list.ScreenToClient(&pt);//将鼠标的屏幕坐标,转换成树控件的客户区域坐标
    UINT uFlags = 0;
    HTREEITEM hItem = m_list.HitTest(pt,&uFlags);//然后做点击测试

    /**判断右键是否在节点上**/
    if ((hItem != NULL)&&(TVHT_ONITEM & uFlags))//如果点击位置在界面位置上面
    {
        
        CMenu menu;
        menu.LoadMenuW(IDR_MENU1);//装载第一个子菜单,即我们菜单的第一列
        CMenu* pPopup = menu.GetSubMenu(0);
        pPopup->TrackPopupMenu(TPM_LEFTALIGN, ScreenPt.x, ScreenPt.y, this);//弹出菜单 2
    
    }
    *pResult = 0;
}

3. TreeControl修改节点

参考链接
实现双击修改节点名称,双击时速度需要慢一些,快速双击为展开和折叠节点

  1. 属性设置:将”Edit Labels“改为”True“
  2. 选中Tree控件,在弹出的菜单中选择【类向导】,添加消息函数”TVN_BEGINLABELEDIT“ 和 ”TVN_ENDLABELEDIT“
  3. 添加全局变量CString g_sSelectStr
  4. 修改两个消息函数,,如下:
void TreeTest::OnBeginlabeleditTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);

    g_sSelectStr = m_list.GetItemText(m_list.GetSelectedItem());//得到修改前的数据
    *pResult = 0;
}


void TreeTest::OnEndlabeleditTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);
    
    CString strName; //修改后的数据
    CString rootstr;
    m_list.GetEditControl()->GetWindowText(strName);
    if (strName.IsEmpty())
    {
        AfxMessageBox(_T("数据项不能为空,请重新输入"));
        return;
    }
    if (strName.Compare(g_sSelectStr) == 0)//名字未做修改
    {
        return;
    }
    //判断是否由重复的名字
    HTREEITEM hRoot = m_list.GetRootItem();
    HTREEITEM hFind = FindItem(hRoot,strName);
    if (hFind == NULL)//如果没有重名,则修改
    {
        CString strText;
        m_list.GetEditControl()->GetWindowText(strText);
        m_list.SetItemText(m_list.GetSelectedItem(),strText);
    }
    *pResult = 0;
}

4. TreeControl查找节点

//根据名称来查找节点
HTREEITEM TreeTest::FindItem(HTREEITEM item,CString strText)
{
    HTREEITEM hFind;
    if (item == NULL)//修改数据与根数据不同,遍历时使用
    {
        return NULL;
    }
    while(item != NULL)
    {
        if (strText.Compare(m_list.GetItemText(item))  == 0)//名字相同
        {
            return item;
        }
        if (m_list.ItemHasChildren(item))//如果有子节点,则继续判断
        {
            item = m_list.GetChildItem(item);
            hFind = FindItem(item,strText);
            if (hFind)
            {
                return hFind;
            }
            else
            {
                item = m_list.GetNextSiblingItem(m_list.GetParentItem(item));
            }
        }
        else
        {
            item = m_list.GetNextSiblingItem(item);
            return FindItem(item,strText);
        }
    }
    return item;
}

5. TreeControl折叠展开节点

//折叠所有的树节点
void TreeTest::mFoldTree(HTREEITEM hTreeItem)
{
    if(!m_list.ItemHasChildren(hTreeItem))    
    {    
        return;    
    }    
    HTREEITEM hNextItem = m_list.GetChildItem(hTreeItem);
    while (hNextItem != NULL)    
    {   
        ExpandTree(hNextItem);    
        hNextItem = m_list.GetNextItem(hNextItem, TVGN_NEXT);    
    }    
    m_list.Expand(hTreeItem,TVE_COLLAPSE); 
}

//展开所有的树节点
void TreeTest::ExpandTree(HTREEITEM hTreeItem)
{
    if(!m_list.ItemHasChildren(hTreeItem))    
    {    
        return;    
    }  
    HTREEITEM hNextItem = m_list.GetChildItem(hTreeItem);
    while (hNextItem != NULL)    
    {   
        ExpandTree(hNextItem); 
        hNextItem = m_list.GetNextItem(hNextItem, TVGN_NEXT);    
    } 
    HTREEITEM hchild = m_list.GetChildItem(hTreeItem);
    CString NodeData,NodeName;
    NodeName = m_list.GetItemText(hchild);
    if (NodeData.Compare(_T("2")) == 0 )
    {
        return;
    }
    m_list.Expand(hTreeItem,TVE_EXPAND); 
}

//展开单独的树节点
void TreeTest::ExpandTree2(HTREEITEM hTreeItem)
{
    if(!m_list.ItemHasChildren(hTreeItem))    
    {    
        return;    
    }  
    HTREEITEM hNextItem = m_list.GetChildItem(hTreeItem);
    while (hNextItem != NULL)    
    {   
        ExpandTree(hNextItem); 
        hNextItem = m_list.GetNextItem(hNextItem, TVGN_NEXT);    
    } 
    m_list.Expand(hTreeItem,TVE_EXPAND); 
}


void TreeTest::OnClickTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
    hTreeItem = m_list.GetSelectedItem();
    *pResult = 0;
}

//折叠树按钮
void TreeTest::OnBnClickedButton1()
{
    HTREEITEM hItem = m_list.GetSelectedItem();
    if (hItem == NULL)
    {
        HTREEITEM hroot = m_list.GetRootItem();
        mFoldTree(hroot);     
    }
    else
    {
        mFoldTree(hItem);
    }
}

//展开树按钮
void TreeTest::OnBnClickedButton7()
{
    HTREEITEM hItem = m_list.GetSelectedItem();
    if (hItem == NULL)
    {
        HTREEITEM hroot = m_list.GetRootItem();
        ExpandTree(hroot);
    }
    else
    {
        ExpandTree2(hItem);
    }
}

6. TreeControl拖动树

参考网址1
参考网址2
参考网址3
参考网址4

创建树的时候,使用继承类TreeControl进行创建。例如:
注意:此方法目前具有一定的局限性,即节点下必须有子节点,才可以完成拖动。后期进行优化

CXtreeCtrl m_list;
HTREEITEM root =    m_list.InsertItem(_T("root"));
HTREEITEM parent1 = m_list.InsertItem(_T("1"),root);
m_list.InsertItem(_T("11"),parent1);

HTREEITEM parent2 = m_list.InsertItem(_T("2"),root);
m_list.InsertItem(_T("21"),parent2);
    
HTREEITEM parent3 = m_list.InsertItem(_T("3"),root);
m_list.InsertItem(_T("31"),parent3);

HTREEITEM parent4 = m_list.InsertItem(_T("4"),root);
m_list.InsertItem(_T("41"),parent4);

7. 继承类TreeControl

XTreeCtrl.cpp

// XtreeCtrl.cpp : implementation file
//

#include "stdafx.h"
#include "Drag.h"
#include "XtreeCtrl.h"
#define DRAG_DELAY 60

// CXtreeCtrl

IMPLEMENT_DYNAMIC(CXtreeCtrl, CTreeCtrl)

CXtreeCtrl::CXtreeCtrl()
{
    m_bDragging = FALSE;
    //m_hSelectItem = NULL;
    m_hItemDragS = NULL;
    m_nHoverTimerID = 0;
    m_nScrollTimerID = 0;
    m_bInsertAbove = FALSE;
    m_hItemDragD = NULL;

}

CXtreeCtrl::~CXtreeCtrl()
{
}


BEGIN_MESSAGE_MAP(CXtreeCtrl, CTreeCtrl)
    ON_NOTIFY_REFLECT(TVN_BEGINDRAG, &CXtreeCtrl::OnTvnBegindrag)
    ON_WM_LBUTTONUP()
    ON_WM_MOUSEMOVE()
    ON_WM_TIMER()
    ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()



// CXtreeCtrl message handlers



void CXtreeCtrl::OnTvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
    // TODO: Add your control notification handler code here
    
    *pResult = 0;
    if( (GetTickCount() - m_dwDragStart) < DRAG_DELAY )
        return;
    
    m_hItemDragS = pNMTreeView->itemNew.hItem;
    if (!ItemHasChildren(m_hItemDragS))             //子节点不能被拖拽,注释后可以随意拖拽
    {
        return;
    }
    m_hItemDragD = NULL;
    m_bDragging = true;
    m_nScrollTimerID = SetTimer( 2,40,NULL );
}
HTREEITEM CXtreeCtrl::GetDragTarget(HTREEITEM hItem, POINT point, BOOL& bInsertAbove)
{
    ASSERT(hItem != NULL);
    HTREEITEM hDragTarget;
    CRect rectItem;
    GetItemRect(hItem, &rectItem, FALSE);
    if (point.y < rectItem.CenterPoint().y)
    {
        hDragTarget = hItem;
        bInsertAbove = TRUE;
    }
    else
    {
        if (ItemHasChildren(hItem) && (GetItemState(hItem, TVIS_EXPANDED) & TVIS_EXPANDED))
        {
            hDragTarget = GetChildItem(hItem);    
            bInsertAbove = TRUE;
        }
        else
        {
            hDragTarget = hItem;
            bInsertAbove = FALSE;
        }
    }
    ASSERT(hDragTarget != NULL);
    return hDragTarget;
}

void CXtreeCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
    // TODO: Add your message handler code here and/or call default

    HTREEITEM hItem;
    UINT      flags;
    if (m_nHoverTimerID > 0)
    {
        KillTimer(m_nHoverTimerID);
        m_nHoverTimerID = 0;
    }   
    if( m_bDragging )
    {
        m_nHoverTimerID = SetTimer(1, 800, NULL);
        m_HoverPoint = point;
        //鼠标经过时高亮显示
        CImageList::DragShowNolock( false ); //避免鼠标经过时留下难看的痕迹
        HTREEITEM m_hNextDragTarget;    
        BOOL m_bNextInsertAbove;        
        if( (hItem = HitTest(point,&flags)) != NULL )
        {
            m_hNextDragTarget = GetDragTarget(hItem, point, m_bNextInsertAbove);
            if ((m_hNextDragTarget != m_hItemDragD) || (m_bInsertAbove != m_bNextInsertAbove))
            {
                SelectDropTarget(m_hNextDragTarget);
                m_hItemDragD = m_hNextDragTarget;
                m_bInsertAbove = m_bNextInsertAbove;
                EnsureVisible(m_hItemDragD);
                RedrawWindow();
            }
        }
        if ((GetScrollPos(SB_HORZ) > 0) && (GetScrollLimit(SB_VERT) > 0))
        {
            Invalidate();
        }
    }
    CTreeCtrl::OnMouseMove(nFlags, point);
}
HTREEITEM CXtreeCtrl::CopyItem(HTREEITEM hItem1, HTREEITEM htiNewParent, HTREEITEM htiAfter) //拷贝条目
{
    TV_ITEM tvSrc;
    tvSrc.mask  = TVIF_HANDLE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE;
    tvSrc.hItem = hItem1;
    if (!GetItem(&tvSrc)) 
        return  htiNewParent;

    tvSrc.hItem = htiNewParent;
    SetItem(&tvSrc);
    SetItemText(htiNewParent,GetItemText(hItem1));
    SetCheck(htiNewParent,GetCheck   (hItem1));

    if (tvSrc.state & TVIS_EXPANDED) 
        Expand(htiNewParent,TVE_EXPAND);
}
HTREEITEM CXtreeCtrl::CopyBranch(HTREEITEM htiBranch, HTREEITEM htiNewParent, HTREEITEM htiAfter) //拷贝分支
{
    ASSERT((htiNewParent != NULL) && (htiBranch != NULL));
    HTREEITEM hChild;
    hChild = GetChildItem( htiBranch );
    while ( hChild != NULL )
    {
        HTREEITEM hChildDest = InsertItem(_T("dest child"), htiNewParent);
        CopyBranch( hChild,hChildDest,htiAfter );
        CopyItem(hChild,hChildDest,htiAfter);
        hChild = GetNextSiblingItem( hChild );
    }
    return htiNewParent;
}

HTREEITEM CXtreeCtrl::InsertItemAndSubtree(HTREEITEM hParent)
{
    if ((m_hItemDragD == NULL) || (m_hItemDragS == NULL)) 
    {
        ASSERT(FALSE);
        return NULL;
    }
    HTREEITEM hRoot = GetRootItem();
    if (!ItemHasChildren(m_hItemDragD))     //如果注释可以随意拖拽父节点到子节点(自己看效果)
    {
        return  NULL;
    }
    
    else if (hRoot == m_hItemDragD)         //如果注释可以随意拖拽父节点至根节点(自己看效果)
    {
        return  NULL;
    }
    if (hParent == NULL)
        hParent = GetParentItem(m_hItemDragD);
    if (hParent == NULL)
        hParent = TVI_ROOT;

    HTREEITEM hInsertAfter;

    if (m_bInsertAbove)
        hInsertAfter = GetPrevSiblingItem(m_hItemDragD);
    else
        hInsertAfter = m_hItemDragD;

    if ((hInsertAfter == hParent) || (hInsertAfter == NULL))
        hInsertAfter = TVI_FIRST;

    HTREEITEM hNew = InsertItem(_T("dummy"), hParent, hInsertAfter);
    if (hNew == NULL)
        return NULL;

    CopyBranch(m_hItemDragS,hNew,m_hItemDragD);
    CopyItem(m_hItemDragS,hNew,m_hItemDragD);

    return hNew;
}

void CXtreeCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
    // TODO: Add your message handler code here and/or call default
    CTreeCtrl::OnLButtonUp(nFlags, point);
    if(m_bDragging)
    {
        m_bLeftBtnUp = TRUE;
        KillTimer(m_nScrollTimerID);
        m_nScrollTimerID = 0;
        KillTimer(m_nHoverTimerID);
        m_nHoverTimerID = 0;
        ReleaseCapture();
        ShowCursor(true);
        m_bDragging = false;
        SelectDropTarget(NULL);
        if (m_bLeftBtnUp)
        {
            if (m_hItemDragD != NULL)
                m_bGoingOK = TRUE;
            HTREEITEM m_hParentNew = m_hItemDragD;
            while (m_hParentNew != NULL)
            {

                if(m_hParentNew == m_hItemDragS)
                {
                    //AfxMessageBox(_T("禁止此操作!"), MB_ICONEXCLAMATION);
                    m_bGoingOK = FALSE;
                    break;
                }
                m_hParentNew = GetParentItem(m_hParentNew);
            }
            HTREEITEM m_hParent;
            if (m_bGoingOK)
            {
                SetRedraw(FALSE);            
                m_hParent = GetParentItem(m_hItemDragD);
                if (m_hParent == NULL)
                    m_hParent = TVI_ROOT;       
                if (m_bGoingOK)
                {
                    // We're finally ready to insert the actual item.
                    HTREEITEM hNew = InsertItemAndSubtree(m_hParent);
                    if (hNew != NULL) 
                    {
                        SelectItem(hNew);
                        DeleteItem(m_hItemDragS);
                    }
                }
            }
            // Regardless of what happens, we need to reset the tree.
            SetRedraw(TRUE);            
            Invalidate();
        }
        else
        {
            // The User chose to abort the drag
            EnsureVisible(m_hItemDragS);
            // Refresh the screen to get rid of any remnants of the drag drawing
            Invalidate();
        }

    }
    CTreeCtrl::OnLButtonUp(nFlags, point);
}

void CXtreeCtrl::OnTimer(UINT_PTR nIDEvent)
{
    // TODO: Add your message handler code here and/or call default
    if( nIDEvent == m_nHoverTimerID)
    {
        KillTimer( m_nHoverTimerID);
        m_nHoverTimerID = 0;
        HTREEITEM trItem = 0;
        UINT uFlag = 0;
        trItem = HitTest(m_HoverPoint,&uFlag);
        if( trItem && m_bDragging)
        {
            SelectItem(trItem);
            //Expand( trItem,TVE_EXPAND );
        }
    }
    else if(nIDEvent == m_nScrollTimerID)
    {
        m_TimerTicks++;
        CPoint pt;
        GetCursorPos(&pt);
        CRect rect;
        GetClientRect(&rect);
        ClientToScreen(&rect);
        HTREEITEM hItem = GetFirstVisibleItem();
        if( pt.y < rect.top +10)
        {
            int slowscroll = 6 - (rect.top + 10 - pt.y )/20;
            if( 0 == (m_TimerTicks % ((slowscroll > 0) ? slowscroll : 1)))
            {
                CImageList::DragShowNolock (false);
                SendMessage( WM_VSCROLL,SB_LINEUP);
                SelectDropTarget(hItem);
                m_hItemDragD = hItem;
                CImageList::DragShowNolock (true);
            }
        }
        else if(pt.y > rect.bottom - 10)
        {
            int slowscroll = 6 - (pt.y - rect.bottom + 10)/20;

            if( 0 == (m_TimerTicks % ((slowscroll > 0) ? slowscroll : 1)))
            {
                CImageList::DragShowNolock (false);
                SendMessage(WM_VSCROLL,SB_LINEDOWN);
                int nCount = GetVisibleCount();
                for( int i=0 ; i<nCount-1 ; i++ )
                    hItem = GetNextVisibleItem( hItem);
                if( hItem)
                    SelectDropTarget(hItem);

                m_hItemDragD = hItem;
                CImageList::DragShowNolock (true);
            }
        }
    }
    else
    CTreeCtrl::OnTimer(nIDEvent);
}

void CXtreeCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: Add your message handler code here and/or call default
    //m_dwDragStart = GetTickCount();   
    //m_hSelectItem = GetSelectedItem();
    //UINT nHitFlags = 0;
    //HTREEITEM hClickedItem = HitTest( point, &nHitFlags );
    CTreeCtrl::OnLButtonDown(nFlags, point);
}

XTreeCtrl.h

#pragma once


// CXtreeCtrl

class CXtreeCtrl : public CTreeCtrl
{
    DECLARE_DYNAMIC(CXtreeCtrl)

public:
    CXtreeCtrl();
    virtual ~CXtreeCtrl();

protected:
    DECLARE_MESSAGE_MAP()


public:
    afx_msg void OnTvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult);
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    afx_msg void OnTimer(UINT_PTR nIDEvent);
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
protected:
    DWORD       m_dwDragStart;
    UINT        m_nScrollTimerID;
    UINT        m_nHoverTimerID;
    UINT        m_TimerTicks;
    POINT       m_HoverPoint;
    BOOL        m_bDragging;
    BOOL        m_bInsertAbove;
    BOOL        m_bLeftBtnUp;
    BOOL        m_bGoingOK;
    CImageList* m_pDragImage;
    HTREEITEM   m_hItemDragS;
    HTREEITEM   m_hItemDragD;
    HTREEITEM   m_hSelectItem;
    HTREEITEM CopyBranch(HTREEITEM htiBranch,HTREEITEM htiNewParent,HTREEITEM htiAfter);
    HTREEITEM CopyItem(HTREEITEM hItem,HTREEITEM htiNewParent,HTREEITEM htiAfter);
    HTREEITEM GetDragTarget(HTREEITEM hItem, POINT point, BOOL& bInsertAbove);
    HTREEITEM InsertItemAndSubtree(HTREEITEM hParent = NULL);
};

推荐文章

spring中JDBCTemplate的简单应用

package cn.itcast.datasource.jdbctemplate;import cn.itcast.utils.JDBCUtils;import org.springframework.jdbc.core.JdbcTemplate;import javax.sql.DataSource;/** * @author newcit

推荐文章

求XF+闭包(第十一届河南省省赛真题)

题目描述 如何设计一个好的数据库不仅仅是一个理论研究问题,也是一个实际应用问题。在关系数据库中不满足规范化理论的数据库设计会存在冗余、插入异常、删除异常等现象。      设R(U)是一个关系模式,U={ A1,A2, ……, An}。其中Ai是关系的属性,X,Y是U的子集。函数依赖 X-&g

推荐文章

ajax 动态获取数据库中的值

功能简介:  在一个输入框中输入内容 ,当内容长度>1时向后发送ajax   从数据库中获取有关文本框中的内容在前台显示, 前台设计一些点击事件,以及jquery的应用  注意: request.getParameter("postData").trim() 放在判断之前可能会空指针异常 如果

推荐文章

nodejs进阶(1)——npm使用技巧和最佳实践

nodejs进阶教程,小白绕道!!! npm使用技巧和最佳实践 前提:请确保安装了node.js npm的最佳实践 npm install是最常见的npm cli命令,但是它还有更多能力!接下来你会了解npm是如何在应用的整个生命周期帮助你的-从创建一个项目到开发和部署整个生命周期 认识npm 在开始之前,我们先来看看一些查看正在运

推荐文章

SHELL-收集Oracle已应用的PSU信息

  1. 命令收集版本信息 # 创建数据收集脚本文件 OPER_FILE=${EXECUTE_ID}_oper.sh if [[ "${OPER_USER}" = "${USER}" ]]; then echo "${PATCH_HOME}/opatch lsinventory > ${MODULE_OU

推荐文章

JavaWeb —— JSP 总结

                                       JSP总结 静态网页   在网站设计中,纯粹HTML(标准通用标记语言下的一个应用)格式的网页通常被称为“静态网页”,静态网页

推荐文章

nodejs应用转换png,jpg,gif为webp图片格式

本博客列表缩略图在支持webp格式的浏览器下,使用的是webp格式图片,不支持webp图片下使用的是原图片(如png,gif,jpg等) webp使用指南,请参考 https://www.imqianduan.com/browser/webp.html 如何转换webp? google官方有推出工具cwebp用来转换webp,可

推荐文章

Spring生态

 Spring Boot:使用默认开发配置来实现快速开发 Spring XD:用来简化大数据应用开发  Spring Cloud:为分布式系统开发提供工具集 Spring Data:对主流的关系型和nosql数据库的支持 Spring Integration:通过消息机制对企业集成模式(EIP)的支持 Spring

推荐文章

jsp(10):数据库操作

首先一定要下载好驱动文件。然后记得一定要先加载到项目中!驱动文件下载连接:已经有写好的数据库文件以及前端页面了 例如我的是mysql驱动。就将mysql-connector-java-5.1.38-bin.jar添加到webcontent的web-inf下的lib中就可以了~ 遵循固定代码格式,不必多说: 最基本必经步骤(de

推荐文章

飞镖忍者 quick-cocos2d-x3.2

经典的入门小游戏,这里用quick-cocos2d-x3.2重新写一遍,以便熟悉下quick 首先,创建工程,如果不会自行百度啊。 1、编译效果如下: 2、将游戏背景设置为白色,同时我们也来看一下MainScene.lua的文件 local MainScene = class("MainScene", function(

推荐文章

python练习册第三题

题目 将 0001 题生成的 200 个激活码(或者优惠券)保存到 Redis 非关系型数据库中。 解题思路 难点是压根不知道redis怎么用。好在找到了一些文章快速学了些: 使用python操作redis python: redis介绍及简单应用 python(十一)下:Redis安装配置及使用详解 安装redis包,就可以开始用了。

推荐文章

Bash Shell中的特殊位置变量及其应用

                            Bash Shell中的特殊位置变量及其应用       众所周知bash shell中有许多特殊的位置变量

推荐文章

Bash的特性

一、命令的别名——(自定义命令) alias alias - 定义或显示别名。 格式:alias [-p] [名称[=值] ... ] 注意:如果alias命令不带任何选项和参数,则表示显示所有已经定义并生效的别名设置; unalias unalias - 从别名定义列表中删除每一个"名字"。 格式

推荐文章

BeautifulSoup模板简单应用-提取html指定数据(api_name/api_method/api_path,请求body/请求header/pagam参数)

from bs4 import BeautifulSoup import re import os.path import itertools name=‘newcrm‘ source_file_path=‘./‘+name+‘.html‘ def get_apiInfo(): with open(sourc

推荐文章

可重入锁和不可重入锁

转自https://www.cnblogs.com/dj3839/p/6580765.html 锁的简单应用 用lock来保证原子性(this.count++这段代码称为临界区) 什么是原子性,就是不可分,从头执行到尾,不能被其他线程同时执行。 可通过CAS来实现原子操作 CAS(Compare and Swap): CAS