Custom Legend Position Issues

TeeChart for ActiveX, COM and ASP
Post Reply
BARMatt
Newbie
Newbie
Posts: 5
Joined: Wed Jan 12, 2011 12:00 am

Custom Legend Position Issues

Post by BARMatt » Tue Mar 08, 2011 6:15 pm

Hi,

I'm capturing the OnGetLegendRect event so as to position it according to my users' GUI-dictated whims. It mostly seems to work but I'm seeing some graphical issues that I suspect are caused by my not refreshing correctly or something similar. The user defines the desired location by specifying a base position (Top or bottom and left or right) and then an offset from that position. This position can either be relative to the plot boundary or the entire window.

First, if I switch the legend position from left to right (or vice-versa) the *rectangle* changes position but the text and legend symbols do not. See figure A. The legend appears correctly the next time the plot is repainted.

Secondly, if the user chooses to place the legend outside of the plot boundary then only the portion of the legend still drawn *inside* of it is displayed. The rest appears as a black rectangle. See figure B.

Finally, it's possible to break the legend completely but I don't know how it's happening. It usually occurs when I switch from inside the plot boundary to outside then back again. The legend disappears and cannot be recovered because the OnGetLegendRect event is no longer received. I've TRACEd the rectangle returned for the legend position and it always makes sense; i.e. Top < Bottom, Left < Right, Top >= 0, Left >= 0, and neither Bottom nor Right exceed the window boundary. No exceptions seems to be thrown either.

Whenever the legend settings are changed, I call Repaint on the parent plot to get it to fire the event. I've tried GetEnvironment().InternalRepaint() but it doesn't always work. In fact, it usually doesn't. Sometimes the window paints and sometimes it doesn't.

Unfortunately, I can't easily provide any compilable sample code because our plots are built as a DLL module loaded by another program and I can't give you anything from the parent. If it would help, I could to try to put together a small test program out of the relevant sections. For now, here's the function called by the OnGetLegendRect handler. Our windows contain multiple plots so the event is actually received by the parent and sent down to the proper individual plot.

Code: Select all

void CTChartEx::GetLegendRect(CRect &legRect)
{
    CRect baseRect;
    COleControlSite *kludge;
    long height = legRect.Height(), width = legRect.Width();

    m_Settings.LegendOffsetX = __max(0, m_Settings.LegendOffsetX);
    m_Settings.LegendOffsetY = __max(0, m_Settings.LegendOffsetY);

	if(m_Settings.bExternal)
	{
        /* Okay, let me explain this crap.  ScreenToClient calls GetExStyle().  *
         * If m_pCtrlSite is not NULL then the COleControlSite version of that  *
         * function asks the control for its DISPID_APPEARANCE property.  This  *
         * causes a DISP_E_MEMBERNOTFOUND exception to be thrown by TeeChart.   *
         * So I trick Windows into calling the regular version which avoids the *
         * exception and still gets me the correct rectangle.   -MST, 04Mar2011 */

	    kludge = m_pCtrlSite;
	    m_pCtrlSite = NULL;
	    GetWindowRect(baseRect);
	    ScreenToClient(baseRect);
	    m_pCtrlSite = kludge;
	}
	else
	{
	    TeeRectToCRect(GetGetChartRect(), baseRect);
	}

    if(m_Settings.bBottom)
    {
        if(m_Settings.bLeft)
        {
            // Bottom-Left
            legRect.top = baseRect.bottom - height - m_Settings.LegendOffsetY;
            legRect.left = baseRect.left + m_Settings.LegendOffsetX;
            legRect.bottom = legRect.top + height;
            legRect.right = legRect.left + width;
        }
        else
        {
            // Bottom-Right
            legRect.top = baseRect.bottom - height - m_Settings.LegendOffsetY;
            legRect.left = baseRect.right - width - m_Settings.LegendOffsetX;
            legRect.bottom = legRect.top + height;
            legRect.right = legRect.left + width;
        }
    }
    else
    {
        if(m_Settings.bLeft)
        {
            // Top-Left
            legRect.top = baseRect.top + m_Settings.LegendOffsetY;
            legRect.left = baseRect.left + m_Settings.LegendOffsetX;
            legRect.bottom = legRect.top + height;
            legRect.right = legRect.left + width;
        }
        else
        {
            // Top-Right
            legRect.top = baseRect.top + m_Settings.LegendOffsetY;
            legRect.left = baseRect.right - width - m_Settings.LegendOffsetX;
            legRect.bottom = legRect.top + height;
            legRect.right = legRect.left + width;
        }
    }
}
Attachments
B.jpg
B.jpg (60.29 KiB) Viewed 6615 times
A.jpg
A.jpg (58.68 KiB) Viewed 6590 times

Yeray
Site Admin
Site Admin
Posts: 9613
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: Custom Legend Position Issues

Post by Yeray » Wed Mar 09, 2011 4:46 pm

Hi BARMatt,

I've checked it with the following code in VB6:

Code: Select all

Private Sub Form_Load()  
  TChart1.Aspect.View3D = False
  TChart1.Legend.LegendStyle = lsSeries

  TChart1.AddSeries scLine
  With TChart1.Series(0)
    .Title = "My series"
    .Color = RGB(150, 0, 0)
    .FillSampleValues
  End With
  With TChart1.Series(0).asLine.Pointer
    .Visible = True
    .Style = psCircle
    .Brush.Style = bsClear
    .Pen.Color = TChart1.Series(0).Color
    .HorizontalSize = 5
    .VerticalSize = 5
  End With
  
  TChart1.Environment.InternalRepaint
  TChart1.Legend.CustomPosition = True
End Sub

Private Sub TChart1_OnGetLegendRect(Left As Long, Top As Long, Right As Long, Bottom As Long)
  Dim tmpwidth, tmpheight As Integer
  tmpwidth = Right - Left
  tmpheight = Bottom - Top
  
  Left = 600
  Top = 30
  
  Right = Left + tmpwidth
  Bottom = Top + tmpheight
End Sub

Private Sub TChart1_OnGetSeriesPointerStyle(ByVal SeriesIndex As Long, ByVal ValueIndex As Long, AStyle As TeeChart.EPointerStyle)
  If ValueIndex Mod 4 = 0 Then
    AStyle = TChart1.Series(SeriesIndex).asLine.Pointer.Style
  Else
    AStyle = psNothing
  End If
End Sub
And here it is the chart I'm getting:
Chart.png
Chart.png (12.68 KiB) Viewed 6586 times
Note that in the event I'm taking and using the values given as parameters in the same (to calculate the width and height). But the event will only give the "correct" values once the chart has been drawn at least once. That's why I'm forcing a redraw (TChart1.Environment.InternalRepaint) before setting TChart1.Legend.CustomPosition = True.

So the code above doesn't seem to reproduce the problem for me here. Could you please try to modify the code above so we can reproduce the problem here?
Could you also check if you are using the latest version available in the download area?
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

Post Reply