ChartDirector 7.1 (C++ Edition)

Using ChartDirector with Other GUI Frameworks


This section is intended for developers that need to use ChartDirector with GUI frameworks that are not MFC or Qt based.

ChartDirector is designed to be GUI framework neutral and should work with all GUI frameworks. Because there is no standard GUI framework in C/C++ (some common ones are MFC, Qt, WTL, wxWindows, Cocoa, Tk, GTK, Motif), it is impractical for ChartDirector to include sample code for all possible GUI frameworks.

Instead, ChartDirector includes CChartViewer (a MFC control) and QChartViewer (a Qt widget), and releases them in source code format as part of the sample code. They are intended to serve as examples on how to use ChartDirector in typical GUI frameworks. Developers that need to use other GUI frameworks may use them as references.

In this section, we will describe the key steps of using ChartDirector in a typical GUI framework, using the MFC and Qt as examples.

Displaying Charts On Screen

ChartDirector can output charts in memory in standard formats, such as BMP, GIF, PNG and JPG. To display the chart on screen, one only needs to use the standard methods of the GUI framework for displaying standard images. The followings are some examples.

On Windows, a DIB (device independent bitmap, which is the data part of BMP) can be blitted to a device context directly using StretchDIBits. This can be used to display a chart, like:

// Output the chart as BMP MemBlock bmp = c->makeChart(Chart::BMP); // The BITMAPINFOHEADER is 14 bytes offset from the beginning LPBITMAPINFO header = (LPBITMAPINFO)(bmp.data + 14); // The bitmap data LPBYTE bitData = (LPBYTE)(bmp.data) + ((LPBITMAPFILEHEADER)(bmp.data))->bfOffBits; // Output to screen device context StretchDIBits(myDeviceContext, 0, 0, header->bmiHeader.biWidth, header->bmiHeader.biHeight, 0, 0, header->bmiHeader.biWidth, header->bmiHeader.biHeight, bitData, header, DIB_RGB_COLORS, SRCCOPY);

On Windows, in many cases, HBITMAP is used instead of DIB. The Win32 API to convert DIB to HBITMAP is CreateDIBitmap. An example conversion function is:

HBITMAP makeChartAsHBITMAP(HDC hdc, BaseChart *c) { // Output the chart as BMP MemBlock bmp = c->makeChart(Chart::BMP); // The BITMAPINFOHEADER is 14 bytes offset from the beginning LPBITMAPINFO header = (LPBITMAPINFO)(bmp.data + 14); // The bitmap data LPBYTE bitData = (LPBYTE)(bmp.data) + ((LPBITMAPFILEHEADER)(bmp.data))->bfOffBits; // Convert the DIB to HBITMAP return CreateDIBitmap(hdc, &(header->bmiHeader), CBM_INIT, bitData, header, DIB_RGB_COLORS); }

In MFC, a CStatic control can be used to display HBITMAP. The code to display a chart is like:

// Get the device context CDC *cdc = GetDC(); //output the chart as HBITMAP HBITMAP hBMP = makeChartAsHBITMAP(myDeviceContext, chart); // Put the chart in the picture control (m_Picture). Also delete any old // HBITMAP in the picture control if (0 != (hBMP = m_Picture->SetBitmap(hBMP))) DeleteObject(hBMP); // Release the CDC ReleaseDC(cdc);

In Qt, many widgets can display QPixmap, which can be created with BMP data. This can be used to display a chart, like:

// Output chart as BMP MemBlock m = c->makeChart(Chart::BMP); // Create a QPixmap with the BMP QPixmap image; image.loadFromData((uchar *)m.data, (uint)m.len); // Display the QPixmap using a QLabel widget myQLabel.setFixedSize(c->getWidth(), c->getHeight()); myQLabel.setPixmap(image);

Handling Hot Spot Mouse Interactions

Hot spots are special regions in on the chart usually used to represent objects inside the chart, such as data representation objects (sectors for pie chart, bars for bar charts, etc). One can display tool tips when the mouse is over the hot spots, and/or to make the hot spots clickable with mouse cursor feedback.

ChartDirector for C++ includes an ImageMapHandler class that determine if a given point is on a hot spot, and to retrieve the various parameters associated with the hot spot. ImageMapHandler accepts standard HTML image maps for defining the hot spots. The BaseChart.getHTMLImageMap method can be used to generate image maps automatically for a chart.

In a typical GUI framework, the ImageMapHandler can be used in the "mouse move" event handler to determine if the mouse cursor is over a hot spot. If the mouse cursor is over a hot spot, the tooltip features of the GUI framework can be used to display tooltips.

For example, in MFC, the code for showing tool tips is like:

void MyControl::OnMouseMove(UINT nFlags, CPoint point) { // m_hotSpotTester = ChartDirector ImageMapHandler handler object previously // created with the image map of the chart if (0 != m_hotSpotTester) { // Retrieve the hot spot under the mouse cursor m_hotSpotTester->getHotSpot(point.x, point.y); // Get the tool tip on the hot spot (returns NULL if not on any hot spot) const char *tooltip = m_hotSpotTester->getValue("title"); // Show the tool tip. We assume there is an MFC CToolTipCtrl control // (m_ToolTip) to show tool tips. As ChartDirector uses UTF8 strings, while // MFC uses TCHAR for strings, we need to use UTF8toTCHAR for conversion. m_ToolTip.UpdateTipText(UTF8toTCHAR(tooltip), this); } }

For Qt, it is like:

void MyControl::mouseMoveEvent(QMouseEvent *event) { // m_hotSpotTester = ChartDirector ImageMapHandler handler object previously // created with the image map of the chart if (0 != m_hotSpotTester) { // Retrieve the hot spot under the mouse cursor m_hotSpotTester->getHotSpot(point.x, point.y); // Get the tool tip on the hot spot (returns NULL if not on any hot spot) const char *tooltip = m_hotSpotTester->getValue("title"); // Show the tool tip using QToolTip QToolTip::showText(event->globalPos(), QString::fromUtf8(m_hotSpotTester->getValue("title"))); } }

Similar code structure can be used to handle other mouse interactions (such as mouse clicks), and to provide mouse cursor feedback.

Adding Track Cursor to the Chart

In ChartDirector, track cursors are created by drawing them on a "dynamic layer" when the mouse moves on the chart. For example, drawing a horizontal line and a vertical line will create a crosshair cursor that tracks the mouse. Other things, such as legend entries, data labels and axis labels, can also be drawn, allowing them to update as the mouse moves over the chart.

The drawing of the track cursor only requires the ChartDirector API and is GUI framework independent. For example, the track drawing code in the MFC and Qt sample programs are identical and does not use any MFC or Qt functions. The same code can be used in other GUI frameworks.

The only support required from the GUI framework is the mouse move event to run the track cursor drawing code. In some track cursor styles, the track cursor may need to be hidden when the mouse leaves the chart. In this case, the mouse leave event may also be useful.

Handling View Port Interactions

A view port can be imagined as a rectangular window of an underlying rectangular surface. For example, a chart that has 10 years of data can be imagined as a very long chart. If one only displays one of the year, we can say the view port covers only 10% of the underlying chart.

With the view port concept, scrolling can be handled as moving the view port, while zooming in and out can be handled as changing the view port size.

ChartDirector for C++ includes a ViewPortManager class for managing the view port. To illustrate how it can be used, we will describe the general steps for implementing the "drag to select" style of zooming in a typical GUI framework:

Similarly, for zoom out, the followings steps may be used:

Printing Charts On Paper

ChartDirector charts can be created as standard BMP, GIF, PNG and JPG images. These images should be printable with standard printing features of typical GUI frameworks. Example printing code for MFC and Qt can be found in Using ChartDirector with MFC and Using ChartDirector with Qt Widget.