MFC TreeControl简单应用
对于TreeControl常用操作,做如下介绍。
1. TreeControl添加节点
在界面种选择TreeControl控件,点击右键,在弹出的菜单种选择【添加变量】,在弹出的界面中输入变量名 "m_list”;
点击界面右键,在弹出的菜单中选择【类向导】,选中“虚函数”选项卡,选择其中的“OnInitDialog”函数,然后点击【添加函数按钮】,然后点击确定。
将TreeControl控件中的属性“Has Buttons”、”Line at root“和“Has Line”后改为 “True”,如果相实现双击更改其值的功能,则将”Edit Labels“改为”True“
如果想要在树节点前添加图标,则需要导入*.icon的图标文件。具体方法为:
选择资源视图,在资源视图中点击右键,在弹出的菜单中选择【添加资源】,在弹出的界面中点击【导入】按钮,然后选择.icon的文件。此图标导入后的名称为”IDI_ICON1“在初始化函数中添加节点代码
//在.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菜单
- 新建一个菜单,内容为”增加“、”删除“、”重命名“
- 选中Tree控件,点击右键,在弹出的菜单中选择”类向导“;在弹出的界面中选择【命令】、对象下选择”IDC_TREE1“,在消息中选择右键消息”NM_RCLICK“,然后点击【添加处理程序】按钮。
- 选中节点后才可以加载菜单,具体代码如下:
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修改节点
参考链接
实现双击修改节点名称,双击时速度需要慢一些,快速双击为展开和折叠节点
- 属性设置:将”Edit Labels“改为”True“
- 选中Tree控件,在弹出的菜单中选择【类向导】,添加消息函数”TVN_BEGINLABELEDIT“ 和 ”TVN_ENDLABELEDIT“
- 添加全局变量
CString g_sSelectStr
- 修改两个消息函数,,如下:
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拖动树
创建树的时候,使用继承类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);
};
MFC TreeControl简单应用的更多相关文章
- MFC时间简单比较方法
MFC//时间简单比较方法 void CMFCsaveListTofileDlg::OnBnClickedButton6()//时间简单比较方法 { // TODO: 在此添加控件通知处理程序代码 C ...
- MFC的简单加法器(二)
创建对话框主要分两大步,第一,创建对话框资源,主要包括创建新的对话框模板.设置对话框属性和为对话框添加各种控件:第二,生成对话框类,主要包括新建对话框类.添加控件变量和控件的消息处理函数等.鸡啄米在本 ...
- MFC使用简单总结(便于以后查阅)
一.资源 共有三个和资源有关的文件:资源头文件resource.h.资源描述文件resource.rc和存放在res文件夹下的具体的资源如图片等. 资源头文件中全部是宏定义,应用程序需要为每个资源都定 ...
- MFC制作简单通讯录程序
学习c++和MFC一段时间了,苦于没有项目实战,所以自己写了一个简单的简单通讯录程序,以前用c#写简单很多,例程是这本书上的实例,我的第一个winform程序也是从这本书上学的,总结c#写的话更简单, ...
- MFC实现简单飞机大战(含游戏声音)
1 实验内容 本实验主要是实现简单的飞机大战游戏,包含游戏声音.碰撞后爆炸效果,有大小敌机等.所用到的知识点如下: 1.贴图技术 2.飞机类.子弹类实现 3.位图移动 4.碰撞判断,实现爆炸效果 5. ...
- MFC之简单计算器
1.界面 2.变量 combobox的变量类型是CComBoBox类型,三个输入框是double类型: 它的type是Drop List 3.代码 (1).初始化combobox BOOL Ccalc ...
- Qt And MFC Mouse Over Tips
Qt鼠标提示分析说明 关于鼠标停留在控件上面,显示提示内容的方法. 对于Qt来说, Qt的某一个控件类, 如果属于GUI的, 那么这个控件类会有一个setToolTip(QString text)的方 ...
- mfc和win32区别
Win32通常是指sdk编程方法,app没有被封装,开发人员需要自己搭程序框架:mfC则是以C++类的形式封装了Windows的API,并且包含一个应用程序框架,以减少应用程序开发人员的工作量 (整理 ...
- <MFC_1>深入剖析MFC的WinMain和消息机制
一.开篇引论 熟悉Win32开发的朋友,应该非常了解它的基本组成和流程 1. WinMain:书写窗口类(WNDCLASS) -> 注册窗口类 -> 创建窗口 -> 显示窗口和更新窗 ...
随机推荐
- 结构体sizeof()问题与字节对齐
32位机器上定义如下结构体: struct xx { long long _x1; char _x2; int _x3; char _x4[2]; static int _x5; }; int xx: ...
- java判断两个时间相差得天数
方法一:通过Calendar类得日期比较,在这需要考虑闰年和平年,也要考虑跨年份 /** * date2比date1多的天数 * @param date1 * @param date2 * @retu ...
- Django 创建app 应用,数据库配置
一.create project mkdir jango cd jango 目录创建project myapp django-admin startproject myapp 2.在给project创 ...
- Spring JdbcTemplate类常用的方法
execute(String sql) 可执行任何sql语句,但返回值是void,所以一般用于数据库的新建.修改.删除和数据表记录的增删改. int update(String sql) int ...
- Solr 8.2.0最新RCE漏洞复现
漏洞描述 国外安全研究员s00py公开了一个Apache Solr的Velocity模板注入漏洞.该漏洞可以攻击最新版本的Solr. 漏洞编号 无 影响范围 包括但不限于8.2.0(20191031最 ...
- html学习-第二集(CSS)
head标签里面添加style标签,可以为标签添加样式 id选择器 类选择器 标签选择器 层级选择器 组合选择器 属性选择器 <!DOCTYPE html> <html lang=& ...
- 数据表设计:多对多关系E-R图转换——中间表
链接:https://blog.csdn.net/vainfanfan/article/details/80568784 链接2:https://www.cnblogs.com/hiwangzi/p/ ...
- Map-HashMap 与 IF 判断内存占用对比
HashMap与IF判断内存占用对比,事实证明,Map对象在以下情况确实比IF判断占用内存低. HashMap占用内存:13000 package com.taiping.bky; import ja ...
- Java面向对象编程 -5
代码块 在程序之中使用"{}"定义的结构就称为代码块,而后根据代码块出现的位置以及定义的关键字的不同, 代码块可以分为 普通代码块 构造代码块 静态代码块 同步代码块 其中同步代码 ...
- Spring boot security权限管理集成cas单点登录
挣扎了两周,Spring security的cas终于搞出来了,废话不多说,开篇! Spring boot集成Spring security本篇是使用spring security集成cas,因此,先 ...