分类: C/C++
2008-09-14 20:17:47
Recently I was working in a project in which I had to draw data from a radio (or a spectrum analyzer). I reviewed all charting controls in CodeProject but none seemed to be useful for me. So, I managed to code it myself. In addition to simple charting, this controls also supports Zoom In/Out and scrolling. One can also discriminate higher data by another color as is seen in the picture.
First of all, place a Picture control on your dialog. Change its ID to IDC_SPECTRUM_STATIC
and its type from Frame
to Rectangle
. Change control's width and height to make it fit. This control will be created at run-time. Add #Include "SpectrumAnalyzer.h";
to your dialog's header file. Add a member variable to dialog for this control:
public:
CSpectrumAnalyzer m_SpectrumAnalyzer_Ctrl;
Now, place this piece of code wherever you want to create the control:
DWORD m_iStartFreq = 100000000, m_iStopFreq = 150000000; CPoint ptRangeX(m_iStartFreq, m_iStopFreq), // Freq. Range : 100-150 MHz ptRangeY(0, 120); // Signal Strength Range: 0-120 units CRect rect; // Get the rectangular coordinates of the rectangle we already placed on dialog GetDlgItem(IDC_SPECTRUM_STATIC)->GetWindowRect(rect); // Convert to the client coordinates ScreenToClient(rect); // remember to destroy it if it was created before if (m_SpectrumAnalyzer_Ctrl) m_SpectrumAnalyzer_Ctrl.Destroy(); // Create and place the spectrum control on screen m_SpectrumAnalyzer_Ctrl.Create(rect, this, IDC_SPECTRUM_STATIC, ptRangeX, ptRangeY);
The control is simply created by the above statements. ptRangeX
defines horizontal bounds and ptRangeY
defines vertical bounds.
These are the public member functions and their descriptions:
// Add a new point void AddPoint(CPoint CurPos); // Draw all viewable data void DrawLine(); // Write(draw) some text on the control void DrawText(CPoint Pos, CString szStr); // Clear all the drawing in the control void Clear(); // re-draw grids, re-write labels void UpdateLabels(); // clear list of data void ClearList(); // return number of points in the control int GetPointCount() { return m_pList->GetCount();}
Using a doubly-linked list to maintain data, the control determines which data points should be drawn (considering scroll position) and draws them.
The control defines three different scales: Actual data (point), Axis and View. Any data you provide is in the scales provided by ptRangeX
and ptRangeY
. The size of the control you place on dialog determines Axis scale. But, as is seen in the picture, user can define margins for top, bottom, left and right for the grids in the control. This defines View scale. So, any data you add to the list, should pass two stages to get drawn: conversion from Point to Axis (by MapPointToAxis()
function), and conversion from Axis to View scale (by MapAxisToView()
function).
In addition, you can change the color of background, grid, text, drawing pen and high-region pen by changing these variables in the constructor: m_crBackGround
, m_crGrids
, m_crText
, m_crDrawPen
and m_crIndicatorPen
.
Because this control was mainly written to be used as a receiver software, there are some extra features in it. You can highlight above-threshold data by using SetVHighIndicator()
function.
Control can also send callback messages to parent dialog. Control sends WM_USER_SET_TO_FREQ
message whenever user wants to set the radio to a new frequency by left-clicking the mouse while CTRL key is held. WM_USER_SHOW_CURRENT_FREQ
message is sent when user moves the mouse over the control. You may want to use this message to show frequency at the pointer.
Use these functions to set callback functions to those messages:
// Set the Callback message that control sends when // user clicks the control to set to a frequency m_SpectrumAnalyzer_Ctrl.SetCallbackSetToFreq(m_hWnd, WM_USER_SET_TO_FREQ); // Set the Callback message that control sends when user moves the mouse over control m_SpectrumAnalyzer_Ctrl.SetCallbackShowFreq(m_hWnd, WM_USER_SHOW_CURRENT_FREQ);
where m_hWnd
is the handle to the window that gets the messages.
One can revise the drawing section to improve speed. I think scrolling section is not wise, because it simply re-draws all the content in the window. One can use some API functions that "move" that portion of the image that is not changed by scrolling. Also, some function is needed for vertical scrolling. I have not written it here.