Duilib development basics: the process of creating custom controls, duilib controls

Source: Internet
Author: User

Duilib development basics: the process of creating custom controls, duilib controls

Reprinted, please describe the original source. Thank you ~ · Http: // blog.csdn.net/zhuhongshu/article/details/45362751


When using Duilib to develop the interface, in many cases, the control that comes with the Library does not meet the requirements, you need to create a custom control based on Duilib (a new control is painted, or a child form used to encapsulate win32, to display videos, webpages, etc ).
In the group, users who are new to Duilib often have questions about how to create their own custom controls, or the created controls cannot be created normally. I will write a simple blog to describe the complete process of creating custom controls and some precautions. In addition, it is helpful to encapsulate win32 subforms as controls.
Creating a custom control involves two steps: 1. inherit the existing control class to create a new control class 2. Let the program identify the new control and use it in xml.

Create a new control class:
First, select the most suitable control class from the existing Duilib control, inherit it, And then rewrite several interfaces. Here I take imitation cool dog skin in the form of a self-painted controls for example (original address: http://blog.csdn.net/zhuhongshu/article/details/38491389) imitation cool dog music box source code: http://blog.csdn.net/zhuhongshu/article/details/41037875






In order to make a skin swap control, select CButtonUI as the parent class, because the CButtonUI control itself contains normal, hot, pushed, and other statuses, and also contains click events.
# Ifndef SKIN_PICKER_PICTURE_ITEM_H # define SKIN_PICKER_PICTURE_ITEM_H // xml sample: <SkinPikerPictureItem name = "" width = "118" height = "70" bkimage = "UI \ BKImage \ 1small.jpg" bkname = "test" author = "Redrain"/> // class name and Interface Name, the CreateControl function uses const TCHAR parameters [] = _ T ("SkinPikerPictureItemUI"); const TCHAR kSkinPickerPictureItemInterface [] = _ T ("SkinPikerPictureItem "); // The Position of the Black foreground chart const TCHAR kSkinPickerPictureItemForeImage [] = _ T ("file = 'ui \ LeftTab \ listitem \ ListBk.png 'fade = '000000 '"); // border color, text color of the image name, text color of the author information const DWORD kBorderColor = 0xFF64B0FA; const DWORD kBkNameColor = 0 xffffffffff; const DWORD kAuthorColor = 0 xFFAAAAAA; class Identifier: public CButtonUI {public: Using (); LPCTSTR GetClass () const; LPVOID GetInterface (LPCTSTR pstrName); void SetAttribute (LPCTSTR pstrName, LPCTSTR pstrValue); void using (HDC hDC ); private: CDuiString m_BkName; CDuiString m_Author ;};# endif // SKIN_PICKER_PICTURE_ITEM_H


Response: Response () {m_Author = _ T ("Author:");} LPCTSTR CSkinPikerPictureItemUI: GetClass () const {return response;} LPVOID CSkinPikerPictureItemUI :: getInterface (LPCTSTR pstrName) {if (_ tcscmp (pstrName, kSkinPickerPictureItemInterface) = 0) return static_cast <attributes *> (this); return CButtonUI: GetInterface (pstrName );} void CSkinPikerPictu ReItemUI: SetAttribute (maid, maid) {if (_ tcscmp (pstrName, _ T ("bkname") = 0) m_BkName = pstrValue; else if (_ tcscmp (pstrName, _ T ("author") = 0) m_Author + = pstrValue; CButtonUI: SetAttribute (pstrName, pstrValue);} void CSkinPikerPictureItemUI :: paintStatusImage (HDC hDC) {CButtonUI: PaintStatusImage (hDC); if (IsFocused () m_uButtonState | = UISTATE_FOCUSED; else m_uButtonState & = ~ UISTATE_FOCUSED; if (! IsEnabled () m_uButtonState | = UISTATE_DISABLED; else m_uButtonState & = ~ UISTATE_DISABLED; if (m_uButtonState & UISTATE_PUSHED )! = 0 | (m_uButtonState & UISTATE_HOT )! = 0) {DrawImage (hDC, kSkinPickerPictureItemForeImage); // calculates the display position of the text of the author's information and the name of the background image, which is hard-coded, modify RECT rcBkName = m_rcItem; LONG nTextPadding = (m_rcItem.right-m_rcItem.left-CRenderEngine: GetTextSize (hDC, GetManager (), \ parse (), m_iFont, m_uTextStyle ). cx)/2; rcBkName. left + = nTextPadding; rcBkName. right-= nTextPadding; rcBkName. top + = 15; rcBkName. bottom = rcBkName. top + 20; RECT rcAuthor = m_rcItem; nTextPadding = (m_rcItem.right-direction-CRenderEngine: GetTextSize (hDC, GetManager (), \ m_Author.GetData (), m_iFont, m_uTextStyle ). cx)/2; rcAuthor. left + = nTextPadding; rcAuthor. right-= nTextPadding; rcAuthor. top + = 40; rcAuthor. bottom = rcAuthor. top + 20; CRenderEngine: DrawText (hDC, m_pManager, rcBkName, m_BkName, kBkNameColor, m_iFont, m_uTextStyle); CRenderEngine: DrawText (hDC, m_pManager, cursor, cursor, kAuthorColor, m_iFont, m_uTextStyle); CRenderEngine: DrawRect (hDC, m_rcItem, 2, kBorderColor );}}



The new control is named CSkinPickerPictureItemUI. Generally, after creating a new control, the first two functions to be overwritten are GetClass and GetInterface. They are then used to distinguish between the control type virtual functions, used to dynamically identify the control type and do the control type conversion.
The built-in controls of Duilib show that, for example, if the current custom control class is CSkinPickerPictureItemUI, the string SkinPickerPictureItemUI returned by the GetClass function. The GetInterface function determines whether to convert itself to the desired control type based on the input parameter and whether it matches its own string. The string used for matching in GetInterface should be the Tag Name of the corresponding control in xml. Here it should be SkinPickerPictureItem.
For example, for the CButtonUI class, GetClass corresponds to ButtonUI and GetInterface corresponds to Button. This is not mandatory, but it is important to maintain this style!

Theoretically, the most basic custom control is created after the two interfaces are completed. However, to enrich the behavior and appearance of custom controls, more functions need to be rewritten. Here I will describe the frequently rewritten functions!
Virtual void DoEvent (TEventUI & event); virtual void DoPaint (HDC hDC, const RECT & rcPaint); virtual void PaintBkColor (HDC hDC); virtual void PaintBkImage (HDC hDC ); virtual void PaintStatusImage (HDC hDC); virtual void PaintText (HDC hDC); virtual void PaintBorder (HDC hDC); virtual void DoInit (); virtual void SetAttribute (LPCTSTR pstrName, LPCTSTR pstrValue); virtual bool IsVisible () const; virtual void SetVisible (bool bVisible = true); virtual void SetInternVisible (bool bVisible = true); // only for internal calls, some UIS have window handles and need to override this function virtual void SetPos (RECT rc );



The functions listed above are the most frequently overwritten. DoEvent function: the core function of the control. It is a message processing function used to process various messages encapsulated by Duilib, for example, move and move the mouse, hover the mouse, double-click the mouse, right-click the mouse, obtain the focus, and set the cursor. Therefore, if your control needs to modify these behaviors, you must rewrite this function. For details, refer to the existing Duilib controls or cool dog simulation programs. 


DoPaint function: the core function of the control. It is the control's rendering processing function. When the Duilib underlying layer needs to re-draw the control, or the control calls the Invalidata function to force its own refresh, this function is triggered. In this function, background foreground, background color, text, and border are drawn in various States. This function calls PaintBkColor, PaintBkImage, PaintStatusImage, PaintText, PaintBorder, and other functions to complete various painting steps. So you can decide to rewrite DoPaint or just rewrite a few PaintXXX functions as needed. The DoPaint function is often used in combination with the DoEvent function. After a message is obtained for DoEvent, the control state is changed and the Invalidate function is called to re-paint the control.

SetAttribute function: Used to extend attributes of custom controls. The Duilib control itself contains attributes such as name, text, and bkimage. To add new attributes, You need to override this function to extend attributes, the above CSkinPickerPictureItemUI example is useful.

DoInit function: the function called by the container after the control is added to the container. Here, the entire Duilib program framework has been completed. You can rewrite this function when you need to perform some initial operations on the interface. A common usage is to create a Win32 subform and encapsulate it here, I will talk about the relevant content later.

IsVisible, SetVisible, SetInternelVisible, and SetPos: these functions are the same. When the control encapsulates Win32 subwindows, rewrite these functions to control the display, hide, and position of subwindows.

In this way, the custom control is created.
Recognize New controls:

After creating a custom control, you need to make it recognizable by the xml layout. Therefore, we need to complete Duilib's IDialogBuilderCallback interface and rewrite the CreateControl function in this interface.
Generally, the Form class can inherit the IDialogBuilderCallback interface and override CreateControl (the WindowImplBase form class that comes with DuiLib already inherits this interface, if you inherit WindowImplBase, you can directly override CreateControl ). The function is used to compare input strings. the pointer of the control is determined based on the string. The input string is the tag of the control in the xml file, such as the string Button in <Button/>.
CControlUI* CSkinPickerDialog::CreateControl(LPCTSTR pstrClass) {if (_tcsicmp(pstrClass, kSkinPickerPictureItemInterface) == 0)returnnew CSkinPikerPictureItemUI();return NULL;}


Traditionally, the Tag Name of the custom control in xml should be consistent with the judgment string in the GetInterface of the control, for example, SkinPickerPictureItem. In this way, when the tag SkinPickerPictureItem is parsed during xml parsing, The CSkinPickerPictureItemUI control is created.

In fact, anyone who inherits the IDialogBuilderCallback interface is certainly acceptable. For example, in QQDemo and cool dog, the custom control itself inherits this interface.
When the program responds to the WM_CREATE message, it creates a CDialogBuilder object and calls its Create method to parse the xml file.

CControlUI* CDialogBuilder::Create(STRINGorID xml, LPCTSTR type, IDialogBuilderCallback* pCallback, CPaintManagerUI* pManager, CControlUI* pParent)


The first parameter of this function is specified as the path of the xml file; the second parameter is generally specified as NULL. I will not explain it here; The third parameter is the key to identifying custom controls. This parameter must be specified as a pointer to class objects that inherit the IDialogBuilderCallback interface. For example, the form class inherits IDialogBuilderCallback, this parameter is the pointer of the Form class object. The custom control is recognized only when this parameter is entered. It is often asked why the custom control cannot be recognized. In most cases, it is not handled properly here;The fourth parameter specifies the CPaintManagerUI Class Object Pointer, which will certainly exist together with the Form class object. The last parameter is generally NULL.
After completing these steps, your custom control can be correctly identified and created by the xml layout. Now, the basic process of creating a custom control is complete! If you do not understand, you can look at the cool dog code, QQDemo and so on.

Encapsulate Win32 controls or Win32 subwindows:


If you want to add a video playback control to Duilib, the video playing library generally depends on a subwindow. In this case, you should customize a control and encapsulate and maintain a subwindow.
There are three types of encapsulated sub-Windows: the first is relatively simple, a sub-window is encapsulated, and a library dependency such as the video library is made; the second is troublesome. It encapsulates subwindows and processes subwindow messages. The third is similar to the second, encapsulates Win32 controls and processes their messages.

Encapsulate the subwindow:

In this case, you need to rewrite the DoInit and SetVisbile functions that I mentioned earlier. Declare the m_hWnd member variable of the HWND type in the custom control to save the child form pointer.
In the DoInit function, call the createjavaswex function to create a win32 subform and use m_hWnd to save the handle. For example:

m_hhWnd = CreateWindow(_T("#32770"), _T("WndMediaDisplay"), WS_VISIBLE | WS_CHILD, 0, 0, 0, 0, m_PaintManager.GetPaintWindow(), (HMENU)0, NULL, NULL);


Then, control the display and hiding of sub-forms in functions such as SetVisible. In the SetPos function, control the position of sub-forms within the control range.
In this way, the win32 subwindow is encapsulated, and the form handle can be used for video playback.
Encapsulate the subwindow and process its messages:

This is troublesome. For more information, see the CEditUI control of Duilib. We need to inherit from c0000wwnd and encapsulate another form class. The encapsulation of form classes does not fall within the scope of this article, so I will not elaborate on it. Override the HandleMessage function of the Form class to respond to various WM_XXX messages.
Then, in our custom control, the HWND type m_hWnd variable is no longer declared, but the object of the Form class just now is customized. Then, call the corresponding Create function in the DoInit function to Create a form class. Then, maintain the hide, position, and position of the form.
For the encapsulation of this control, refer to the webkit kernel browser control I wrote. It contains a complete Win32 subform encapsulated and processes its messages, displays Web pages rendered by the webkit kernel. Address: http://blog.csdn.net/zhuhongshu/article/details/38540711

Encapsulate the Win32 control and process its messages:

You can refer to the processing code of the CEditUI control. The idea is the same as encapsulating subwindows and processing messages. You can also refer to the webkit kernel browser control code. However, we need to rewrite two functions.
LPCTSTR GetWindowClassName() const;LPCTSTR GetSuperClassName() const;



Here, the most important thing is to process the GetSuperClassName function. This function is used for superclass, while encapsulating subwindows and processing messages are subclasses. The two operations are the opposite. In the GetSuperClassName function, the Win32 control is created after the corresponding class name of the Win32 control and the GetSuperClassName function is detected by Duilib. Now we can process the HandleMessage function to process messages of the Win32 control. For specific processing logic, see the CEditUI control.

Summary:
Let's talk about it here. Let's take a look at the basic steps of common custom controls. In actual development, we need to look at the Duilib source code to develop controls as expected, hope to help Duilib!

Redrain QQ: 491646717

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.