Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Knob-Slider Control

0.00/5 (No votes)
8 Oct 2003 1  
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