2019年11月

参考说明:

https://www.codeproject.com/Articles/1401/Changing-Row-Height-in-an-owner-drawn-Control

如果所有项的高度调整成一样,简便的方法

Problem/Solution:
You can easily change the row height by making the image list icon size to your desired size (and fool the user by drawing your icon not to the actual size). E.g.:

imagelist.Create( 24, 24, ILC_COLOR4, 10, 10 ); 
m_cList.SetImageList( &imageList, LVSIL_SMALL ); 

Windows下ToolTips控件的使用心得

1.创建ToolTips控件,通常建议dwStyles参数设置为TTS_ALWAYSTIP | TTS_BALLOON,其中WS_POPUP参数不需要设置,默认自带

2.调用TTM_ADDTOOL增加一条工具提示时,建议uFlags指定TTF_IDISHWND | TTF_SUBCLASS参数,此时hwnd及uId均指定为HWND(弹提示的窗口句柄)

3.希望弹提示的窗口,如果是Static,必须指定SS_NOTIFY标志,其他窗口也需要有类似标志,否则,弹不出来

4.TTM_ADDTOOL的lpszText,允许字符串资源ID,也允许指定回调方式LPSTR_TEXTCALLBACK,同时也支持固定某个字符串(测试时发现动态分配的字符串会有问题,弹不出来)

5.调用TTM_ADDTOOL完后,建议均调用一次TTM_ACTIVATE。

6.MFC及WTL中调用函数AddTool要求rect及uId要么全有效,要么全无效,使用并不灵活。直接构建TTTOOLINFO信息填充相应内容更方便。

 

对于ComboBox之类特殊控件,希望下拉框中每个子项提示不同,请参考链接:

https://www.codeproject.com/Articles/10559/Neat-Tooltip-for-ComboBox

软件工作完成后,自然希望用户的范围不受语言限制,因此软件的多语言支持就基本是一个必须考虑的事情。

微软整的那个MUI,本质上类似于多语言资源文件,限制较多,实现也繁琐。

通过ini,加载不同的语言INI,通常所见软件的多语言实现并不难。

设计思路:

1.头文件中实现两个API:MultiLang_GetUiidString与MultiLang_GetBlockString

  第一个通过资源ID,得到多语言翻译后的内容,第二个通过分区块名、关键字名字,得到多语言翻译后的内容

2.两个API在任何一个第一次调用时,会做初始化。初始化动作:

   1)获取程序当前路径

   2)判断当前路径下Lang.ini是否存在

   3)如果存在,读取其中的Default块下,关键字Lang的内容(此Key用于手工指定使用某个语言INI)

   4)如果Lang.ini不存在或Lang关键字指定的ini文件不存在,则通过函数GetLocaleInfoA获取当前用户的缺省语言缩写

   5)组合Lang_语言缩写.ini,尝试当前程序路径下打开,打开成功则加载。

3.接口实现就简单了

#ifndef _MULTI_LANG_H_#define _MULTI_LANG_H_#ifdef __cplusplusextern "C"{#endif

/*****************************************************************************
* @brief : 通过界面ID获取相应的多语言翻译
* @author : xiaomw
* @date : 2019/8/20
* @inparam : ui_id 界面ID
* @inparam : strDefaultString 缺省内容
* @return :
****************************************************************************
*/ const char* MultiLang_GetUiidString(unsigned int ui_id, const char*strDefaultString);/*****************************************************************************
* @brief : 通过标识获取相应的多语言翻译
* @author : xiaomw
* @date : 2019/8/20
* @inparam : strBlock 标识
* @inparam : strDefaultString 缺省内容,同时,也是标识块下的唯一内容
* @return :
****************************************************************************
*/ const char* MultiLang_GetBlockString(const char* strBlock, const char*strDefaultString);/*定义两个宏,供使用*/#ifdef UNICODE#define MULTILANG_BY_UI_ID(ui_id, strDefault) (to_wstring(std::string(MultiLang_GetUiidString(ui_id, strDefault))).c_str()) #define MULTILANG_BY_BLOCK(strBlock, strDefault) (to_wstring(std::string(MultiLang_GetBlockString(strBlock, strDefault))).c_str()) #else #define MULTILANG_BY_ID(ui_id, strDef) (MultiLang_GetUidString(ui_id, strDef))) #define MULTILANG_BY_BLOCK(strBlock, strDef) ((MultiLang_GetBlockString(strBlock, strDef)) #endif#ifdef __cplusplus
};
#endif #endif //_MULTI_LANG_H_
/*****************************************************************************
* @brief : 通过界面ID获取相应的多语言翻译
* @author : xiaomw
* @date : 2019/8/20
* @inparam : ui_id 界面ID
* @inparam : strDefaultString 缺省内容
* @return :
****************************************************************************
*/ const char* MultiLang_GetUiidString(unsigned int ui_id, const char*strDefaultString)
{
CSimpleIniA
* lang_ini =_get_lang_ini();return lang_ini->GetValue("DefaultUI", std::to_string(ui_id).c_str(), strDefaultString);
}
/*****************************************************************************
* @brief : 通过标识获取相应的多语言翻译
* @author : xiaomw
* @date : 2019/8/20
* @inparam : strBlock 标识
* @inparam : strDefaultString 缺省内容,同时,也是标识块下的唯一内容
* @return :
****************************************************************************
*/ const char* MultiLang_GetBlockString(const char* strBlock, const char*strDefaultString)
{
CSimpleIniA
* lang_ini =_get_lang_ini();return lang_ini->GetValue(strBlock, strDefaultString, strDefaultString);
}
CSimpleIniA是一个开源的INI文件访问类,GITHUB上可以搜索到

 

上一篇文章中,WTL下Rollout控件并不支持随意调整子窗口的大小

现实有这个动态变化窗口控件、控件宽高的要求,因此对其进行扩展。

patch文件如下:

diff --git "a/AtlRollOutCtrl.h" "b/AtlRollOutCtrl.h"index 68566eb..2f585d4100644
--- "a/ARK-Breeding-Calculator/AtlRollOutCtrl.h"
+++ "b/ARK-Breeding-Calculator/AtlRollOutCtrl.h"@@-319,6 +319,15 @@ public:#define RCM_COLLAPSE                (RCM_BASE + 2)
 #define RCM_ISEXPANDED                (RCM_BASE + 3)
 #define RCM_GETRECT                    (RCM_BASE + 4)
+#define RCM_REINIT                    (RCM_BASE + 5)
+
+//Messages
+#define RCCM_BASE            (WM_USER + 2)
+//Ensures that the given rect is visible
+//WPARAM unused
+//LPARAM ptr to rect in screen space
+#define RCCM_ENSUREVISIBLE    (RCCM_BASE + 0)
+#define RCCM_RECALC_LAYOUT  (RCCM_BASE + 1)template<DWORD t_dwStyle, DWORD t_dwExStyle, DWORD t_dwExRolloutCtrlStyle>
 classCRolloutCtrlImplTraits
@@
-462,6 +471,7 @@ public:
MESSAGE_HANDLER(RCM_COLLAPSE, OnCollapse)
MESSAGE_HANDLER(RCM_ISEXPANDED, OnIsExpanded)
MESSAGE_HANDLER(RCM_GETRECT, OnGetRect)
+MESSAGE_HANDLER(RCM_REINIT, OnReInit)
COMMAND_CODE_HANDLER(BN_CLICKED, OnButtonClicked)
COMMAND_CODE_HANDLER(BN_SETFOCUS, OnButtonSetFocus)
ALT_MSG_MAP(
1)
@@
-594,6 +604,38 @@ public:return 1;
}
+ LRESULT OnReInit(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)+{+ m_Child.GetWindowRect(&m_rcExpanded);+ ScreenToClient(&m_rcExpanded);+ + HFONT hFont = m_Child.GetFont();//AtlGetDefaultGuiFont(); +SetFont(hFont);+ +CWindowDC dc(m_hWnd);+ HFONT hOldFont =dc.SelectFont(hFont);+SIZE ptTextExtent;+TCHAR szTitle[MAX_PATH];+GetWindowText(szTitle, MAX_PATH);+ dc.GetTextExtent(szTitle, -1, &ptTextExtent);+dc.SelectFont(hOldFont);+ + int cyButton = ptTextExtent.cy + 2 *m_sizeBorder.cy;+ + ::InflateRect(&m_rcExpanded, m_sizeBorder.cx, m_sizeBorder.cy);+ m_rcExpanded.bottom +=cyButton;+ + m_rcCollapsed =m_rcExpanded;+ m_rcCollapsed.bottom = m_rcCollapsed.top +cyButton;+ + SetWindowPos(NULL, &m_rcExpanded, SWP_NOMOVE | SWP_NOZORDER |SWP_NOACTIVATE);+ + //notify parent change layout. + ::SendMessage(::GetParent(m_hWnd), RCCM_RECALC_LAYOUT, 0, 0);+ + return 0;+}+ //Implementation voidInit()
{
@@
-681,13 +723,6 @@ public:

typedef CRolloutContainerImplTraits
<WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_CLIENTEDGE | WS_EX_CONTROLPARENT>CRolloutContainerTraits;-//Messages -#define RCCM_BASE (WM_USER + 2) -//Ensures that the given rect is visible -//WPARAM unused -//LPARAM ptr to rect in screen space -#define RCCM_ENSUREVISIBLE (RCCM_BASE + 0) -template<class T, class TBase = CWindow, class TWinTraits = CRolloutContainerTraits> class ATL_NO_VTABLE CRolloutContainerImpl : public CWindowImpl<T, TBase, TWinTraits>{
@@
-906,9 +941,19 @@ public:
MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
MESSAGE_HANDLER(DM_GETDEFID, OnGetDefId)
MESSAGE_HANDLER(RCCM_ENSUREVISIBLE, OnEnsureVisible)
+MESSAGE_HANDLER(RCCM_RECALC_LAYOUT, OnUpdateLayout)
COMMAND_CODE_HANDLER(BN_CLICKED, OnRolloutCtrlClicked)
END_MSG_MAP()
+ LRESULT OnUpdateLayout(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL&bHandled)+{+UpdateSliderRect();+InvalidateSlider();+UpdateLayout();+ + return 0;+}+LRESULT OnSize(UINT/*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL&bHandled)
{
m_sizePage.cx
= LOWORD(lParam);

主要增加两个消息,CRolloutCtrlImpl的RCM_REINIT消息,及CRolloutContainerImpl的RCCM_RECALC_LAYOUT消息

CRolloutCtrlImpl包装的子窗口调整好大小后,发送RCM_REINIT消息给CRolloutCtrlImpl

然后就会触发整个容器调整位置。