CWaitingTreeCtrl

等待树控件是一款专为展示网络资源而设计的树形控件,可在用户展开节点时动态加载内容,支持加载动画和进度反馈。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CWaitingTreeCtrl

By Paolo Messina

What is it & Why?

My real intention, when I started this project, was to develop a tree control to display network resources. Enumerating network resources could be a lengthy operation, so I decided to actually do enumeration only when the user tries to expand an item. I realized soon that this kind of behavior could be useful to many other purposes, so I put all the code needed to have this behavior in a base class for my tree control, that was ready to use with other classes. I also added support for visual feedback, while an item is being populated.

When the user clicks to expand an item, a new item is added which contains a wait message. If you implement some animation inside the tree control the message is visible, otherwise it remains hidden. The blue rectangle is the area in which you can draw: you can do everything you want, even completely overwrite the wait message, as long as you stay within that area. Timed animations are also supported.

In the meantime, you can populate the item being expanded with new child items and the tree control will redraw itself to reflect the new content only when you have finished: the user will see only your animation. You may also choose not to display anything while populating, this is very easy.

I also added the ability to repaint the control while populating. The main thread is busy until the population process completes, this is "by design", but I noticed that it still receives WM_ERASEBKGND messages, at least on Win2K. So now I take a snapshot of the control before the process takes place and use that bitmap to redraw the control's background until the expanded item gets populated completely. (Please, report if this works on other platforms)

If you want to see some examples of what you can do with this class take a look at these articles:

Using the Class

This class provides a common interface for two types of derived classes: those providing animation effects and those providing the items for the tree control. Obviously you can implement a single class that provides both content and animation, but you may lose in code re-use.

If you keep the two implementations separated, you can:

  • focus your attention on the content provider class, which will handle the underlying tree control
  • choose a ready-to-use animation provider class to add visual feedback to your content provider class or create your own
  • leave the control without any animation (users won't see the wait message)
  • enable the wait message when you use your content provider class

Providing Tree Content

Just derive your class from CTreeCtrl and then replace each occurence of CTreeCtrl with CWaitingTreeCtrl in both your '.h' and '.cpp' files.

Collapse
class CMyTreeCtrl : public CWaitingTreeCtrl
{
...
};

Tip: if you want to use Class Wizard to generate message handlers later, you may temporarily change the base class in the BEGIN_MESSAGE_MAP macro to CTreeCtrl, but remember to restore it to the correct one (CWaitingTreeCtrl) and to change every call to the base implementation in the generated message handlers.

Collapse
BEGIN_MESSAGE_MAP(CMyTreeCtrl, CWaitingTreeCtrl)
//{{AFX_MSG_MAP(CMyTreeCtrl)

...
//}}AFX_MSG_MAP

END_MESSAGE_MAP()

To fill in the tree control with items you are required to override PopulateItem and to call PopulateRoot somewhere to insert items at the first level. You may also override WantsRefresh to automatically refresh some items whenever they are expanded by user.

CWaitingTreeCtrl::PopulateItem
Collapse
virtual void PopulateItem(HTREEITEM hParent)

This function gets called in the main thread after an item is expanded and the wait message is displayed. The animation takes place during the execution of this function and it is stopped when the function returns.

Tipically, you use the hParent parameter to get information about the parent item to populate and then you start adding new items. No redraw will happen until this function has finished, this is by design.

Also, there's currently no mean to abort this function, because it blocks the main thread, but you may create the underlying tree control in another user interface thread and provide your own means.

When you implement this function you have to remember the following rules:

  • you are supposed to add only one level of child items and you should only work with the hParent item and its children
  • you can always suppose that the hParent item has no children when the function gets called
  • you need to handle the special case in which hParent is TVI_ROOT
  • you should set the cChildren field of the TVITEM structure to <SPAN CLASS="cpp-literal">1 if you want that child item to be expandable
  • you should notify your progress to the base class (see below)

Returning TRUE means that the base class will check if you added any items and if it doesn't find any you will not be able to expand the hParent item again (the plus button will be removed).

Returning FALSE means that the hParent item will be always expandable, even if it has no children now. Note that it doesn't mean that the hParent item will be refreshed every time it's expanded, but that it will be expandable until it gets some children. If you want to refresh the hParent item each time it's expanded you have to override WantsRefresh.

Note: if you associate some data with each item you will probably handle the TVN_DELETEITEM notification. If you do so, you should ignore items that have the lParam field equals to zero. They could be the items used to display the wait message and they have no associated data. However this should not be a problem, since a zero value is tipically a NULL pointer.

CWaitingTreeCtrl::WantsRefresh
Collapse
virtual BOOL WantsRefresh(HTREEITEM hParent)

This function gets called just before PopulateItem, only if the hParent item already has children, to ask a derived class if it wants the item's children to be refreshed.

You have to override this function if you want an item to refresh its children whenever the user expand it. Remember that to refresh items that have no children, you have to tell the base class not to check for inserted items by returning FALSE in your PopulateItem override.

Return TRUE if you want to automatically refresh the item (in the sense described above), or FALSE if you don't want automatic refresh. The base class implementation simply returns FALSE.

CWaitingTreeCtrl::PopulateRoot
Collapse
void PopulateRoot()

You have to call this function somewhere in your derived class, if you want to see some items. A good place could be in your PreSubclassWindow or OnCreate override, but you may decide to have a function which initializes some data associated with the root item and then simulates a root expansion, populating the first level of items (PopulateItem is called with TVI_ROOT as the parent item).

You may also populate the first or some deeper levels of the tree without requiring the user to expand any items. A parent item that already has children won't be passed to PopulateItem, unless WantsRefresh says it must be refreshed. So static items are perfectly legal and can be used in conjunction with dynamic items.

CWaitingTreeCtrl::SetPopulationCount
Collapse
void SetPopulationCount(int iMaxSubItems, int iFirstSubItem = 0)

You should call this function in your PopulateItem override, before adding any item, to set the total count of items you plan to insert (iMaxSubItems) and the optional initial value (iFirstSubItem).

You should set the total count to zero if you don't know how many items you're going to insert.

CWaitingTreeCtrl::IncreasePopulation
Collapse
void IncreasePopulation(int iSubItemsToAdd = 1)

You should call this function in your PopulateItem override, when you insert a new item or a group of items. The current count is increased of the iSubItemsToAdd parameter, which can be a negative value.

CWaitingTreeCtrl::IncreasePopulation
Collapse
void UpdatePopulation(int iSubItems)

You should call this function in your PopulateItem override, when you insert a new item or a group of items. The current count is updated to the value of iSubItems.

Providing Animation

Create a generic class and derive it from CWaitingTreeCtrl. Later you may replace the base class with a template, so that you can use the class as a plug-in to add custom animations and visual effects to a generic CWaitingTreeCtrl-derived class. (I'm not familiar with templates, so there could be a better way to do it).

Collapse
template <class BASE_TYPE>
class CMyAnimationFX : public BASE_TYPE
{
...
};

There are two types of animations: those refreshing at specified time intervals and those getting updated only when new items are inserted by a content provider class.

To display an animation frame, you have to override DoAnimation. If you want to initialize some variables related to the message item, such as the position of the animation frames, you need to override PreAnimation and PostAnimation (only if you need to free some memory at the end).

In all these functions you should call the base class implementation, especially when not directly deriving from CWaitingTreeCtrl. This way, and using templates, you can add more than a single animation to your content provider class.

CWaitingTreeCtrl::PreAnimation
Collapse
virtual void PreAnimation(HTREEITEM hItemMsg)

This function gets called in the main thread just before the animation starts. Its only argument is the handle of the tree item displaying the wait message. You may use it to calculate the position in which to show the animation, but you shouldn't store it for later use. You can't assume the item still exists during the animation.

The wait message item is not visible by default, if you want to use its attributes to display something near to it, such as an animated item's image, or if you change its visual aspect, you have to call ShowWaitMessage in the constructor (or somewhere before entering this function).

You usually implement this function to initialize additional variables you may need during the animation. Remember that the hItemMsg item is a temporary item: you can use it only from inside this function, and only if the wait message is visible.

If you use the hItemMsg to draw something, you need to make it visible. If the message item is visible, you may also change the visual aspect of the tree control, such as scrolling the client area to properly displaying the animation. If the wait message is hidden the tree control can't redraw itself. You may have this situation if you don't draw the animation inside the tree control, but instead you use another window or control.

CWaitingTreeCtrl::DoAnimation
Collapse
virtual void DoAnimation(BOOL bTimerEvent, int iMaxSteps, int iStep)

This function gets called in a higher priority worker thread each time you need to update your animation. If the bTimerEvent argument is TRUE this function has been called when the timer interval elapsed, otherwise the item count has been updated. If you want to handle timer events you have to specify the timer period calling SetAnimationDelay before the animation starts, either in the constructor or in PreAnimation.

The other two arguments reflect the current progress of the enumeration process: iMaxSteps is the total number of steps of the process (zero means unknown), while iStep is the current step. You may choose to ignore these during a timer event. You tipically use this information to display a progress bar.

You need to implement this function to draw a new frame of your animation. If you draw within the tree control, you should only draw inside the rectangle obtained by calling GetItemRect(hItemMsg, lpRect, FALSE). Remember that you can't call this function here: you may use CTreeCtrl::GetItemRect or CWaitingTreeCtrl::GetItemImageRect only inside PreAnimation.

CWaitingTreeCtrl::PostAnimation
Collapse
virtual void PostAnimation()

This function gets called in the main thread just after the animation ends.

You have to implement this function only if you need to clean up some additional variables.

CWaitingTreeCtrl::SetAnimationDelay
Collapse
void SetAnimationDelay(UINT nMilliseconds)

You may call this function in the constructor, or in your PreAnimation override, to set the delay between timer events. A delay of zero means you don't need timer events and it is the initial value. If you want timer events you have to explicitly call this function.

Note that there is only one timer, so the last call to this function before the animation starts takes precedence (if you want to use multiple animation classes).

CWaitingTreeCtrl::GetItemImageRect
Collapse
BOOL GetItemImageRect(HTREEITEM hItem, LPRECT pRect)

You may call this function if you need to draw over an item's image, usually beside the wait message.

The return value is TRUE if the function is successful, FALSE otherwise.

Public Functions

There are also a few public functions that your content provider class will inherit.

CWaitingTreeCtrl::SetWaitMessage
Collapse
void SetWaitMessage(LPCTSTR pszText, HICON hIcon = NULL)

You may call this function to change the wait message's text and image. If the hIcon argument is NULL the item gets a blank icon.

CWaitingTreeCtrl::ShowWaitMessage
Collapse
void ShowWaitMessage()

You need to call this function in your animation provider class, either in the constructor or in any place before PreAnimation gets called, if you want to draw within the tree control. You are supposed to draw only in the rectangular area occupied by the wait message, so it must be visible. If you draw your animation in another window or if you use another control to provide visual feedback, you are not required to make the wait message visible.

You may also call this function if you don't have any animations, but you want the static wait message. Never call this function in your content provider class, the choice to display the message is left to the final user of your tree control.

Remember that the animation provider class should always assume that the wait message is not visible, and so it must show it if it needs to draw inside the control.

CWaitingTreeCtrl::RefreshSubItems
Collapse
void RefreshSubItems(HTREEITEM hParent)

You may call this function to manually refresh the hParent item's children. You can only refresh items that can be expanded, whether or not they actually have children. In fact you assign a button only to items that can be expanded by the user, and only those items can be refreshed.

Updates

17 Oct 2000
Initial public release.
27 Sep 2001
Fixed a bug with refreshing empty items and possibly some other things
Added background repainting while busy (at least on Win2k)
License changed to Artistic License

Conclusion

This class probably needs some adjustments, but it's enough for me now. I think you may better understand this class if you see some implementations, so take a look at the other articles (see top). I will appreciate any comment, suggestion or contribution. Any help to improve this (and the others) article is welcome, I know it's not easy for you to read and it has been difficult for me to write.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Paolo Messina


Paolo began programming at the age of 9 with a glorious 8086 and GW-BASIC, then he played a bit with C, ASM and Pascal. He tought himself MFC and Windows programming, to exploit his studies of C++. Always attracted by low-level programming and Assembly, he's beginning to appreciate the joys of templates and STL.

He lives in Follonica, Italy.

He has been abroad in the U.S. to work on his final thesis before graduating. For seven months he was playing with airplanes and automatic control at the Unversity of Illinois at Urbana-Champaign.

He graduated in Computer Science Engineering at the University of Pisa, Italy, in December 2003.

Currently working for an edutainment robotics company (www.robotechsrl.com).
Occupation: Software Developer
Company: RoboTech srl
Location: Italy Italy

From: http://www.codeproject.com/KB/tree/waitingtreectrl.aspx
标题基于SpringBoot+Vue的学生交流互助平台研究AI更换标题第1章引言介绍学生交流互助平台的研究背景、意义、现状、方法与创新点。1.1研究背景与意义分析学生交流互助平台在当前教育环境下的需求及其重要性。1.2国内外研究现状综述国内外在学生交流互助平台方面的研究进展与实践应用。1.3研究方法与创新点概述本研究采用的方法论、技术路线及预期的创新成果。第2章相关理论阐述SpringBoot与Vue框架的理论基础及在学生交流互助平台中的应用。2.1SpringBoot框架概述介绍SpringBoot框架的核心思想、特点及优势。2.2Vue框架概述阐述Vue框架的基本原理、组件化开发思想及与前端的交互机制。2.3SpringBoot与Vue的整合应用探讨SpringBoot与Vue在学生交流互助平台中的整合方式及优势。第3章平台需求分析深入分析学生交流互助平台的功能需求、非功能需求及用户体验要求。3.1功能需求分析详细阐述平台的各项功能需求,如用户管理、信息交流、互助学习等。3.2非功能需求分析对平台的性能、安全性、可扩展性等非功能需求进行分析。3.3用户体验要求从用户角度出发,提出平台在易用性、美观性等方面的要求。第4章平台设计与实现具体描述学生交流互助平台的架构设计、功能实现及前后端交互细节。4.1平台架构设计给出平台的整体架构设计,包括前后端分离、微服务架构等思想的应用。4.2功能模块实现详细阐述各个功能模块的实现过程,如用户登录注册、信息发布与查看、在线交流等。4.3前后端交互细节介绍前后端数据交互的方式、接口设计及数据传输过程中的安全问题。第5章平台测试与优化对平台进行全面的测试,发现并解决潜在问题,同时进行优化以提高性能。5.1测试环境与方案介绍测试环境的搭建及所采用的测试方案,包括单元测试、集成测试等。5.2测试结果分析对测试结果进行详细分析,找出问题的根源并
内容概要:本文详细介绍了一个基于灰狼优化算法(GWO)优化的卷积双向长短期记忆神经网络(CNN-BiLSTM)融合注意力机制的多变量多步时间序列预测项目。该项目旨在解决传统时序预测方法难以捕捉非线性、复杂时序依赖关系的问题,通过融合CNN的空间特征提取、BiLSTM的时序建模能力及注意力机制的动态权重调节能力,实现对多变量多步时间序列的精准预测。项目不仅涵盖了数据预处理、模型构建与训练、性能评估,还包括了GUI界面的设计与实现。此外,文章还讨论了模型的部署、应用领域及其未来改进方向。 适合人群:具备一定编程基础,特别是对深度学习、时间序列预测及优化算法有一定了解的研发人员和数据科学家。 使用场景及目标:①用于智能电网负荷预测、金融市场多资产价格预测、环境气象多参数预报、智能制造设备状态监测与预测维护、交通流量预测与智慧交通管理、医疗健康多指标预测等领域;②提升多变量多步时间序列预测精度,优化资源调度和风险管控;③实现自动化超参数优化,降低人工调参成本,提高模型训练效率;④增强模型对复杂时序数据特征的学习能力,促进智能决策支持应用。 阅读建议:此资源不仅提供了详细的代码实现和模型架构解析,还深入探讨了模型优化和实际应用中的挑战与解决方案。因此,在学习过程中,建议结合理论与实践,逐步理解各个模块的功能和实现细节,并尝试在自己的项目中应用这些技术和方法。同时,注意数据预处理的重要性,合理设置模型参数与网络结构,控制多步预测误差传播,防范过拟合,规划计算资源与训练时间,关注模型的可解释性和透明度,以及持续更新与迭代模型,以适应数据分布的变化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值