MFC 自定义树控件:树节点的样式与交互
在本教程中,将介绍如何在 MFC 应用程序中使用树控件 (CTreeCtrl
) 进行高级定制,包括设置字体、颜色、徽章、图标、节点的高度等。通过这些自定义设置,可以显著提升用户界面的交互性和视觉效果。
1. 树控件基本设置
首先,我们需要初始化树控件并进行一些基础的设置。以下代码展示了如何设置树控件的字体、背景色、选中项、悬停项等。
// 设置树控件的背景色、选中项、悬停项及文本颜色
m_treeCtrl.UpdateFont(FontType::FONT_SEGOE_UI, 16); // 设置字体
m_treeCtrl.SetDefaultBkColor(RGB(240, 240, 240)); // 浅灰色背景
m_treeCtrl.SetSelectedBkColor(RGB(0, 0, 255)); // 蓝色选中项
m_treeCtrl.SetHoverBkColor(RGB(255, 255, 0)); // 黄色悬停项
m_treeCtrl.SetDefaultTextColor(RGB(0, 0, 0)); // 默认黑色文本
m_treeCtrl.SetSelectedTextColor(RGB(255, 0, 255)); // 白色选中文本
m_treeCtrl.SetHoverTextColor(RGB(255, 0, 0)); // 红色悬停项文本
在这里,我们设置了树控件的字体为 Segoe UI,字号为 16。然后定义了不同状态下的背景色和文本颜色,包括默认状态、选中状态和悬停状态的颜色。
2. 设置树项的高度
通过调用 SetItemHeight
方法,我们可以设置树控件中每个树项的高度。此方法允许我们对树项进行自定义布局,使界面更符合设计要求。
// 设置树项高度
m_treeCtrl.SetItemHeight(50);
这段代码将树项的高度设置为 50,使得每个节点的显示区域更大,适合显示更多内容。
3. 插入节点并设置样式
树控件允许我们动态插入节点,并为每个节点设置不同的样式。以下是如何插入根节点和子节点,并为其设置背景色、图标、徽章等。
插入根节点
// 插入根节点及其子节点
HTREEITEM hRoot = m_treeCtrl.InsertItem(_T("Root Node"));
m_treeCtrl.SetNodeBkColor(hRoot, RGB(100, 100, 255)); // 蓝色背景
m_treeCtrl.SetItemIcon(hRoot, m_hIcon); // 设置图标
在此,我们插入了一个名为“Root Node”的根节点,并设置了它的背景色为蓝色,以及图标。
插入子节点并设置徽章
// 插入子节点及设置徽章
HTREEITEM hChild = m_treeCtrl.InsertItem(_T("Child Node"), hRoot);
m_treeCtrl.SetItemBadge(hChild, 20, 20, RGB(255, 0, 0), RGB(255, 255, 255)); // 红色徽章背景,白色徽章前景
m_treeCtrl.ShowItemBadgeNumber(hChild, 5); // 显示数字 5
m_treeCtrl.SetNodeTextColor(hChild, RGB(255, 0, 0));
此段代码展示了如何插入一个子节点并为其设置一个徽章,徽章的背景色为红色,前景色为白色,并且显示了数字 5。此外,还修改了子节点的文本颜色为红色。
插入圆点徽章节点
// 插入圆点徽章节点
HTREEITEM hDotNode = m_treeCtrl.InsertItem(_T("Dot Node"), hRoot);
m_treeCtrl.SetItemBadge(hDotNode, 20, 20, RGB(255, 0, 0), RGB(255, 255, 255)); // 设置徽章背景色和前景色
m_treeCtrl.ShowItemBadgeDotMode(hDotNode, 100, RGB(255, 0, 0), RGB(255, 255, 255)); // 显示圆点徽章
在这里,我们插入了一个带圆点徽章的节点,并为其设置了一个红色的圆点徽章,背景色为红色,前景色为白色。
插入加粗字体节点
// 插入加粗字体节点
HTREEITEM hBoldNode = m_treeCtrl.InsertItem(_T("Bold Node"), hRoot);
m_treeCtrl.SetItemBold(hBoldNode); // 设置加粗字体
我们还展示了如何将某个节点的字体设置为加粗样式,突出显示该节点。
4. 展开根节点
插入完所有节点后,我们可以使用 Expand
方法展开根节点,显示所有子节点。
// 展开根节点
m_treeCtrl.Expand(hRoot, TVE_EXPAND);
这会将根节点展开,显示其子节点,使得树结构更加清晰可见。
5. 头文件和源文件
以下是一些需要添加的代码结构,用于实现上述功能:
头文件代码
#if !defined(AFX_APREDTREECTRL_H__A4EABEC5_2E8C_11D1_B79F_00805F9ECE10__INCLUDED_)
#define AFX_APREDTREECTRL_H__A4EABEC5_2E8C_11D1_B79F_00805F9ECE10__INCLUDED_#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000#include <afxcmn.h>
#include <map>
#include <vector>/*** @brief 消息宏,用于向父窗口发送树项目单击的通知。* * 当用户单击树控件的项目时,父窗口会收到该消息。*/
#define ID_MSG_TREE_CLICK_ITEM WM_USER + 2080/*** @brief 字体类型枚举。*/
enum class FontType {FONT_TAHOMA,FONT_SEGOE_UI,FONT_MS_SANS_SERIF,FONT_ARIAL,FONT_WINGDINGS// 可以继续扩展其他字体
};/*** @brief CApredTreeCtrl 类* * CApredTreeCtrl 是一个继承自 MFC 的 CTreeCtrl 的自定义控件,扩展了以下功能:* - 为树控件的每个项目添加徽章(数字徽章、小圆点等)* - 支持项目的加粗显示* - 支持设置项目图标* - 自定义项目的背景颜色、文本颜色和悬停效果*/
class CApredTreeCtrl : public CTreeCtrl {
public:/*** @brief 树项目徽章的定义结构体。* * 描述了项目上的徽章类型、颜色及显示时间。*/typedef struct tagBADGE {HTREEITEM hTreeItem; ///< 树项目的句柄COLORREF badgeBackground; ///< 徽章背景颜色COLORREF badgeForeground; ///< 徽章前景(文字)颜色int width; ///< 徽章宽度int height; ///< 徽章高度int type; ///< 徽章类型:0(隐藏),1(小圆点),2(数字)int number; ///< 数字徽章显示的数字(仅当类型为数字时有效)int showTime; ///< 徽章的显示时间,单位为秒(0 表示永久显示)} BADGE;/*** @brief 动态声明宏,用于支持动态创建和 RTTI。*/DECLARE_DYNAMIC(CApredTreeCtrl)/*** @brief 构造函数:初始化控件的默认样式和资源。*/CApredTreeCtrl();/*** @brief 析构函数:释放分配的资源。*/virtual ~CApredTreeCtrl();/*** @brief 设置树项目的徽章。* * @param hItem 树项目句柄* @param width 徽章的宽度* @param height 徽章的高度* @param badgeBackground 徽章的背景颜色* @param badgeForeground 徽章的前景(文字)颜色*/void SetItemBadge(HTREEITEM hItem, int width = 20, int height = 20, COLORREF badgeBackground = RGB(255, 255, 255), COLORREF badgeForeground = RGB(0, 0, 0));/*** @brief 显示树项目的数字徽章。* * @param hItem 树项目句柄* @param number 徽章中显示的数字* @param badgeBackground 徽章的背景颜色,默认为白色* @param badgeForeground 徽章的前景(字体)颜色,默认为黑色*/void ShowItemBadgeNumber(HTREEITEM hItem, int number, COLORREF badgeBackground = RGB(255, 255, 255), COLORREF badgeForeground = RGB(0, 0, 0));/*** @brief 显示树项目的小圆点徽章。* * @param hItem 树项目句柄* @param nSecond 徽章显示的持续时间,单位为秒,0 表示永久显示 * @param badgeBackground 徽章的背景颜色,默认为白色* @param badgeForeground 徽章的前景(字体)颜色,默认为黑色*/void ShowItemBadgeDotMode(HTREEITEM hItem, int nSecond = 0, COLORREF badgeBackground = RGB(255, 255, 255), COLORREF badgeForeground = RGB(0, 0, 0));/*** @brief 隐藏树项目的徽章。* * @param hItem 树项目句柄*/void HideItemBadge(HTREEITEM hItem);/*** @brief 将树项目设置为加粗显示。* * @param item 树项目句柄*/void SetItemBold(HTREEITEM item);/*** @brief 取消树项目的加粗显示。* * @param item 树项目句柄*/void CancelItemBold(HTREEITEM item);/*** @brief 检查树项目是否为加粗状态。* * @param item 树项目句柄* @return BOOL 如果项目是加粗的,返回 TRUE;否则返回 FALSE。*/BOOL FindBoldItem(HTREEITEM item);/*** @brief 设置树项目的图标。* * @param hItem 树项目句柄* @param hIcon 图标句柄*/void SetItemIcon(HTREEITEM hItem, HICON hIcon);/*** @brief 设置默认背景色。* * @param color 背景色值*/void SetDefaultBkColor(COLORREF color);/*** @brief 设置选中项的背景色。* * @param color 选中项的背景色值*/void SetSelectedBkColor(COLORREF color);/*** @brief 设置悬停项的背景色。* * @param color 悬停项的背景色值*/void SetHoverBkColor(COLORREF color);/*** @brief 设置默认文本颜色。* * @param color 文本颜色值*/void SetDefaultTextColor(COLORREF color);/*** @brief 设置选中文本的颜色。* * @param color 选中文本的颜色值*/void SetSelectedTextColor(COLORREF color);/*** @brief 设置悬停项的文本颜色。* * @param color 悬停项文本的颜色值*/void SetHoverTextColor(COLORREF color);/*** @brief 为特定节点设置背景色。* * @param hItem 树项目句柄* @param color 节点的背景色*/void SetNodeBkColor(HTREEITEM hItem, COLORREF color);/*** @brief 为特定节点设置文本颜色。** @param hItem 树项目句柄* @param color 节点的文本颜色*/void CApredTreeCtrl::SetNodeTextColor(HTREEITEM hItem, COLORREF color);/*** @brief 刷新树控件,更新颜色显示。*/void Refresh();/*** @brief 刷新指定的树项目,更新颜色显示。** @param hItem 树项目句柄*/void RefreshItem(HTREEITEM hItem);/*** @brief 设置字体。** @param eFont 字体类型* @param nSize 字体大小*/void UpdateFont(FontType eFont, int nSize);protected:/*** @brief 绘制树项目右侧的展开/收起按钮。* * @param hItem 树项目句柄* @param hDC 设备上下文句柄* @param pRect 按钮的绘制区域*/void DrawItemButton(HTREEITEM hItem, HDC hDC, CRect* pRect);/*** @brief 绘制树控件中的所有可见项目。* * @param hDC 设备上下文句柄*/void DrawItems(HDC hDC);/*** @brief 绘制树项目的背景。** @param hDC 设备上下文句柄* @param hItem 树项目句柄* @param pRect 绘制区域*/void DrawBadge(HTREEITEM hItem, HDC hDC, CRect* pRect, const BADGE& badge);// 私有数据成员std::map<HTREEITEM, COLORREF> m_itemTextColors;///< 节点文本颜色存储std::map<HTREEITEM, COLORREF> m_itemBkColors; ///< 节点背景色存储std::map<HTREEITEM, BADGE> m_badges; ///< 存储每个树项目的徽章信息std::map<HTREEITEM, HICON> m_icons; ///< 存储每个树项目的图标信息std::vector<HTREEITEM> m_itemBolds; ///< 存储需要加粗显示的树项目HBRUSH m_hBrushItem[3]; ///< 树项目背景刷子(默认、选中、悬停)COLORREF m_crItemBk[3]; ///< 树项目背景颜色(默认、选中、悬停)COLORREF m_crText[3]; ///< 树项目文本颜色(默认、选中、悬停)HBRUSH m_hBrushBtn[3]; ///< 按钮的背景刷子HPEN m_hPenItem[3]; ///< 树项目边框画笔(默认、选中、悬停)HTREEITEM m_hHoverItem; ///< 当前鼠标悬停的树项目句柄BOOL m_bTracking; ///< 鼠标是否正在跟踪树项目(用于悬停效果)CFont m_font; ///< 树控件的字体public:// MFC 消息映射DECLARE_MESSAGE_MAP()/*** @brief 重载的 WM_PAINT 消息处理函数,用于自定义绘制树控件。*/afx_msg void OnPaint();/*** @brief 重载的 WM_MOUSEMOVE 消息处理函数,用于处理鼠标移动事件。*/afx_msg void OnMouseMove(UINT nFlags, CPoint point);/*** @brief 重载的 WM_MOUSEHOVER 消息处理函数,用于处理鼠标悬停事件。*/afx_msg void OnMouseHover(UINT nFlags, CPoint point);/*** @brief 重载的 WM_MOUSELEAVE 消息处理函数,用于处理鼠标移出控件的事件。*/afx_msg void OnMouseLeave();/*** @brief 重载的 WM_TIMER 消息处理函数,用于徽章的显示时间控制。*/afx_msg void OnTimer(UINT_PTR nIDEvent);/*** @brief 重载的 WM_LBUTTONDOWN 消息处理函数,用于处理鼠标左键单击事件。*/afx_msg void OnLButtonDown(UINT nFlags, CPoint point);/*** @brief 重载的 WM_CREATE 消息处理函数,用于初始化定时器。*/afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);/*** @brief 重载的 PreSubclassWindow 函数,用于初始化定时器和其他资源。*/virtual void PreSubclassWindow();/*** @brief 重载的 WM_DESTROY 消息处理函数,用于释放资源。*/afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
};#endif // !defined(AFX_APREDTREECTRL_H__A4EABEC5_2E8C_11D1_B79F_00805F9ECE10__INCLUDED_)
源文件代码
#include "pch.h"
#include "ApredTreeCtrl.h"#define ROFFSET 7 // 按钮距离右侧的偏移量
#define WIDE 10 // 按钮宽度
#define WIDE2 5 // 按钮宽度的一半
#define EXPANDED_WIDE 8 // 按钮展开时的宽度// 徽章类型定义
#define BADGE_HIDE 0 // 不显示徽章
#define BADGE_DOT 1 // 小圆点徽章
#define BADGE_NUMBER 2 // 数字徽章
#define BADGE_RECTANGLE 3 // 矩形徽章
#define BADGE_TRIANGLE 4 // 三角形徽章IMPLEMENT_DYNAMIC(CApredTreeCtrl, CTreeCtrl)/*** @brief 构造函数:初始化控件默认样式和资源。*/
CApredTreeCtrl::CApredTreeCtrl() {// 初始化背景刷子、边框画笔和颜色for (int i = 0; i < 3; ++i) {m_hBrushItem[i] = nullptr;m_hBrushBtn[i] = nullptr;m_hPenItem[i] = nullptr;}// 默认、选中、悬停的背景和文本颜色m_crItemBk[0] = RGB(255, 255, 255);m_crItemBk[1] = RGB(228, 229, 234);m_crItemBk[2] = RGB(236, 237, 241);m_crText[0] = RGB(28, 28, 28);m_crText[1] = RGB(28, 28, 28);m_crText[2] = RGB(28, 28, 28);m_hHoverItem = nullptr; // 当前没有悬停的项目m_bTracking = FALSE; // 鼠标未开始跟踪
}/*** @brief 析构函数:释放资源。*/
CApredTreeCtrl::~CApredTreeCtrl() {for (int i = 0; i < 3; ++i) {if (m_hBrushItem[i] != nullptr) ::DeleteObject(m_hBrushItem[i]);if (m_hBrushBtn[i] != nullptr) ::DeleteObject(m_hBrushBtn[i]);if (m_hPenItem[i] != nullptr) ::DeleteObject(m_hPenItem[i]);}
}BEGIN_MESSAGE_MAP(CApredTreeCtrl, CTreeCtrl)ON_WM_PAINT()ON_WM_MOUSEMOVE()ON_WM_MOUSEHOVER()ON_WM_MOUSELEAVE()ON_WM_TIMER()ON_WM_LBUTTONDOWN()ON_WM_CREATE()ON_WM_LBUTTONDBLCLK()
END_MESSAGE_MAP()/*** @brief 绘制展开/收起按钮。*/
void CApredTreeCtrl::DrawItemButton(HTREEITEM hItem, HDC hDC, CRect* pRect) {POINT pt[3]; // 三角形顶点if ((GetItemState(hItem, TVIS_EXPANDED) & TVIS_EXPANDED) == TVIS_EXPANDED) {// 项目已展开,绘制向下的三角形int nBottomOffset = (pRect->Height() - EXPANDED_WIDE) / 2;pt[0].x = pRect->right - ROFFSET - EXPANDED_WIDE;pt[0].y = pRect->bottom - nBottomOffset;pt[1].x = pRect->right - ROFFSET;pt[1].y = pRect->bottom - nBottomOffset;pt[2].x = pRect->right - ROFFSET;pt[2].y = pRect->bottom - nBottomOffset - EXPANDED_WIDE;} else {// 项目未展开,绘制向右的三角形int nBottomOffset = (pRect->Height() - WIDE) / 2;pt[0].x = pRect->right - ROFFSET - WIDE2;pt[0].y = pRect->bottom - nBottomOffset - WIDE;pt[1].x = pRect->right - ROFFSET - WIDE2;pt[1].y = pRect->bottom - nBottomOffset;pt[2].x = pRect->right - ROFFSET;pt[2].y = pRect->bottom - nBottomOffset - WIDE2;}::Polygon(hDC, pt, 3); // 绘制三角形
}/*** @brief 自定义绘制树控件。*/
void CApredTreeCtrl::OnPaint() {HDC hDC, hMemDC;HBITMAP hBitmap;RECT rcClient;for (int i = 0; i < 3; i++) {m_hBrushItem[i] = CreateSolidBrush(m_crItemBk[i]);m_hBrushBtn[i] = CreateSolidBrush(m_crText[i]);m_hPenItem[i] = ::CreatePen(PS_SOLID, 1, m_crText[i]);}PAINTSTRUCT ps;hDC = ::BeginPaint(m_hWnd, &ps); // 开始绘制GetClientRect(&rcClient);// 创建内存设备上下文和兼容位图hMemDC = ::CreateCompatibleDC(hDC);hBitmap = ::CreateCompatibleBitmap(hDC, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);::SelectObject(hMemDC, hBitmap);// 设置背景色HBRUSH hBrushBK = CreateSolidBrush(m_crItemBk[0]);::FillRect(hMemDC, &rcClient, hBrushBK);DeleteObject(hBrushBK);// 绘制子项DrawItems(hMemDC);// 将内存 DC 中的内容复制到窗口 DC::BitBlt(hDC, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, hMemDC, 0, 0, SRCCOPY);// 清理资源::EndPaint(m_hWnd, &ps);::DeleteObject(hBitmap);::DeleteDC(hMemDC);
}/*** @brief 绘制树控件的所有可见子项。*/
void CApredTreeCtrl::DrawItems(HDC hDC) {HTREEITEM hCurrentItem;int itemState;CRect rcClient, rcItem, rcText;GetClientRect(&rcClient);//Gdiplus::Graphics graphics(hDC);//graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);// 统一设置透明背景::SetBkMode(hDC, TRANSPARENT);// 获取第一个可见项hCurrentItem = GetFirstVisibleItem();do {if (GetItemRect(hCurrentItem, &rcItem, FALSE) && GetItemRect(hCurrentItem, &rcText, TRUE)) {rcText.right = rcItem.right - 16;rcText.left += 16;CRect fillRect(0, rcItem.top, rcClient.right, rcItem.bottom);if (rcItem.top > rcClient.bottom) {break;}// 背景颜色COLORREF nodeBackgroundColor = m_crItemBk[0]; // 默认背景色if (m_itemBkColors.find(hCurrentItem) != m_itemBkColors.end()) {nodeBackgroundColor = m_itemBkColors[hCurrentItem]; // 特定节点背景色}// 绘制背景:根据选中、悬停或特定节点背景色填充itemState = GetItemState(hCurrentItem, TVIF_STATE);COLORREF crText = m_crText[0];if (m_itemTextColors.find(hCurrentItem) != m_itemTextColors.end()) {crText = m_itemTextColors[hCurrentItem]; // 特定节点背景色}if (itemState & TVIS_SELECTED) {crText = m_crText[1];HRGN hRgn = CreateRoundRectRgn(rcItem.left, rcItem.top, rcItem.right, rcItem.bottom, 4, 4);::FillRgn(hDC, hRgn, m_hBrushItem[1]);::DeleteObject(hRgn);}else if (hCurrentItem == m_hHoverItem) {crText = m_crText[2];HRGN hRgn = CreateRoundRectRgn(rcItem.left, rcItem.top, rcItem.right, rcItem.bottom, 4, 4);::FillRgn(hDC, hRgn, m_hBrushItem[2]);::DeleteObject(hRgn);}else if (nodeBackgroundColor != m_crItemBk[0]) {// 为特定节点设置背景色HRGN hRgn = CreateRoundRectRgn(rcItem.left, rcItem.top, rcItem.right, rcItem.bottom, 4, 4);::FillRgn(hDC, hRgn, ::CreateSolidBrush(nodeBackgroundColor));::DeleteObject(hRgn);}// 处理根节点的三角形按钮和文本if (hCurrentItem == GetRootItem()) {::SetBkMode(hDC, TRANSPARENT); // 确保背景透明CRect rcBtn = rcText;rcBtn.right = rcText.left - 2;rcBtn.left = rcBtn.right - 30;rcBtn.left -= 8;DrawItemButton(hCurrentItem, hDC, &rcBtn); // 绘制展开/收起按钮}// 处理其他节点的展开按钮else if (ItemHasChildren(hCurrentItem)) {CRect rcBtn = rcText;rcBtn.right = rcText.left - 2;rcBtn.left = rcBtn.right - 30;rcBtn.left -= 8;DrawItemButton(hCurrentItem, hDC, &rcBtn); // 绘制展开/收起按钮}// 绘制图标(如果存在)if (m_icons.find(hCurrentItem) != m_icons.end()) {HICON hIcon = m_icons[hCurrentItem];DrawIconEx(hDC, 16, (rcItem.bottom - rcItem.top - 32) / 2, hIcon, 32, 32, 0, 0, DI_NORMAL);rcText.left += 32;}// 创建加粗字体LOGFONT lf;::GetObject(m_font, sizeof(LOGFONT), &lf);lf.lfWeight = FW_BOLD; // 设置加粗HFONT hFontBold = CreateFontIndirect(&lf); // 创建加粗字体// 绘制文本::SetTextColor(hDC, crText);CString strText = GetItemText(hCurrentItem);// 如果是加粗文本,选择加粗字体if (FindBoldItem(hCurrentItem)) {::SelectObject(hDC, hFontBold);::DrawText(hDC, strText, strText.GetLength(), &rcText, DT_LEFT | DT_VCENTER | DT_SINGLELINE);::DeleteObject(hFontBold); // 释放加粗字体资源}else {::SelectObject(hDC, m_font);::DrawText(hDC, strText, strText.GetLength(), &rcText, DT_LEFT | DT_VCENTER | DT_SINGLELINE);}// 是否有小圆点(如徽章)if (m_badges.find(hCurrentItem) != m_badges.end()) {BADGE& badge = m_badges[hCurrentItem];int x = rcItem.right - 18 - badge.width;int y = rcItem.top + (rcItem.Height() - badge.height) / 2;CRect rcBadge;rcBadge.left = x;rcBadge.right = rcBadge.left + badge.width;rcBadge.top = y;rcBadge.bottom = rcBadge.top + badge.height;if (badge.type == BADGE_NUMBER) {::SetTextColor(hDC, badge.badgeForeground);char szBuffer[32];sprintf_s(szBuffer, 32, "%d%s", min(badge.number, 9), badge.number > 9 ? "+" : "");DrawText(hDC, CString(szBuffer), (int)strlen(szBuffer), &rcBadge, DT_CENTER | DT_VCENTER | DT_SINGLELINE);}else {DrawBadge(hCurrentItem, hDC, &rcBadge, badge);}}}} while ((hCurrentItem = GetNextVisibleItem(hCurrentItem)) != NULL);
}void CApredTreeCtrl::DrawBadge(HTREEITEM hItem, HDC hDC, CRect* pRect, const BADGE& badge) {int x = pRect->left; // 徽章的 X 坐标int y = pRect->top; // 徽章的 Y 坐标// 调试输出徽章位置TRACE("Badge position: x = %d, y = %d, width = %d, height = %d\n", x, y, badge.width, badge.height);// 启用抗锯齿(GDI中的高级图形模式)SetGraphicsMode(hDC, GM_ADVANCED); // 启用高级图形模式SetBkMode(hDC, TRANSPARENT); // 背景透明// 设置笔和画刷,创建抗锯齿效果HBRUSH hBrush = CreateSolidBrush(badge.badgeBackground);HPEN hPen = CreatePen(PS_SOLID, 1, badge.badgeForeground); // 设置边框颜色SelectObject(hDC, hBrush);SelectObject(hDC, hPen);// GDI 绘制抗锯齿设置SetGraphicsMode(hDC, GM_ADVANCED); // 启用高级图形模式SetBkMode(hDC, TRANSPARENT); // 背景透明// 根据徽章的类型绘制图形switch (badge.type) {case BADGE_DOT:{// 绘制圆形徽章Ellipse(hDC, x, y, x + badge.width, y + badge.height); // 绘制一个圆形// 使用 m_font 绘制文本::SelectObject(hDC, m_font.GetSafeHandle()); // 设置字体::SetTextColor(hDC, badge.badgeForeground);RECT rcText = { x, y, x + badge.width, y + badge.height };::SetBkMode(hDC, TRANSPARENT); // 设置透明背景char szBuffer[32];sprintf_s(szBuffer, 32, "%d", badge.showTime); // 显示时间或其他数字DrawText(hDC, CString(szBuffer), -1, &rcText, DT_CENTER | DT_VCENTER | DT_SINGLELINE);}break;case BADGE_RECTANGLE:{// 绘制矩形徽章Rectangle(hDC, x, y, x + badge.width, y + badge.height); // 绘制矩形}break;case BADGE_TRIANGLE:{// 绘制三角形徽章DrawItemButton(hItem, hDC, pRect);}break;default:// 如果没有匹配的类型,可以选择默认行为break;}// 清理资源DeleteObject(hBrush);DeleteObject(hPen);// 恢复图形模式SetGraphicsMode(hDC, GM_COMPATIBLE); // 恢复为兼容模式,关闭抗锯齿
}/*** @brief 鼠标移动事件处理:更新当前悬停的项目。*/
void CApredTreeCtrl::OnMouseMove(UINT nFlags, CPoint point) {HTREEITEM hHoverItem = HitTest(point); // 根据鼠标位置获取悬停的树项目// 检查是否需要更新悬停项if (m_hHoverItem != hHoverItem) {// 如果之前有悬停项,恢复它的状态if (m_hHoverItem != NULL) {// 恢复之前悬停项的状态(比如取消高亮)RefreshItem(m_hHoverItem);}m_hHoverItem = hHoverItem; // 更新当前悬停项目if (m_hHoverItem != NULL) {// 更新当前悬停项的状态(比如高亮)RefreshItem(m_hHoverItem);}}// 追踪鼠标事件(只在第一次进入时设置)if (!m_bTracking) {TRACKMOUSEEVENT tme = {};tme.cbSize = sizeof(tme);tme.dwFlags = TME_HOVER | TME_LEAVE; // 追踪鼠标悬停和离开事件tme.hwndTrack = m_hWnd;tme.dwHoverTime = 10; // 鼠标停留时间阈值m_bTracking = _TrackMouseEvent(&tme);}CTreeCtrl::OnMouseMove(nFlags, point); // 调用基类的默认处理
}/*** @brief 鼠标悬停事件处理:可在此添加需要悬停时的逻辑。*/
void CApredTreeCtrl::OnMouseHover(UINT nFlags, CPoint point) {// 此处可以添加鼠标悬停特定逻辑CTreeCtrl::OnMouseHover(nFlags, point);
}/*** @brief 鼠标移出控件事件处理:重置悬停状态。*/
void CApredTreeCtrl::OnMouseLeave() {if (m_hHoverItem != nullptr) {// 清空悬停项目并刷新HTREEITEM hPreviousHoverItem = m_hHoverItem;m_hHoverItem = nullptr; // 清除悬停项// 刷新之前悬停项的区域CRect rcItem;if (GetItemRect(hPreviousHoverItem, &rcItem, FALSE)) {InvalidateRect(&rcItem, FALSE); // 仅刷新该项的区域}}m_bTracking = FALSE; // 停止鼠标事件追踪CTreeCtrl::OnMouseLeave(); // 调用基类的处理方法
}/*** @brief 定时器事件处理:控制徽章显示时间。*/
void CApredTreeCtrl::OnTimer(UINT_PTR nIDEvent) {if (nIDEvent == 1) { // 检测定时器 IDfor (auto& item : m_badges) {if (item.second.showTime > 0) { // 如果有计时的徽章item.second.showTime--; // 减少显示时间if (item.second.showTime == 0) { // 时间到达时隐藏徽章item.second.type = BADGE_HIDE;}// 只刷新当前徽章所在的项RefreshItem(item.first);}}}CTreeCtrl::OnTimer(nIDEvent);
}/*** @brief 鼠标左键点击事件处理:选中项目并通知父窗口。*/
void CApredTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point) {HTREEITEM hItem = HitTest(point); // 根据鼠标位置获取点击的树项目if (hItem != nullptr) {SelectItem(hItem); // 选中点击的项目GetParent()->SendMessage(ID_MSG_TREE_CLICK_ITEM, (WPARAM)hItem, 0); // 通知父窗口}CTreeCtrl::OnLButtonDown(nFlags, point); // 调用基类的默认处理
}/*** @brief 鼠标左键双击事件处理:展开或收起树项目。*/
void CApredTreeCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
{HTREEITEM hItem = HitTest(point);if (hItem != NULL && ItemHasChildren(hItem)) {// 获取该节点的矩形区域CRect rcItem;GetItemRect(hItem, &rcItem, TRUE); // 获取包含文本区域的矩形if (!rcItem.PtInRect(point)) {// 检查节点是否已经展开UINT nState = GetItemState(hItem, TVIS_EXPANDED); // 获取项的状态if (nState & TVIS_EXPANDED) {Expand(hItem, TVE_COLLAPSE);}else {Expand(hItem, TVE_EXPAND);}// 在展开或收起后,刷新该项RefreshItem(hItem);}}// 调用父类的处理方法CTreeCtrl::OnLButtonDblClk(nFlags, point);
}/*** @brief 设置树项目的徽章(背景色和前景色)。*/
void CApredTreeCtrl::SetItemBadge(HTREEITEM hItem, int width /*= 20*/, int height /*= 20*/, COLORREF badgeBackground /*= RGB(255, 255, 255)*/, COLORREF badgeForeground /*= RGB(255, 255, 255)*/) {if (m_badges.find(hItem) == m_badges.end()) {// 如果项目没有徽章,创建一个新的徽章记录BADGE badge = {hItem, // 树项目句柄badgeBackground, // 背景颜色badgeForeground, // 前景颜色width, // 徽章宽度height, // 徽章高度BADGE_DOT, // 徽章类型(小圆点)0, // 数字徽章的数字0 // 显示时间(0 表示永久显示)};m_badges[hItem] = badge;} else {// 更新现有徽章的信息BADGE& badge = m_badges[hItem];badge.badgeBackground = badgeBackground;badge.badgeForeground = badgeForeground;badge.width = width;badge.height = height;}
}/*** @brief 显示树项目的数字徽章。*/
void CApredTreeCtrl::ShowItemBadgeNumber(HTREEITEM hItem, int number, COLORREF badgeBackground /*= RGB(255, 255, 255)*/, COLORREF badgeForeground /*= RGB(0, 0, 0)*/) {if (m_badges.find(hItem) != m_badges.end()) {BADGE& badge = m_badges[hItem];badge.type = BADGE_NUMBER;badge.number = number;badge.badgeBackground = badgeBackground;badge.badgeForeground = badgeForeground;InvalidateRect(NULL, TRUE); // 刷新控件}
}/*** @brief 显示树项目的小圆点徽章。*/
void CApredTreeCtrl::ShowItemBadgeDotMode(HTREEITEM hItem, int nSecond /*= 0*/, COLORREF badgeBackground /*= RGB(255, 255, 255)*/, COLORREF badgeForeground /*= RGB(0, 0, 0)*/) {if (m_badges.find(hItem) != m_badges.end()) {BADGE& badge = m_badges[hItem];badge.type = BADGE_DOT;badge.showTime = nSecond; // 设置显示时长badge.badgeBackground = badgeBackground;badge.badgeForeground = badgeForeground;InvalidateRect(NULL, TRUE);}
}/*** @brief 隐藏树项目的徽章。*/
void CApredTreeCtrl::HideItemBadge(HTREEITEM hItem) {if (m_badges.find(hItem) != m_badges.end()) {BADGE& badge = m_badges[hItem];badge.type = BADGE_HIDE;badge.showTime = 0;InvalidateRect(NULL, TRUE);}
}/*** @brief 将树项目设置为加粗显示。*/
void CApredTreeCtrl::SetItemBold(HTREEITEM item) {if (!FindBoldItem(item)) {m_itemBolds.push_back(item); // 加入加粗列表InvalidateRect(NULL, TRUE); // 刷新控件}
}/*** @brief 取消树项目的加粗显示。*/
void CApredTreeCtrl::CancelItemBold(HTREEITEM item) {for (auto iter = m_itemBolds.begin(); iter != m_itemBolds.end(); ++iter) {if (*iter == item) {m_itemBolds.erase(iter); // 从加粗列表中移除break;}}InvalidateRect(NULL, TRUE); // 刷新控件
}/*** @brief 检查树项目是否为加粗状态。*/
BOOL CApredTreeCtrl::FindBoldItem(HTREEITEM item) {return std::find(m_itemBolds.begin(), m_itemBolds.end(), item) != m_itemBolds.end();
}/*** @brief 初始化时钟或其他资源。*/
int CApredTreeCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) {if (CTreeCtrl::OnCreate(lpCreateStruct) == -1) {return -1;}SetTimer(1, 1000, nullptr); // 设置定时器,间隔 1 秒return 0;
}/*** @brief 设置图标到树项目。*/
void CApredTreeCtrl::SetItemIcon(HTREEITEM hItem, HICON hIcon) {m_icons[hItem] = hIcon; // 存储图标InvalidateRect(NULL, TRUE); // 刷新控件
}/*** @brief 子类化窗口前的初始化。*/
void CApredTreeCtrl::PreSubclassWindow() {SetTimer(1, 1000, nullptr); // 初始化定时器CTreeCtrl::PreSubclassWindow();
}/*** @brief 设置默认背景色。*/
void CApredTreeCtrl::SetDefaultBkColor(COLORREF color) {m_crItemBk[0] = color;if (m_hBrushItem[0]) {::DeleteObject(m_hBrushItem[0]);}m_hBrushItem[0] = CreateSolidBrush(color);Refresh();
}/*** @brief 设置选中项背景色。*/
void CApredTreeCtrl::SetSelectedBkColor(COLORREF color) {m_crItemBk[1] = color;if (m_hBrushItem[1]) {::DeleteObject(m_hBrushItem[1]);}m_hBrushItem[1] = CreateSolidBrush(color);Refresh();
}/*** @brief 设置悬停项背景色。*/
void CApredTreeCtrl::SetHoverBkColor(COLORREF color) {m_crItemBk[2] = color;if (m_hBrushItem[2]) {::DeleteObject(m_hBrushItem[2]);}m_hBrushItem[2] = CreateSolidBrush(color);Refresh();
}/*** @brief 设置默认文本色。*/
void CApredTreeCtrl::SetDefaultTextColor(COLORREF color) {m_crText[0] = color;Refresh();
}/*** @brief 设置选中文本色。*/
void CApredTreeCtrl::SetSelectedTextColor(COLORREF color) {m_crText[1] = color;Refresh();
}/*** @brief 设置悬停文本色。*/
void CApredTreeCtrl::SetHoverTextColor(COLORREF color) {m_crText[2] = color;Refresh();
}/*** @brief 为特定节点设置背景色。*/
void CApredTreeCtrl::SetNodeBkColor(HTREEITEM hItem, COLORREF color) {m_itemBkColors[hItem] = color;Refresh();
}/*** @brief 为特定节点设置文本颜色。*/
void CApredTreeCtrl::SetNodeTextColor(HTREEITEM hItem, COLORREF color)
{m_itemTextColors[hItem] = color; // 设置指定节点的文本颜色Refresh(); // 刷新树控件以应用更改
}/*** @brief 刷新控件。*/
void CApredTreeCtrl::Refresh() {InvalidateRect(NULL, TRUE); // 强制重绘控件
}void CApredTreeCtrl::RefreshItem(HTREEITEM hItem)
{CRect rcItem;if (GetItemRect(hItem, &rcItem, FALSE)) { // 改为 FALSE,获取整个项的矩形区域InvalidateRect(&rcItem, FALSE); // 刷新整个项的区域}
}void CApredTreeCtrl::UpdateFont(FontType eFont, int nSize)
{LOGFONT logFont = { 0 };// 根据 FontType 枚举选择对应的字体switch (eFont){case FontType::FONT_TAHOMA:_tcscpy_s(logFont.lfFaceName, _T("Tahoma"));break;case FontType::FONT_SEGOE_UI:_tcscpy_s(logFont.lfFaceName, _T("Segoe UI"));break;case FontType::FONT_MS_SANS_SERIF:_tcscpy_s(logFont.lfFaceName, _T("MS Sans Serif"));break;case FontType::FONT_ARIAL:_tcscpy_s(logFont.lfFaceName, _T("Arial"));break;case FontType::FONT_WINGDINGS:_tcscpy_s(logFont.lfFaceName, _T("Wingdings"));break;// 可以继续添加其他字体default:_tcscpy_s(logFont.lfFaceName, _T("Segoe UI")); // 默认字体break;}// 设置字体的大小logFont.lfHeight = -nSize; // 字体大小为负值表示像素大小logFont.lfQuality = CLEARTYPE_QUALITY; // 清晰字体质量// 删除旧字体并创建新字体m_font.DeleteObject();m_font.CreateFontIndirect(&logFont);// 设置新的字体到控件SetFont(&m_font);
}
总结
通过上述代码,我们可以轻松实现树控件的个性化定制,设置节点的字体、颜色、徽章、图标等样式。这些功能不仅提升了用户体验,还能够增强界面的可操作性和美观度。你可以根据项目需求灵活调整设置,以达到最佳效果。如果 GDI 抗锯齿效果不理想,考虑使用 GDI+(Graphics)来绘制圆形和文本,它提供了更高质量的抗锯齿效果。
相关文章:
MFC 自定义树控件:树节点的样式与交互
在本教程中,将介绍如何在 MFC 应用程序中使用树控件 (CTreeCtrl) 进行高级定制,包括设置字体、颜色、徽章、图标、节点的高度等。通过这些自定义设置,可以显著提升用户界面的交互性和视觉效果。 1. 树控件基本设置 首先,我们需要…...
YOLOv8-ultralytics-8.2.103部分代码阅读笔记-loss.py
loss.py ultralytics\utils\loss.py 目录 loss.py 1.所需的库和模块 2.class VarifocalLoss(nn.Module): 3.class FocalLoss(nn.Module): 4.class DFLoss(nn.Module): 5.class BboxLoss(nn.Module): 6.class RotatedBboxLoss(BboxLoss): 7.class KeypointLoss(n…...
像素流送api ue多人访问需要什么显卡服务器
关于像素流送UE推流,在之前的文章里其实小芹和大家聊过很多,不过今天偶然搜索发现还是有很多小伙伴,在搜索像素流送相关的问题,搜索引擎给的提示有这些。当然这些都是比较短的词汇,可能每个人真正遇到的问题和想获取的…...
字符型注入‘)闭合
前言 进行sql注入的时候,不要忘记闭合,先闭合再去获取数据 步骤 判断是字符型注入 用order by获取不了显位,select也一样 是因为它是’)闭合,闭合之后,就可以获取数据了 最后就是一样的步骤...
评分规则的建模,用户全选就是满分10分(分数可自定义), 选2个5分, 选2个以下0分
子夜(603***854) 15:11:40 和各位讨论一下设计问题: 有个有业务场景: 有一组产品共4个产品(数目用户可自定义), 需要一套规则,比如如果用户全选就是满分10分(分数可自定义), 选2个5分, 选2个以下0分 又比如另一组产品 产品有个必选属性,如果选了其中所有的必选则5分, 其他项每1…...
Elasticsearch与NLP的深度融合:文本嵌入与向量搜索实战指南
Elasticsearch与NLP的深度融合:文本嵌入与向量搜索实战指南 引言 在当今信息爆炸的时代,如何从海量文本数据中快速准确地检索出相关信息,成为了一个迫切需要解决的问题。自然语言处理(NLP)技术的发展为这一挑战提供了新的解决方案。Elasticsearch,作为一个强大的搜索引…...
4. STM32_定时器
概述 什么是定时器: 定时器核心就是计数器,是使用精准的时基,通过硬件的方式,实现定时功能的器件。 定时器的工作原理: 主频时钟CLK通过PSC进行分频后产生定时器时钟TIM CLK,计数器CNT根据TIM CLK的频率…...
Mysql 深度分页问题及优化方案
Mysql 深度分页问题及优化方案 一、为什么 MySQL 深度分页慢?二、优化方案三、补充 一、为什么 MySQL 深度分页慢? 在数据量大时,深分页查询速度缓慢,主要原因是多次回表查询。 前言:N个条件为索引,id为主…...
前端性能优化技巧
前端性能优化技巧 1. 介绍 前端性能优化是确保网站或应用程序快速、响应迅速和流畅的关键。本文档将详细探讨提升前端性能的各种策略和最佳实践。 2. 资源加载优化 2.1 资源压缩 代码压缩:使用 Webpack、Terser 等工具压缩 JavaScript、CSS 文件文件大小压缩&a…...
taro使用createAsyncThunk报错ReferenceError: AbortController is not defined
解决办法: 1,安装这俩包:yet-another-abortcontroller-polyfill,event-target-polyfill 2,app.js import: import ‘event-target-polyfill’; import ‘yet-another-abortcontroller-polyfill’; 补充 但…...
Linux:systemd进程管理【1】
整体理解 要快速掌握Linux的systemd并覆盖80%的使用场景,以下是最重要的20%知识点: Systemd简介与核心功能: Systemd是一个系统和服务管理器,作为Linux系统的PID 1进程,负责启动和管理其他系统组件。它提供并行启动服…...
【Maven】继承和聚合
5. Maven的继承和聚合 5.1 什么是继承 Maven 的依赖传递机制可以一定程度上简化 POM 的配置,但这仅限于存在依赖关系的项目或模块中。当一个项目的多个模块都依赖于相同 jar 包的相同版本,且这些模块之间不存在依赖关系,这就导致同一个依赖…...
【线上问题记录 | 排查网络连接问题】
问题描述 现在有我们程序是部署在服务器A的,A链接的是B。程序从B的redis进行存储和取数据的。 我们的业务是: 信息展示,也就是如果发现机器有异常了,实时进行监控。突然发现有一天,信息显示延迟了。 然后我们就开始排查究竟什么原…...
springboot车辆管理系统设计与实现(代码+数据库+LW)
摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了车辆管理系统的开发全过程。通过分析车辆管理系统管理的不足,创建了一个计算机管理车辆管理系统的方案。文章介绍了车辆管理系统的系统分析部分&…...
独家|京东调整职级序列体系
原有的M、P、T、S主序列将正式合并为新的专业主序列P。 作者|文昌龙 编辑|杨舟 据「市象」独家获悉,京东已在近日在内部宣布对职级序列体系进行调整,将原有的M、P、T、S主序列正式合并为新的专业主序列P,合并后的职级体系将沿用原有专业序…...
Arrays.copyOfRange(),System.arraycopy() 数组复制,数组扩容
Arrays.copyOfRange() 当需要将数组中的 长度扩容时, 数组复制 使用 需要用到Arrays 类提供的的 参数解析 * param original the array from which a range is to be copied * param from the initial index of the range to be copied, inclusive * param to the final ind…...
Python学习37天
# 魔术方法 # 创建类Monster,默认为object的子类 class Monster: name None age None gender None def __init__(self, name, age, gender): self.name name self.age age self.gender gender # 重写魔术方法__str__输出实例对象信息…...
flask的第一个应用
本文编写一个简单的实例来记录下flask的使用 文章目录 简单实例flask中的路由 简单实例 flask的依赖包都安装好之后,我们就可以写一个最简单的web应用程序了,我们把这个应用程序命名为first.py: from flask import Flaskapp Flask(__name__)app.route(/…...
【论文格式】同步更新中
1横向和纵向坐标的坐标密度不能太大,显示太多看起来不好看,本课题组采用emf,目前使用页面内紧凑,600dpi 2Force(kN):k小写 3涉及到变量的,变量本身斜体...
Java-GUI(登录界面示例)
简述: 步骤: (1)构造界面(将组件对象加入容器对象,注意:应设定对容器对象的布局策略) (2)为界面加入事件响应处理(如单击按钮) 实现: 两种方式实现,只有用户名为"admin"且密码为…...
看华为,引入IPD的正确路径
目录 前言 引发重视 作者简介 前言 华为将 IPD 的引入过程归结为三步: 先僵化、后优化、再固化。 如果只是单纯模仿,在不清楚底层逻辑的情况下, 就开始走先僵化的流程,去搞削足适履式的引入。 开始执行后,你就…...
计算机毕业设计Spark+大模型知识图谱中药推荐系统 中药数据分析可视化大屏 中药爬虫 机器学习 中药预测系统 中药情感分析 大数据毕业设计
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
pcb线宽与电流
三十年一路高歌猛进的中国经济, 中国经历了几个三十年? 第一个三十年:以计划为导向。 第二个三十年:以经济为导向。 现在,第三个三十年呢? 应该是以可持续发展为导向。 传统企业摇摇欲坠, 新兴企…...
w~视觉~合集26
我自己的原文哦~ https://blog.51cto.com/whaosoft/12663170 #InternVL 本文设计了一个大规模的视觉-语言基础模型(InternVL),将视觉基础模型的参数扩展到60亿,并逐步与LLM对齐,利用来自不同来源的网络规模的图像-文…...
Qt支持RKMPP硬解的视频监控系统/性能卓越界面精美/实时性好延迟低/录像存储和回放/云台控制
一、前言 之前做的监控系统,已经实现了在windows上硬解码比如dxva2和d3d11va,后续又增加了linux上的硬解vdpau的支持,这几种方式都是跨系统的硬解实现方案,也是就是如果都是windows系统,无论X86还是ARM都通用…...
【Qt】图片绘制不清晰的问题
背景 实现一个图片浏览器,可以支持放大/缩小查看图片。主要组件如下: // canvaswidget.h #ifndef CANVASWIDGET_H #define CANVASWIDGET_H#include <QWidget>class CanvasWidget : public QWidget {Q_OBJECT public:explicit CanvasWidget(QImag…...
2008年IMO几何预选题第3题
设有两个圆凸内接四边形 A B Q D ABQD ABQD 和 B P Q C BPQC BPQC, 在线段 P Q PQ PQ 上存在一点 E E E, 使得, ∠ E A P ∠ E D Q \angle EAP\angle EDQ ∠EAP∠EDQ, ∠ E B P ∠ E C Q \angle EBP\angle ECQ ∠EBP∠ECQ. 求证: A A A, B B B, C C C, D D D 四点共…...
NAT拓展
NAT ALG(NAT应用级网) 为某些应用层协议,因为其报文内容可能携带IP相关信息,而普通NAT转化无法将这些IP转化,从而导致协议无法正常运行 例如FTP,DHCP,RSTP,ICMP,IPSEC…...
Flink四大基石之State
State state 可以理解为-- 历史计算结果 有状态计算和无状态计算 无状态计算: 不需要考虑历史数据, 相同的输入,得到相同的输出!如:map, 将每个单词记为1, 进来一个hello, 得到(hello,1),再进来一个hello,得到的还是(hello,1) 有状态计算: 需要考虑历史数据, 相同的输入,可…...
Spacy小笔记:zh_core_web_trf、zh_core_web_lg、zh_core_web_md 和 zh_core_web_sm区别
Spacy小笔记 最近频繁用到spacy,就小记一下。 2024.11.29 zh_core_web_trf、zh_core_web_lg、zh_core_web_md 和 zh_core_web_sm区别 首先,它们都是预训练的中文模型: zh_core_web_trf:395M 架构: 基于 Transformer 架构(bert…...
做网站备案需要哪些材料/百度seo建议
服务器登录密码被人改 内容精选换一换登录Windows操作系统的弹性云服务器时,需使用密码方式登录。因此,用户需先根据创建弹性云服务器时使用的密钥文件,获取该弹性云服务器初始安装时系统生成的管理员密码(Administrator帐户或Cloudbase-init…...
wordpress主题 标签/广告主资源哪里找
多列-column-rule-style列之间规则的样式 微信小程序交流群:111733917 | 微信小程序从0基础到就业的课程:https://edu.csdn.net/topic/huangjuhua 通用语法 定义和用法 column-rule-style 属性规定列之间的样式规则。 默认值: none 继承性&a…...
女朋友做网站/关键词收录
出人意料,去年哈佛最受欢迎的选修课是“幸福课”,听课人数超过了王牌课《经济学导论》。教这门课的是一位名不见经传的年轻讲师,名叫泰勒本-沙哈尔。 在一周两次的“幸福课”上,本-沙哈尔没有大讲…...
企业官方网站怎么查/太原百度seo
Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播,即协调已经有事务标识的方法之间的发生调用时的事务上下文的规则(是否要有独立的事务隔离级别和锁)概述 当我…...
政府单位官方网站建设/渠道推广有哪些方式
1.什么是索引 索引是一种特殊的数据库结构,有数据表中的一列或者多列组合而成,可以快速查询数据表中的值,相当于图书的目录,根据目录的页码快速找到所需内容 2.建立索引的原则 查询更快,占用空间小 1.定义主键的…...
学做家常菜的网站 知乎/营销渠道方案
以下是行业内了解到的一些情况。需要更多API调试请移步注册API账号 http://console.open.onebound.cn/console/?iRookie “detail_url”: “http://detail.m.1688.com/page/index.html?offerId634154940183&sortType&pageId&abBizDataTypecbuOffer&trace_log…...