Vc mfc scroll bar Control

Source: Internet
Author: User

Here we will not talk about how to use the scroll bar, but how to customize the scroll bar control.

Scroll bar basics reference http://hi.baidu.com/3582077/blog/item/d30e5b38f8709aecb211c7c0.html

(PS: for the time being, we will first draw a horizontal scroll bar without considering the vertical scroll bar. With this foundation, a complete example will be provided later. You can simply look at the code without making it clear)

Self-painting is completed in the wm_paint message processing function of the scroll bar. The first step is to know the size of each component of the scroll bar, such as the width of the left button, the size of the slider position, and the size of the right channel. You can use the API function to obtain the information.Getscrollbarinfo. Let's introduce this function later. Let's take a look at a picture (obtained from the internet). It's clear and clear. We have a rough understanding of these components.

Then I defined the cnewscrollbar In the derived class of cscrollbar.Six variables crectCorresponds to the above information.

Crect m_clirect; // scroll bar size
Crect m_rcleftbutton; // size of the left arrow button
Crect m_rcrightbutton; // size of the right arrow button
Crect m_rcthumb; // slider position, size
Crect m_rcleftchannel; // the size of the left channel
Crect m_rcrightchannel; // the size of the left channel

Let's talk about how to assign values to them correctly. getscrollbarinfo only obtains some simple data, such as the button width, Slider position, and width. Those channels must be calculated by ourselves.

Getscrollbarinfo Function Definition:

Bool getscrollbarinfo (hwnd, // the handle of the scroll bar window, or the handle of the window with the attribute of the scroll bar (this is a false scroll bar that integrates with the window)

Long idobject, // if it is a scroll bar window handle, fill in objid_client. If it is a "fake scroll bar", fill in objid_hscroll horizontally, and vertical objid_vscroll

Pscrollbarinfo PSBI); // This structure contains information about the scroll bar.

(If the scrollbarinfo structure is undefined during code compilation, add # define winver 0x500 at the top of the stdafx. h header file)

Scrollbarinfo structure definition:

Typedef struct tagscrollbarinfo {
DWORD cbsize; // initialize the struct. The value must be sizeof (scrollbarinfo), that is, the struct size.
Rect rcscrollbar; // the size and position of the scroll bar. This is relative to the screen and is not limited by the parent window. That is, the size obtained by calling the getwindowrect function.
Int dxylinebutton; // button width (horizontal), or button height (vertical)
Int xythumbtop; // The left position (horizontal) of the slider and the top position (vertical) of the slider. This position is relative to the scroll bar.
Int xythumbbottom; // the right position (horizontal) of the slider and the bottom position (vertical) of the slider ). Relative to the scroll bar
Int reserved; // reserved...
DWORD rgstate [cchildren_scrollbar + 1]; // specifies the status of each component. For example, if a button is pressed and msdn is checked for details, this example will not be used.
} Scrollbarinfo, * pscrollbarinfo, * lpscrollbarinfo;
To save trouble, I calculated the information in the wm_paint message processing function. As follows:

// Obtain the scroll bar information, button size, and slider size.
Scrollbarinfo SBI;
SBI. cbsize = sizeof (scrollbarinfo );
: Getscrollbarinfo (this-> m_hwnd, objid_client, & SBI );
// Scroll bar size
M_clirect = SBI. rcscrollbar;
// Calculate the size of the left arrow button
M_rcleftbutton = crect (0, 0, SBI. dxylinebutton, m_clirect.height ());
// Calculate the right arrow button size
M_rcrightbutton = crect (m_clirect.width ()-SBI. dxylinebutton, 0,
M_clirect.width (), m_clirect.height ());
// Calculate the slider position
M_rcthumb = crect (SBI. xythumbtop, 0, SBI. xythumbbottom, m_clirect.height ());
// Calculate the size of the left channel
M_rcleftchannel = crect (SBI. dxylinebutton, 0, m_rcthumb.left, m_clirect.height ());
// Calculate the size of the right channel
M_rcrightchannel = crect (m_rcthumb.right, 0,
M_clirect.width ()-SBI. dxylinebutton, m_clirect.height ());

In fact, even if you do not do anything in wm_paint message processing and do not call the wm_paint message processing function of the parent class, the parent class also has the opportunity to draw a scroll bar, and we need to completely customize it, the parent class is not required for processing. This will always cause errors. For example, double-click the scroll bar and draw the scroll bar without passing the wm_paint message processing function ..

Therefore, we need to disable the parent class from processing wm_lbuttondblclk messages. The method is also very simple. Add the wm_lbuttondblclk message processing function to the cnewscrollbar, so that the function does not call the parent class double-click message processing function. Of course, this is just an example. The parent class will still be used to draw the scroll bar ..

For example, when the setscrollpos function is called to set the position of the scroll bar, the self-painting range is escaped again. The parent class is involved in drawing the scroll bar again...

Because setscrollpos is called to set the scroll bar position, the sbm_setscrollinfo message is sent to the scroll bar. In fact, the scrolling information is set by sending messages. The scroll bar is certainly drawn in the message processing function of the parent class .. So what we need to do is to intercept sbm_setscrollinfo and prevent the parent class from processing it...

However, there is a problem here. If the parent class is not allowed to be processed, the data cannot be connected .. After all, the information such as the position of the scroll bar must be processed by the parent class.

I have seen an example, that is, it is replaced by its own data, that is, the size and position of the page of the scroll bar, which is also stored and set by the new class.

This problem will be solved later. Now let's take a look at message sending.

The code example of sending a message to the parent window through the scroll bar. If you drag the scroll bar, the left and right buttons are clicked as follows:

Getparent ()-> sendmessage (wm_hscroll, makelong (sb_lineleft, 0), (lparam) This-> m_hwnd); // The Left (top) button is clicked

Getparent ()-> sendmessage (wm_hscroll, makelong (sb_lineright, 0), (lparam) This-> m_hwnd); // The right (bottom) button is clicked

Getparent ()-> sendmessage (wm_hscroll, makelong (sb_pageleft, 0), (lparam) This-> m_hwnd); // you can click

Getparent ()-> sendmessage (wm_hscroll, makelong (sb_pageright, 0), (lparam) This-> m_hwnd); // you can click

Getparent ()-> sendmessage (wm_hscroll, makelong (sb_thumbtrack, NPOs), (lparam) This-> m_hwnd); // drag the slider

Only the above five messages are used, and other messages are not required. Here we also talk about the sb_thumbtrace message. The parameters attached to this message must specify the slider position. That is, the NPOs, which is used to set the slider position for the caller. This pos requires us to find it by ourselves (when we drag the slider). Here I will give a simple calculation method. We can see that the Paster is for us to better understand this calculation method, suppose that the maximum slider position is 255 and the page size is 50.

I set the slider to a maximum position of 255 above, but when the actual slider position is 205, it will arrive at the beginning. The reason is that the page size is set to 50. So the scroll range of the slider position is 0 ~ 205 (minus page size 50 ). As you can see, the slider position ranges from 0 ~ 205, while the scrolling pixel range is 0 ~ 235. Then we can find the number of vertices (percentages) to scroll in one pixel)

That is 205/235. The specific application code is:

Define a double variable in the derived scroll bar class, store the ratio, a crect variable, and store the scroll size.

Double m_ratio; // Ratio

Crect m_clirect; // scroll bar size

In the wm_paint message processing function, calculate the ratio (the code used to calculate the scrolling information on the interface)

// Obtain the scroll bar information, page size, and slider position.
Scrollinfo Si;
Si. cbsize = sizeof (scrollinfo );
Getscrollinfo (& Si );
// The pixel range that the computing channel can scroll
Int chlwidth = m_clirect.width ()-SBI. dxylinebutton * 2-m_rcthumb.width ();
// Calculates the maximum position of the slider.
Int maxpos = Si. nMax-si.nPage;
// Calculate the ratio of one pixel.
M_ratio = (double) maxpos/chlwidth;

After finding the ratio, calculate the correct position of the scroll bar when you move the slider by dragging the mouse. Here, we also need to define some variables in the derived class, as shown below:

Bool m_istrace; // specifies whether the mouse is in the slider and the left mouse button is in the status

Int m_nsize; // The distance from the left side of the slider when you click the slider.

The m_nsize above is obtained by using the wm_lbuttondown message processing function. The figure above is used as an example. If the left mouse button is pressed at 248 pixels on the X axis, then the value of m_nsize is calculated.

It is 248-235. For details, refer to the Code in the wm_lbuttondown message processing function:

Void cnewscrollbar: onlbuttondown (uint nflags, cpoint point)

{

If (m_rcthumb.ptinrect (point ))
{
M_istrace = true;
M_nsize = point. The x-m_rcThumb.left;
Setcapture ();
}

// Cscrollbar: onlbuttondown (nflags, point); prevents the parent class from processing

}

In the wm_movemouse message processing function, the Code is as follows:

Void cnewscrollbar: onmousemove (uint nflags, cpoint point)
{
// Todo: add your message handler code here and/or call default
If (m_istrace)
{

//-17 is the button width on the left, which is replaced by a constant. If you want to dynamically calculate the button width, define a variable in the class. This will not be done here.
Int NPOs = (point. x-m_nSize-17) * m_ratio;

Getparent ()-> sendmessage (wm_hscroll, makelong (sb_thumbtrack, NPOs), (lparam) This-> m_hwnd );
}
// Cscrollbar: onmousemove (nflags, point );
}

Now, we have finally completed the most difficult sb_thumbtrack message sending. For the correct sending of the remaining several messages, refer to the Code in the project. I won't mention it here.

As mentioned earlier, sbm_setscrollinfo messages should be intercepted to prevent the parent class from being involved in drawing the scroll bar. Here we will simply handle it. Of course, this will have many drawbacks,

But this is learning to use, from simplicity to difficulty. Now we don't need to make any improvements. With this foundation, we can do it again when we need it later. This is an entry point.

Add the virtual function windowproc to the cnewscrollbar. The code for this function is as follows:

Lresult cnewscrollbar: windowproc (uint message, wparam, lparam)
{
// Todo: add your specialized code here and/or call the base class
If (Message = sbm_setscrollinfo)
{
Lresult res = cscrollbar: windowproc (message, wparam, lparam); // Let the parent class Process

// The cnewscrollbar does not have its own scroll bar information structure, so it must rely on its parent class. Calling the above function will allow the parent class to draw a scroll bar. This is what we don't want to see.

// Refresh immediately below. An unnecessary drawing is added here. To avoid this, you must have your own information structure, that is, scrollinfo.

// I will give a project later. This is a complete project, which I downloaded from the codeproject website, which avoids calling the parent windowproc method.
This-> invalidate (); // refresh now
Return res;
}
Return cscrollbar: windowproc (message, wparam, lparam );
}

Program running effect:

Click "button1" to set the scroll bar information.

I just drew a picture. If you are interested, you can use bitmap to draw it.

In addition, if you click the button quickly, there will be a certain interval and the speed will not keep up with the standard scroll bar. This is because the window class of the scroll bar supports double-clicking the mouse (cs_dblclks ), I don't know how the standard scroll bar is implemented. It supports double-clicking and fast enough. However, I can only remove the double-click attribute of the window class. I can't use double-click, which has no effect.

The method is to add the virtual function precreatewindow to the cnewscrollbar and change its window class when creating the scroll bar. As follows:

Bool cnewscrollbar: precreatewindow (createstruct & CS)
{

// Todo: add your specialized code here and/or call the base class
Wndclass wndcls;
// The window class name scrollbar, that is, wndcls. lpszclassname, which has been registered and used directly during creation
// The following function obtains the window class information, which is identified by wndcls. lpszclassname.
Getclassinfo (null, "scrollbar", & wndcls );
Wndcls. Style ^ = cs_dblclks; // remove the double-click attribute
Wndcls. lpszclassname = "newscrollbar"; // new window class name
CS. lpszclass = wndcls. lpszclassname;
Afxregisterclass (& wndcls); // register the window class
Return cscrollbar: precreatewindow (CS );
}

However, the above scroll bar does not work, and a double-click message is still generated because the scroll bar above is a resource in the dialog box. When it is created, it is not directly created through the precreatewindow function, then I guess I can call a function like subclasswindow to associate it with it.

Therefore, this method is only valid for the scroll bar created by calling the create function in the control. The code example for creating a scroll bar using the create function is as follows:

Cnewscrollbar m_sr;

Crect rect = crect (, 17 );

M_sr.create (ws_child | ws_visible, rect, this, 1002 );

After a try, there is no interval between clicking the response speed.

Engineering: http://ishare.iask.sina.com.cn/f/22477752.html

Remember to click "button1" to set the scroll information.

In addition, I downloaded from codeproject Project address: http://www.codeproject.com/KB/dialog/skinscrollbar.aspx this project is more complete, you can refer. I just reference it ......

If you implement the scroll bar hotspot function, you can use a timer to implement the function and judge it at intervals of time. (Cancel timing when the mouse leaves the scroll bar to save resources)

 

Http://hi.baidu.com/3582077/item/bb76bb564dc8589609be1721

 

Google:

Http://www.google.com.hk/#newwindow=1&safe=strict&q=%E6%94%B9%E5%8F%98%E6%BB%9A%E5%8A%A8%E6%9D%A1%E5% AE %BD%E5%BA%A6+vc&oq=%E6%94%B9%E5%8F%98%E6%BB%9A%E5%8A%A8%E6%9D%A1%E5% AE %BD%E5%BA%A6+vc&gs_l=serp.12...0.0.2.188.0.0.0.0.0.0.0.0..0.0...0.0...1c..9.serp.80bocRxN_94&bav=on.2,or.&bvm=bv.45373924,d.dGI&fp=676c413d4dea429e&biw=1600&bih=805

 

 

Replace a window's internal scrollbar with a customdraw scrollbar Control

Http://www.codeproject.com/Articles/14724/Replace-a-Window-s-Internal-Scrollbar-with-a-custo

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.