|
Flickering occurs at MFC SDI. |
Posted by CoreTech on Oct-19-2013 04:14 |
|
I made MFC SDI version from your sample code "tracklabel".
Flickering occured but i don't know how to fix it.
Below is CView code.
Could you help me?
===========================================================
#include "stdafx.h"
#include "SDI_WithChartView2.h"
#include "SDI_WithChartView2Doc.h"
#include "SDI_WithChartView2View.h"
#include <sstream>
#include <algorithm>
using namespace std;
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CSDI_WithChartView2View
IMPLEMENT_DYNCREATE(CSDI_WithChartView2View, CView)
BEGIN_MESSAGE_MAP(CSDI_WithChartView2View, CView)
ON_WM_CREATE()
ON_WM_SIZE()
ON_WM_ERASEBKGND()
ON_CONTROL(CVN_MouseMovePlotArea, IDC_ChartViewer, OnMouseMovePlotArea)
END_MESSAGE_MAP()
// CSDI_WithChartView2View construction/destruction
CSDI_WithChartView2View::CSDI_WithChartView2View()
{
// TODO: add construction code here
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
CSDI_WithChartView2View::~CSDI_WithChartView2View()
{
}
BOOL CSDI_WithChartView2View::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CView::PreCreateWindow(cs);
}
// CSDI_WithChartView2View drawing
void CSDI_WithChartView2View::OnDraw(CDC* /*pDC*/)
{
CSDI_WithChartView2Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
drawChart(&m_CChartViewer);
}
void CSDI_WithChartView2View::OnRButtonUp(UINT nFlags, CPoint point)
{
ClientToScreen(&point);
OnContextMenu(this, point);
}
void CSDI_WithChartView2View::OnContextMenu(CWnd* pWnd, CPoint point)
{
theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
}
// CSDI_WithChartView2View diagnostics
#ifdef _DEBUG
void CSDI_WithChartView2View::AssertValid() const
{
CView::AssertValid();
}
void CSDI_WithChartView2View::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CSDI_WithChartView2Doc* CSDI_WithChartView2View::GetDocument() const // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSDI_WithChartView2Doc)));
return (CSDI_WithChartView2Doc*)m_pDocument;
}
#endif //_DEBUG
// CSDI_WithChartView2View message handlers
int CSDI_WithChartView2View::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
//1.
CRect rectDummy;
rectDummy.SetRectEmpty();
const DWORD dwStyle = WS_CHILD | WS_VISIBLE | SS_BITMAP | SS_NOTIFY;
if (!m_CChartViewer.Create(NULL, dwStyle, rectDummy, this, IDC_ChartViewer))
{
TRACE0("Failed to create CChartView\\n");
return -1; // fail to create
}
//2.
AdjustLayout();
//last.
return 0;
}
void CSDI_WithChartView2View::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
AdjustLayout();
}
void CSDI_WithChartView2View::AdjustLayout()
{
//0.
CRect rectClient;
GetClientRect(rectClient);
UINT nFlags = SWP_NOACTIVATE | SWP_NOZORDER;
//1.
m_CChartViewer.SetWindowPos(NULL, rectClient.left, rectClient.top, rectClient.Width(), rectClient.Height(), nFlags);
}
void CSDI_WithChartView2View::drawChart( CChartViewer *p_pCChartViewer )
{
//1. Data for the chart as 3 random data series
RanSeries r(127);
DoubleArray data0 = r.getSeries(100, 100, -15, 15);
DoubleArray data1 = r.getSeries(100, 150, -15, 15);
DoubleArray data2 = r.getSeries(100, 200, -15, 15);
DoubleArray timeStamps = r.getDateSeries(100, Chart::chartTime(2011, 1, 1), 86400);
//2. Create a XYChart object of size 640 x 400 pixels
CRect oCRect;
GetClientRect(oCRect);
XYChart *pXYChart = new XYChart(oCRect.Width(), oCRect.Height());
//3. Add a title to the chart using 18 pts Times New Roman Bold Italic font
pXYChart->addTitle(" Product Line Global Revenue", "timesbi.ttf", 18);
//4. Set the plotarea at (50, 55) with width 70 pixels less than chart width, and height 90 pixels
// less than chart height. Use a vertical gradient from light blue (f0f6ff) to sky blue (a0c0ff)
// as background. Set border to transparent and grid lines to white (ffffff).
pXYChart->setPlotArea(50, 55, pXYChart->getWidth() - 70, pXYChart->getHeight() - 90, pXYChart->linearGradientColor(0, 55, 0, pXYChart->getHeight() - 35, 0xf0f6ff, 0xa0c0ff), -1, Chart::Transparent, 0xffffff, 0xffffff);
//5. Add a legend box at (50, 25) using horizontal layout. Use 10pts Arial Bold as font. Set the
// background and border color to Transparent.
pXYChart->addLegend(50, 25, false, "arialbd.ttf", 10)->setBackground(Chart::Transparent);
//6. Set axis label style to 8pts Arial Bold
pXYChart->xAxis()->setLabelStyle("arialbd.ttf", 8);
pXYChart->yAxis()->setLabelStyle("arialbd.ttf", 8);
//7. Set the axis stem to transparent
pXYChart->xAxis()->setColors(Chart::Transparent);
pXYChart->yAxis()->setColors(Chart::Transparent);
//8. Configure x-axis label format
pXYChart->xAxis()->setMultiFormat(Chart::StartOfYearFilter(), "{value|mm/yyyy} ",
Chart::StartOfMonthFilter(), "{value|mm}");
//9. Add axis title using 10pts Arial Bold Italic font
pXYChart->yAxis()->setTitle("USD millions", "arialbi.ttf", 10);
//10. Add a line layer to the chart using a line width of 2 pixels.
LineLayer *pLineLayer = pXYChart->addLineLayer();
pLineLayer->setLineWidth(2);
//11. Add 3 data series to the line layer
pLineLayer->setXData(timeStamps);
pLineLayer->addDataSet(data0, 0xff3333, "Alpha");
pLineLayer->addDataSet(data1, 0x008800, "Beta");
pLineLayer->addDataSet(data2, 0x3333cc, "Gamma");
//12. Assign the chart to the WinChartViewer
p_pCChartViewer->setChart(pXYChart);
}
void CSDI_WithChartView2View::OnMouseMovePlotArea()
{
trackLineLabel((XYChart *)m_CChartViewer.getChart(), m_CChartViewer.getPlotAreaMouseX());
m_CChartViewer.updateDisplay();
// Hide the track cursor when the mouse leaves the plot area
m_CChartViewer.removeDynamicLayer(CVN_MouseLeavePlotArea);
}
void CSDI_WithChartView2View::trackLineLabel( XYChart *p_pXYChart, int p_nMouseX )
{
//1. Clear the current dynamic layer and get the DrawArea object to draw on it.
DrawArea *pDrawArea = p_pXYChart->initDynamicLayer();
//2. The plot area object
PlotArea *pPlotArea = p_pXYChart->getPlotArea();
//3. Get the data x-value that is nearest to the mouse, and find its pixel coordinate.
double xValue = p_pXYChart->getNearestXValue(p_nMouseX);
int xCoor = p_pXYChart->getXCoor(xValue);
//4. Draw a vertical track line at the x-position
pDrawArea->vline(pPlotArea->getTopY(), pPlotArea->getBottomY(), xCoor,
pDrawArea->dashLineColor(0x000000, 0x0101));
//5. Draw a label on the x-axis to show the track line position.
ostringstream xlabel;
xlabel << "<*font,bgColor=000000*> " << p_pXYChart->xAxis()->getFormattedLabel(xValue, "mmm dd, yyyy")
<< " <*/font*>";
TTFText *pTTFText = pDrawArea->text(xlabel.str().c_str(), "arialbd.ttf", 8);
//6. Restrict the x-pixel position of the label to make sure it stays inside the chart image.
int xLabelPos = max(0, min(xCoor - pTTFText->getWidth() / 2, p_pXYChart->getWidth() - pTTFText->getWidth()));
pTTFText->draw(xLabelPos, pPlotArea->getBottomY() + 6, 0xffffff);
pTTFText->destroy();
//7. Iterate through all layers to draw the data labels
for (int i = 0; i < p_pXYChart->getLayerCount(); ++i) {
Layer *pLayer = p_pXYChart->getLayerByZ(i);
//8. The data array index of the x-value
int xIndex = pLayer->getXIndexOf(xValue);
//9. Iterate through all the data sets in the layer
for (int j = 0; j < pLayer->getDataSetCount(); ++j)
{
DataSet *pDataSet = pLayer->getDataSetByZ(j);
const char *dataSetName = pDataSet->getDataName();
//10. Get the color, name and position of the data label
int color = pDataSet->getDataColor();
int yCoor = p_pXYChart->getYCoor(pDataSet->getPosition(xIndex), pDataSet->getUseYAxis());
//11. Draw a track dot with a label next to it for visible data points in the plot area
if ((yCoor >= pPlotArea->getTopY()) && (yCoor <= pPlotArea->getBottomY()) && (color !=
Chart::Transparent) && dataSetName && *dataSetName)
{
pDrawArea->circle(xCoor, yCoor, 4, 4, color, color);
ostringstream label;
label << "<*font,bgColor=" << hex << color << "*> "
<< p_pXYChart->formatValue(pDataSet->getValue(xIndex), "{value|P4}") << " <*font*>";
pTTFText = pDrawArea->text(label.str().c_str(), "arialbd.ttf", 8);
//12. Draw the label on the right side of the dot if the mouse is on the left side the
// chart, and vice versa. This ensures the label will not go outside the chart image.
if (xCoor <= (pPlotArea->getLeftX() + pPlotArea->getRightX()) / 2)
pTTFText->draw(xCoor + 5, yCoor, 0xffffff, Chart::Left);
else
pTTFText->draw(xCoor - 5, yCoor, 0xffffff, Chart::Right);
pTTFText->destroy();
}//end of if
}//end of for
}//end of for
}
//
// Handle the ON_WM_ERASEBKGND message to set background color
//
BOOL CSDI_WithChartView2View::OnEraseBkgnd(CDC* pDC)
{
// Set brush to desired background color
CBrush backBrush(RGB(255, 255, 255));
// Save old brush
CBrush* pOldBrush = pDC->SelectObject(&backBrush);
// Erase the area needed with the given background color
CRect rect;
pDC->GetClipBox(&rect);
pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
// Restore old brush and exit
pDC->SelectObject(pOldBrush);
return TRUE;
}
|
Re: Flickering occurs at MFC SDI. |
Posted by Peter Kwan on Oct-22-2013 04:01 |
|
Hi CoreTech,
The cause of this issue is because of the project using Windows Common Controls 6.0 with manifest for XP style support. It is the same problem in the thread below:
http://www.chartdir.com/forum/download_thread.php?bn=chartdir_support&pattern=flickering&thread=1137671302#N1376375622
As mentioned in the above thread, even Microsoft's own controls can flicker, although the flickering can be less noticible because of their small size (and hence faster repaint). I suspect the issue is that when there is Windows Common Control 6.0 with XP style support, the OS some how cause the entire window to be repainted, resulting in flickering.
There are two methods:
(a) Disable the mainfest - just common out the manifest code as mention in the thread above, and delete the manifest files already generated (in the Debug directory).
or
(b) Add the following line in PreCreateWindow, which cause double buffering at the Window level. (It seems double buffering in the control itself does not help, as the flickering is at the Window level.)
cs.dwExStyle |= WS_EX_COMPOSITED;
Hope this can help.
Regards
Peter Kwan |
Re: Flickering occurs at MFC SDI. |
Posted by CoreTech on Oct-23-2013 15:16 |
|
Thank you for your help But i cannot solve my problem.
For (a), I cannot use this method to my MDI application because unwanted side-effect occurs.
For (b), I tested that method but another problems occurred as side-effect.
( First problem is that trace is not smooth like before.
Second problem is that that make application to be unstable very much.
If you make sample SDI application with my uploaded code - That is just modified from your Dialog based sample code to SDI code -, you can see that easily. )
So i should dig this problem deeply by myself.
Thank you anyway.
Peter Kwan wrote:
Hi CoreTech,
The cause of this issue is because of the project using Windows Common Controls 6.0 with manifest for XP style support. It is the same problem in the thread below:
http://www.chartdir.com/forum/download_thread.php?bn=chartdir_support&pattern=flickering&thread=1137671302#N1376375622
As mentioned in the above thread, even Microsoft's own controls can flicker, although the flickering can be less noticible because of their small size (and hence faster repaint). I suspect the issue is that when there is Windows Common Control 6.0 with XP style support, the OS some how cause the entire window to be repainted, resulting in flickering.
There are two methods:
(a) Disable the mainfest - just common out the manifest code as mention in the thread above, and delete the manifest files already generated (in the Debug directory).
or
(b) Add the following line in PreCreateWindow, which cause double buffering at the Window level. (It seems double buffering in the control itself does not help, as the flickering is at the Window level.)
cs.dwExStyle |= WS_EX_COMPOSITED;
Hope this can help.
Regards
Peter Kwan
|
|