Click here to Skip to main content
15,885,985 members
Articles / Desktop Programming / MFC
Article

Knob-Slider Control

Rate me:
Please Sign up or sign in to vote.
3.83/5 (6 votes)
8 Oct 20032 min read 74.2K   1.9K   26   3
A custom user control that implements a knob slider.

Introduction

The purpose of this article is to show how a user control could be implemented. Also, its sample is useful for programmers who would like to use a rotating knob slider control, for which the example is provided.

Background

For any developer who wants to understand this sample and /or to implement a new one, it is required to know how to derive a new MFC control class from a standard one.

Using the code

The code could be used by inserting the KbutsliderCtrl class in your own project, and also by adding a new slider control in the resources. The class can be used directly by creating instances of it, or creating a new class derived from this one. The derivation is useful when the programmer wants to capture the OnLButtonUp and OnLButtonDown events.

Functions SetKnobNum and SetKnobPosi are used to set the number and position of each knob which is gliding on the circular channel. These functions also will update the control's window with the new parameters which are protected against overflow errors by using the % (modulo) operator. Of course in order to get the current position of each knob, function GetKnobPosi was implemented.

The KbutsliderCtrl class has some private functions which are used for some mathematical and graphical operations, as follows:

  • Function GetCurentAngle calculates the angle composed by the vertical axis, the central point, and the specified point (normally mouse's coordinates).
  • Function DetectNearestKnob scans the knobs in order to identify the knob with the nearest angle value with the specified value. In most of the cases, the last two functions are used together.
  • The function CalculateKnobPosi is used to calculate the position of a knob which has to stay on the channel and to describe a specified angle.
  • The functions DrawCircle, DrawBitmap, and DrawText are used to show parts of the graphical control.
  • The function DrawLine is used to substitute the function SetPixelV, which is optional.

The OnPaint routine is presented:

void KbutsliderCtrl::OnPaint() {
  int j;
  CPaintDC dc(this); // device context for painting
  CMemDC memDC(&dc); // derived memory context
  CMemDC *pDC = &memDC; // pointer to it
  int nRadius = m_nRadius;
  CRect rc;
  GetClientRect(rc);
  pDC->SelectStockObject(NULL_BRUSH);
  pDC->FillSolidRect(rc, ::GetSysColor(COLOR_BTNFACE));  
  DrawCircle(pDC, m_ptCenter, nRadius--, ::GetSysColor(COLOR_3DDKSHADOW),
    ::GetSysColor(COLOR_3DHIGHLIGHT));
  DrawCircle(pDC, m_ptCenter, nRadius, ::GetSysColor(COLOR_3DSHADOW),
    ::GetSysColor(COLOR_3DLIGHT));
  nRadius-=2;
  DrawCircle(pDC, m_ptCenter, nRadius--, ::GetSysColor(COLOR_3DHIGHLIGHT),
    ::GetSysColor(COLOR_3DDKSHADOW));
  DrawCircle(pDC, m_ptCenter, nRadius--, ::GetSysColor(COLOR_3DLIGHT),
    ::GetSysColor(COLOR_3DSHADOW));
  DrawBitmap(pDC,s_ButStateNew);
  for ( j=0; j<m_nKnobNum; j++ ) {
    const CPoint ptKnobCenter = CalculateKnobPosi(m_nKnobPosi[j]);
    int nKnobRadius = m_nKnobRadius;  
    const CRect rcKnob(ptKnobCenter.x - nKnobRadius,
      ptKnobCenter.y - nKnobRadius, ptKnobCenter.x + nKnobRadius,
      ptKnobCenter.y + nKnobRadius);
    CRgn rgnKnob;
    rgnKnob.CreateEllipticRgnIndirect(rcKnob);
    CBrush brKnob(::GetSysColor(COLOR_BTNFACE));
    pDC->FillRgn(&rgnKnob, &brKnob);
    rgnKnob.DeleteObject();
    if(m_bDragging) {
      DrawCircle(pDC, ptKnobCenter, --nKnobRadius,
        ::GetSysColor(COLOR_3DDKSHADOW),
        ::GetSysColor(COLOR_3DHIGHLIGHT));
      DrawCircle(pDC, ptKnobCenter, --nKnobRadius,
        ::GetSysColor(COLOR_3DSHADOW),
        ::GetSysColor(COLOR_3DLIGHT));
    } else {
      DrawCircle(pDC, ptKnobCenter, --nKnobRadius,
        ::GetSysColor(COLOR_3DHIGHLIGHT),
        ::GetSysColor(COLOR_3DDKSHADOW));
      DrawCircle(pDC, ptKnobCenter, --nKnobRadius,
        ::GetSysColor(COLOR_3DLIGHT),
        ::GetSysColor(COLOR_3DSHADOW));
    }
    if(GetFocus() == this) {
      DrawCircle(pDC, ptKnobCenter, nKnobRadius-2, RGB(0, 0, 0), TRUE);
      if ( j == m_nKnobCrt ) {
        DrawCircle(pDC, ptKnobCenter, nKnobRadius-4, RGB(0, 0, 0),
          TRUE);
      }
    }
  }
  DrawText(pDC);
}

Points of interest

The thing which I learned from this project is the fact that some internal state variables were necessary to be used together with window events in order to define the desired behavior of the control.

History

This is the first version of this kind of mixed control developed, which looks like a knob slider.

Acknowledgements

I would like to appreciate the help of code from Kyle Rule which I used for flicker free drawing context object. Also thanks to other developers who shared on this site, interesting source codes.

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


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralOne Correction Pin
Rick York9-Oct-03 6:36
mveRick York9-Oct-03 6:36 
GeneralHas some good points. Pin
WREY5-Oct-03 9:21
WREY5-Oct-03 9:21 
GeneralRe: Has some good points. Pin
Stewenson6-Oct-03 21:02
Stewenson6-Oct-03 21:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.