使用SOUI4中的STreeView控件
STreeView控件是一个基于虚表技术实现的高性能树形控件。
和STreeCtrl这种传统的树形控件将数据和控件固定在一起不同,STreeView数据和控件分离,使用一个adapter进行连接。
用过soui的朋友应该对soui提供的SListView很熟悉,SListView里可以轻松实现超大数据量的管理,显示,编辑等。和传统控件不同,在这种mvc框架下,控件占用的内存和数据量没有关系。
SListView使用起来相对简单,STreeView会相对复杂一点,这里专门写一篇小文章来介绍。
和使用SListView就是搞清楚使用IAdapter一样,使用STreeView就是要搞清楚如何实现ITvAdapter这个接口。
在C++的使用中,我们通常不会直接实现ITvAdapter, 而是使用soui提供的一个helper类:STreeAdapterBase
下面先看看这个类的实现。
1 template <class BaseClass>
2 class TvAdatperImpl : public BaseClass {
3 public:
4 void notifyBranchChanged(HSTREEITEM hBranch)
5 {
6 m_obzMgr.notifyChanged(hBranch);
7 }
8
9 /**
10 * Notifies the attached observers that the underlying data is no longer valid
11 * or available. Once invoked this adapter is no longer valid and should
12 * not report further data set changes.
13 */
14 void notifyBranchInvalidated(HSTREEITEM hBranch, bool bInvalidParents = true, bool bInvalidChildren = true)
15 {
16 m_obzMgr.notifyInvalidated(hBranch, bInvalidParents, bInvalidChildren);
17 }
18
19 void notifyBranchExpandChanged(HSTREEITEM hBranch, BOOL bExpandedOld, BOOL bExpandedNew)
20 {
21 m_obzMgr.notifyExpandChanged(hBranch, bExpandedOld, bExpandedNew);
22 }
23
24 //notify the item will be removed
25 void notifyItemBeforeRemove(HSTREEITEM hItem){
26 m_obzMgr.notifyItemBeforeRemove(hItem);
27 }
28
29 STDMETHOD_(void, registerDataSetObserver)(ITvDataSetObserver *observer) OVERRIDE
30 {
31 m_obzMgr.registerObserver(observer);
32 }
33
34 STDMETHOD_(void, unregisterDataSetObserver)(ITvDataSetObserver *observer) OVERRIDE
35 {
36 m_obzMgr.unregisterObserver(observer);
37 }
38
39 protected:
40 STvObserverMgr m_obzMgr;
41 };
这是基类,提供了常规的ITvAdapter和STreeView交互的方法。
1 template <typename T>
2 class STreeAdapterBase : public TObjRefImpl<TvAdatperImpl<ITvAdapter>> {
3 public:
4 STreeAdapterBase()
5 {
6 memset(m_rootUserData, 0, sizeof(m_rootUserData));
7 }
8 ~STreeAdapterBase()
9 {
10 }
11
12 struct ItemInfo
13 {
14 ULONG_PTR userData[DATA_INDEX_NUMBER];
15 T data;
16 };
17
18 //获取hItem中的指定索引的数据
19 STDMETHOD_(ULONG_PTR, GetItemDataByIndex)(HSTREEITEM hItem, DATA_INDEX idx) const OVERRIDE
20 {
21 if (hItem == ITEM_ROOT)
22 return m_rootUserData[idx];
23 ItemInfo &ii = m_tree.GetItemRef((HSTREEITEM)hItem);
24 return ii.userData[idx];
25 }
26
27 //保存hItem指定索引的数据
28 STDMETHOD_(void, SetItemDataByIndex)(HSTREEITEM hItem, DATA_INDEX idx, ULONG_PTR data) OVERRIDE
29 {
30 if (hItem == ITEM_ROOT)
31 m_rootUserData[idx] = data;
32 else
33 {
34 ItemInfo &ii = m_tree.GetItemRef((HSTREEITEM)hItem);
35 ii.userData[idx] = data;
36 }
37 }
38
39 STDMETHOD_(HSTREEITEM, GetParentItem)(HSTREEITEM hItem) const OVERRIDE
40 {
41 if (hItem == ITEM_ROOT)
42 return ITEM_NULL;
43 HSTREEITEM hParent = m_tree.GetParentItem((HSTREEITEM)hItem);
44 if (hParent == NULL)
45 hParent = ITEM_ROOT;
46 return (HSTREEITEM)hParent;
47 }
48
49 STDMETHOD_(BOOL, HasChildren)(HSTREEITEM hItem) const OVERRIDE
50 {
51 return GetFirstChildItem(hItem) != ITEM_NULL;
52 }
53
54 STDMETHOD_(HSTREEITEM, GetFirstChildItem)(HSTREEITEM hItem) const OVERRIDE
55 {
56 SASSERT(hItem != ITEM_NULL);
57 return (HSTREEITEM)m_tree.GetChildItem((HSTREEITEM)hItem, TRUE);
58 }
59
60 STDMETHOD_(HSTREEITEM, GetLastChildItem)(HSTREEITEM hItem) const OVERRIDE
61 {
62 SASSERT(hItem != ITEM_NULL);
63 return (HSTREEITEM)m_tree.GetChildItem((HSTREEITEM)hItem, FALSE);
64 }
65
66 STDMETHOD_(HSTREEITEM, GetPrevSiblingItem)(HSTREEITEM hItem) const OVERRIDE
67 {
68 SASSERT(hItem != ITEM_NULL && hItem != ITEM_ROOT);
69 return (HSTREEITEM)m_tree.GetPrevSiblingItem((HSTREEITEM)hItem);
70 }
71
72 STDMETHOD_(HSTREEITEM, GetNextSiblingItem)(HSTREEITEM hItem) const OVERRIDE
73 {
74 SASSERT(hItem != ITEM_NULL && hItem != ITEM_ROOT);
75 return (HSTREEITEM)m_tree.GetNextSiblingItem((HSTREEITEM)hItem);
76 }
77
78 STDMETHOD_(BOOL,IsDecendentItem)(CTHIS_ HSTREEITEM hItem,HSTREEITEM hChild) const OVERRIDE{
79 HSTREEITEM hParent = GetParentItem(hChild);
80 while(hParent){
81 if(hParent == hItem)
82 return TRUE;
83 hParent = GetParentItem(hParent);
84 }
85 return FALSE;
86 }
87
88 STDMETHOD_(int, getViewType)(HSTREEITEM hItem) const OVERRIDE
89 {
90 return 0;
91 }
92
93 STDMETHOD_(int, getViewTypeCount)() const OVERRIDE
94 {
95 return 1;
96 }
97
98 STDMETHOD_(void, getView)(THIS_ HSTREEITEM hItem, SItemPanel *pItem, SXmlNode xmlTemplate)
99 {
100 }
101
102 STDMETHOD_(void, getView)
103 (THIS_ HSTREEITEM hItem, IWindow *pItem, IXmlNode *pXmlTemplate) OVERRIDE
104 {
105 SItemPanel *pItemPanel = sobj_cast<SItemPanel>(pItem);
106 SXmlNode xmlTemplate(pXmlTemplate);
107 return getView(hItem, pItemPanel, xmlTemplate);
108 }
109
110 STDMETHOD_(void, getViewDesiredSize)(SIZE *ret,HSTREEITEM hItem, SItemPanel *pItem, int wid, int hei)
111 {
112 pItem->GetDesiredSize(ret,wid, hei);
113 }
114
115 STDMETHOD_(void, getViewDesiredSize)
116 (SIZE *ret,HSTREEITEM hItem, IWindow *pItem, int wid, int hei) OVERRIDE
117 {
118 SItemPanel *pItemPanel = sobj_cast<SItemPanel>(pItem);
119 getViewDesiredSize(ret,hItem, pItemPanel, wid, hei);
120 }
121
122 STDMETHOD_(void, InitByTemplate)(SXmlNode xmlTemplate)
123 {
124 (xmlTemplate);
125 }
126
127 STDMETHOD_(void, InitByTemplate)(IXmlNode *pXmlTemplate) OVERRIDE
128 {
129 SXmlNode xmlTemplate(pXmlTemplate);
130 return InitByTemplate(xmlTemplate);
131 }
132
133 STDMETHOD_(BOOL, isViewWidthMatchParent)() const OVERRIDE
134 {
135 return FALSE;
136 }
137
138 STDMETHOD_(void, ExpandItem)(HSTREEITEM hItem, UINT uCode) OVERRIDE
139 {
140 BOOL bExpandedOld = IsItemExpanded(hItem);
141 BOOL bExpandedNew = bExpandedOld;
142 switch (uCode)
143 {
144 case TVC_COLLAPSE:
145 bExpandedNew = FALSE;
146 break;
147 case TVC_EXPAND:
148 bExpandedNew = TRUE;
149 break;
150 case TVC_TOGGLE:
151 bExpandedNew = !bExpandedOld;
152 break;
153 }
154 if (bExpandedOld == bExpandedNew)
155 return;
156
157 SetItemExpanded(hItem, bExpandedNew);
158 notifyBranchExpandChanged(hItem, bExpandedOld, bExpandedNew);
159 }
160
161 STDMETHOD_(BOOL, IsItemExpanded)(HSTREEITEM hItem) const OVERRIDE
162 {
163 if (hItem == ITEM_ROOT)
164 return TRUE; //虚拟根节点自动展开
165 return (BOOL)GetItemDataByIndex(hItem, DATA_INDEX_ITEM_EXPANDED);
166 }
167
168 STDMETHOD_(void, SetItemExpanded)(HSTREEITEM hItem, BOOL bExpanded) OVERRIDE
169 {
170 SetItemDataByIndex(hItem, DATA_INDEX_ITEM_EXPANDED, bExpanded);
171 }
172
173 STDMETHOD_(BOOL, IsItemVisible)(HSTREEITEM hItem) const OVERRIDE
174 {
175 HSTREEITEM hParent = GetParentItem(hItem);
176 while (hParent != ITEM_NULL)
177 {
178 if (!IsItemExpanded(hParent))
179 return FALSE;
180 hParent = GetParentItem(hParent);
181 }
182 return TRUE;
183 }
184
185 STDMETHOD_(HSTREEITEM, GetFirstVisibleItem)() const OVERRIDE
186 {
187 return GetFirstChildItem(ITEM_ROOT);
188 }
189
190 STDMETHOD_(HSTREEITEM, GetLastVisibleItem)() const OVERRIDE
191 {
192 HSTREEITEM hItem = GetLastChildItem(ITEM_ROOT);
193 if (hItem == ITEM_NULL)
194 return hItem;
195 for (; IsItemExpanded(hItem);)
196 {
197 HSTREEITEM hChild = GetLastChildItem(hItem);
198 if (hChild == ITEM_NULL)
199 break;
200 hItem = hChild;
201 }
202 return hItem;
203 }
204
205 STDMETHOD_(HSTREEITEM, GetPrevVisibleItem)(HSTREEITEM hItem) const OVERRIDE
206 {
207 SASSERT(IsItemVisible(hItem));
208 HSTREEITEM hRet = GetPrevSiblingItem(hItem);
209 if (hRet == ITEM_NULL)
210 {
211 hRet = GetParentItem(hItem);
212 if (hRet == ITEM_ROOT)
213 hRet = ITEM_NULL;
214 }
215 return hRet;
216 }
217
218 STDMETHOD_(HSTREEITEM, GetNextVisibleItem)(HSTREEITEM hItem) const OVERRIDE
219 {
220 SASSERT(IsItemVisible(hItem));
221 if (IsItemExpanded(hItem))
222 {
223 HSTREEITEM hChild = GetFirstChildItem(hItem);
224 if (hChild != ITEM_NULL)
225 return hChild;
226 }
227
228 HSTREEITEM hParent = hItem;
229 while (hParent != ITEM_NULL && hParent != ITEM_ROOT)
230 {
231 HSTREEITEM hRet = GetNextSiblingItem(hParent);
232 if (hRet)
233 return hRet;
234 hParent = GetParentItem(hParent);
235 }
236 return ITEM_NULL;
237 }
238
239 STDMETHOD_(HRESULT, QueryInterface)(THIS_ REFGUID id, IObjRef **ppObj) OVERRIDE
240 {
241 return E_NOINTERFACE;
242 }
243
244 public:
245 HSTREEITEM InsertItem(const T &data, HSTREEITEM hParent = STVI_ROOT, HSTREEITEM hInsertAfter = STVI_LAST)
246 {
247 ItemInfo ii = { 0 };
248 ii.data = data;
249 return m_tree.InsertItem(ii, hParent, hInsertAfter);
250 }
251
252 void DeleteItem(HSTREEITEM hItem,BOOL bNotifyChange = TRUE)
253 {
254 HSTREEITEM hParent = GetParentItem(hItem);
255 if(!hParent) hParent = STVI_ROOT;
256 if(bNotifyChange){
257 notifyItemBeforeRemove(hItem);
258 }
259 m_tree.DeleteItem(hItem);
260 if(bNotifyChange) {
261 notifyBranchChanged(hParent);
262 }
263 }
264
265 BOOL DeleteItemEx(HSTREEITEM hItem)
266 {
267 return m_tree.DeleteItemEx(hItem);
268 }
269
270 const T &GetItemData(HSTREEITEM hItem) const
271 {
272 SASSERT(hItem != STVI_ROOT);
273 ItemInfo &ii = m_tree.GetItemRef((HSTREEITEM)hItem);
274 return ii.data;
275 }
276
277 void SetItemData(HSTREEITEM hItem, const T &data)
278 {
279 SASSERT(hItem != STVI_ROOT);
280 ItemInfo& ii = m_tree.GetItemRef((HSTREEITEM)hItem);
281 ii.data = data;
282 }
283 protected:
284 CSTree<ItemInfo> m_tree;
285 ULONG_PTR m_rootUserData[DATA_INDEX_NUMBER];
286 };
前面STDMETHOD_开头的方法是ITvAdatper的实现,后面部分方法是树结构的数据管理。
可以看到这个ITvAdapter使用了一个CSTree类来管理数据(该类是作者自己实现的一个多叉树数据结构)。
看起来接口的方法不少,实际上使用并没有那么复杂。
下面我们以xliveplayer这个播放器的房间显示TreeView来介绍使用方法。
先看一下这个STreeView的adapter实现,这个adapter有两层,外面是js, 里面是c++, js实现的具体逻辑,这里只要看C++层就够了。
1 typedef int TvKey;
2 class STvAdapter : public STreeAdapterBase<TvKey>, public JsThisOwner
3 {
4 public:
5 typedef STreeAdapterBase<TvKey> _baseCls;
6 public:
7 STvAdapter() {}
8
9 void notifyBranchChanged(HSTREEITEM hBranch)
10 {
11 _baseCls::notifyBranchChanged(hBranch);
12 }
13 void notifyBranchInvalidated(HSTREEITEM hBranch, bool bInvalidParents = true, bool bInvalidChildren = true)
14 {
15 _baseCls::notifyBranchInvalidated(hBranch, bInvalidParents, bInvalidChildren);
16 }
17
18 void notifyBranchExpandChanged(HSTREEITEM hBranch, BOOL bExpandedOld, BOOL bExpandedNew)
19 {
20 _baseCls::notifyBranchExpandChanged(hBranch, bExpandedOld, bExpandedNew);
21 }
22
23 HSTREEITEM InsertItem(TvKey key, HSTREEITEM hParent, HSTREEITEM hInsertAfter) {
24 return _baseCls::InsertItem(key, hParent, hInsertAfter);
25 }
26
27 HSTREEITEM GetChildItem(HSTREEITEM hParent,BOOL bFirst) const{
28 return bFirst?_baseCls::GetFirstChildItem(hParent): _baseCls::GetLastChildItem(hParent);
29 }
30
31 HSTREEITEM WINAPI GetParentItem(HSTREEITEM hItem) const{
32 return _baseCls::GetParentItem(hItem);
33 }
34
35 HSTREEITEM GetNextSibling(HSTREEITEM hItem) const {
36 return _baseCls::GetNextSiblingItem(hItem);
37 }
38
39 HSTREEITEM GetPrevSibling(HSTREEITEM hItem) const {
40 return _baseCls::GetPrevSiblingItem(hItem);
41 }
42
43 TvKey GetItemData(HSTREEITEM hItem) {
44 return _baseCls::GetItemData(hItem);
45 }
46
47 void SetItemData(HSTREEITEM hItem, TvKey key) {
48 _baseCls::SetItemData(hItem, key);
49 }
50
51 void DeleteItem(HSTREEITEM hItem,BOOL bNotifyChange) {
52 _baseCls::DeleteItem(hItem, bNotifyChange);
53 }
54
55 void DeleteAllItems() {
56 DeleteItem(STVI_ROOT,true);
57 }
58
59 void SetItemExpended(HSTREEITEM hItem, bool expended) {
60 _baseCls::SetItemExpanded(hItem, expended);
61 }
62
63 bool IsItemExpended(HSTREEITEM hItem) {
64 return _baseCls::IsItemExpanded(hItem)==TRUE;
65 }
66
67 void WINAPI ExpandItem(HSTREEITEM hItem, uint32_t mode) {
68 _baseCls::ExpandItem(hItem, mode);
69 }
70
71 public:
72 STDMETHOD_(void, getView)(THIS_ HSTREEITEM hItem, IWindow* pItem, IXmlNode* pXmlTemplate) OVERRIDE
73 {
74 if(!m_funGetView.IsFunction())
75 return;
76 Context* ctx = m_funGetView.context();
77 Value args[3];
78 args[0] = NewValue(*ctx, hItem);
79 args[1] = NewValue(*ctx, pItem);
80 args[2] = NewValue(*ctx, pXmlTemplate);
81 ctx->Call(GetJsThis(), m_funGetView, 3, args);
82 }
83
84 STDMETHOD_(int, getViewType)(HSTREEITEM hItem) const OVERRIDE
85 {
86 if(!m_funGetViewType.IsFunction())
87 return 0;
88 Context* ctx = m_funGetViewType.context();
89 Value args[1];
90 args[0] = NewValue(*ctx, hItem);
91 Value ret = ctx->Call(GetJsThis(), m_funGetViewType, 1, args);
92 if (ret.IsNumber()) {
93 return ret.ToInt32();
94 }
95 else
96 {
97 return 0;
98 }
99 }
100
101 STDMETHOD_(int, getViewTypeCount)() const OVERRIDE
102 {
103 if(!m_funGetViewTypeCount.IsFunction())
104 return 1;
105 Context* ctx = m_funGetViewTypeCount.context();
106 Value ret = ctx->Call(GetJsThis(), m_funGetViewTypeCount, 0, NULL);
107 return ret.ToInt32();
108 }
109
110 STDMETHOD_(void, InitByTemplate)(IXmlNode* pXmlTemplate) OVERRIDE
111 {
112 if(!m_funInitByTemplate.IsFunction())
113 return;
114 Context* ctx = m_funInitByTemplate.context();
115 Value args[1];
116 args[0] = NewValue(*ctx, pXmlTemplate);
117 ctx->Call(GetJsThis(), m_funInitByTemplate, 1, args);
118 }
119
120 STDMETHOD_(BOOL, isViewWidthMatchParent)() const OVERRIDE
121 {
122 if(!m_funIsViewWidthMatchParent.IsFunction())
123 return FALSE;
124 Context* ctx = m_funIsViewWidthMatchParent.context();
125 Value ret = ctx->Call(GetJsThis(), m_funIsViewWidthMatchParent, 0, NULL);
126 return ret.ToBool();
127 }
128
129 virtual const WeakValue& GetJsThis() const override {
130 if (m_cbHandler.IsObject())
131 return m_cbHandler;
132 else
133 return JsThisOwner::GetJsThis();
134 }
135 public:
136 static void Mark(STvAdapter* pThis, JS_MarkFunc* mark_fun) {
137 pThis->m_cbHandler.Mark(mark_fun);
138 pThis->m_funGetView.Mark(mark_fun);
139 pThis->m_funGetViewType.Mark(mark_fun);
140 pThis->m_funGetViewTypeCount.Mark(mark_fun);
141 pThis->m_funIsViewWidthMatchParent.Mark(mark_fun);
142 pThis->m_funInitByTemplate.Mark(mark_fun);
143 }
144
145 Value m_cbHandler;
146 Value m_funGetView,
147 m_funInitByTemplate,
148 m_funGetViewTypeCount,
149 m_funGetViewType,
150 m_funIsViewWidthMatchParent;
151 };
除了那些树结构相关的接口外,
我们需要关注的接口有下面几个(新手通常也就这几个接口的用法搞不清楚):
通知一个分支的数据及状态(展开,收缩)发生变化,刷新界面,包括子节点。
void notifyBranchChanged(HSTREEITEM hBranch)
通知一个节点的数据发生改变,刷新界面显示,后面两个参数控制是否刷新父节点或者子节点。
void notifyBranchInvalidated(HSTREEITEM hBranch, bool bInvalidParents = true, bool bInvalidChildren = true);
通知一个节点的展开状态发生变化。
void notifyBranchExpandChanged(HSTREEITEM hBranch, BOOL bExpandedOld, BOOL bExpandedNew);
明白了上面这几个方法,接下就是和SListView基本一样了,再实现下面几个和界面显示相关的方法即可:
初始化一个列表项,包含连接控件的事件。
STDMETHOD_(void, getView)(THIS_ HSTREEITEM hItem, IWindow* pItem, IXmlNode* pXmlTemplate) OVERRIDE
获取列表项的XML模板类型(当列表有多个模板时需要实现)
STDMETHOD_(int, getViewType)(HSTREEITEM hItem) const OVERRIDE
获取列表项的XML模板类型数量(当列表有多个模板时需要实现)
STDMETHOD_(int, getViewTypeCount)() const OVERRIDE
通过XML初始化adapter时调用,方便获取XML中配置的一些特定参数,一般不需要实现。
STDMETHOD_(void, InitByTemplate)(IXmlNode* pXmlTemplate) OVERRIDE
是否树节点占满一行,一般不需要实现。
STDMETHOD_(BOOL, isViewWidthMatchParent)() const OVERRIDE
具体使用方法参数SLivePlayer中的用法: https://github.com/soui4/soui4js
使用SOUI4中的STreeView控件的更多相关文章
- 在DevExpress程序中使用SplashScreenManager控件实现启动闪屏和等待信息窗口
在我很早的WInform随笔<WinForm界面开发之"SplashScreen控件">有介绍如何使用闪屏的处理操作,不过那种是普通WInform和DevExpress ...
- 在WPF中使用WinForm控件方法
1. 首先添加对如下两个dll文件的引用:WindowsFormsIntegration.dll,System.Windows.Forms.dll. 2. 在要使用WinForm控 ...
- wpf telerik中的book控件
下载 telerik中的书本控件,仅供学习使用.
- [原创]在Framelayout中放置button控件出现的覆盖问题
android Framelayout(帧布局)是很常用的布局,主要用来处理需要多个view叠加显示的情况. 然而在使用中,我发现Framelayout中的Button控件,会挡住所有其他控件,而不论 ...
- (转)客户端触发Asp.net中服务端控件事件
第一章. Asp.net中服务端控件事件是如何触发的 Asp.net 中在客户端触发服务端事件分为两种情况: 一. WebControls中的Button 和HtmlControls中的Type为su ...
- 在web中使用windows控件,实现摄像头功能
最近做的一个Web版的视频会议项目,需要在网页中播放来自远程摄像头采集的实时视频,我们已经有了播放远程实时视频的使用C#编写的windows控件,如何将其嵌入到网页中去了?这需要使用一种古老的技术,A ...
- WPF中的image控件的Source赋值
WPF中的Image控件Source的设置 1.XAML中 简单的方式(Source="haha.png"); image控件的Source设置为相对路径后(Source=&quo ...
- 在Web中使用Windows控件
版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 将Net控件转化为ActiveX控件 1GUID 2实现IObjectSafety接口 3程序集设定 制作安装程序 Web集 ...
- asp.net中的ListBox控件添加双击事件
问题:在Aspx页里的ListBox A中添加双击事件,将选中项添加到另一个ListBox B中,双击ListBox B中的选中项,删除当前选中项 页面: <asp:ListBox ID=&qu ...
- C#中的BackgroundWorker控件+Delegate.Invoke (委托同步调用)
C#中的BackgroundWorker控件+Delegate.Invoke (委托同步调用) 简单代码,记录一下.一个BackgroundWorker控件 backgroundWorkerRefr ...
随机推荐
- (系列十二)Vue3+.Net8实现用户登录(超详细登录文档)
说明 该文章是属于OverallAuth2.0系列文章,每周更新一篇该系列文章(从0到1完成系统开发). 该系统文章,我会尽量说的非常详细,做到不管新手.老手都能看懂. 说明:OverallAuth2 ...
- Yii2之model
记录model常用方法 between: $model->andFilterWhere(['between','apply_time',$startTime,$endTime])
- ZCMU-1129
数学公式题罢了 学长 1.斯特灵公式: 2.对数公式(因为以10为底,得到的是10^x,所以最后向下取整加上1): #include<cstdio> #include<cmath&g ...
- word常规操作
为何写标 招标: A公司要买100台电脑 [需求] 投标: 电脑公司看到招标后,就会投标:自我介绍(公司,产品,售后) [自我介绍满足需求] 中标: A公司选择XX公司 [选择] 保密价格内容 不能透 ...
- VTK 设置面片背面颜色
在上一篇文章切开了零件,发现零件内部和外部颜色一样,当需要不一样时,可以通过actor的SetBackfaceProperty方法设置背面属性. 代码跟上一篇几乎一样,只是给actor设置了SetBa ...
- 零基础学习人工智能—Python—Pytorch学习(十三)
前言 最近学习了一新概念,叫科学发现和科技发明,科学发现是高于科技发明的,而这个说法我觉得还是挺有道理的,我们总说中国的科技不如欧美,但我们实际感觉上,不论建筑,硬件还是软件,理论,我们都已经高于欧美 ...
- 腾讯云 TStor 统一存储通过信通院首批文件存储基础能力评测
在大数据上升为国家战略背景下,当前我国各行业.各领域正积极提升数据资源掌控能力和深度价值挖掘能力.存储作为数据基础设施建设的关键支柱,在国民经济发展过程中的重要性日益凸显. 2022年6月16日,中国 ...
- 渗透测试-前端加密分析之RSA加密登录(密钥来源服务器)
本文是高级前端加解密与验签实战的第6篇文章,本系列文章实验靶场为Yakit里自带的Vulinbox靶场,本文讲述的是绕过RSA加密来爆破登录. 分析 这里的代码跟上文的类似,但是加密的公钥是通过请求服 ...
- 【Python】【Pandas】使用concat添加行
添加行 t = pd.DataFrame(columns=["姓名","平均分"]) t = t.append({"姓名":"小红 ...
- mysql:sql create database新建utf8mb4 数据库
create database sina default character set utf8mb4 collate utf8mb4_unicode_ci;或者是create database con ...