Teechart, автоматический пересчет пользовательской области меток из-за смены названия - PullRequest
0 голосов
/ 14 октября 2018

Delphi 10.1, VCL, со встроенным Teechart.

У меня есть серия областей с меткой, перемещенной кодом в пользовательскую позицию.При изменении содержимого заголовка Mark желтый фон не настраивается (автоматически изменяемый размер) в соответствии с новым содержимым Mark.У меня есть обходной путь для этого, но у него есть мерцания, и это не элегантно. Я ищу идею, как сделать это лучше.

Подробно : я положил на график три кнопки, одну для перемещения положения метки,2-ая ​​кнопка, чтобы добавить вторую строку содержимого в заголовок пометки.Третья кнопка - моя работа, чтобы получить правильный размер.Создание серии:

procedure TForm2.FormCreate(Sender: TObject);
begin
  Chart1.View3D := false;
  Chart1.Axes.Bottom.SetMinMax(0,5);

  with Chart1.AddSeries(tAreaSeries) as tAreaSeries do
    begin
      AddXY(1, 10);                  // Two points AreaSeries
      AddXY(4, 10);
      Marks[1].Visible     := false; // Hide the other Mark, the default is true
      Marks.Visible        := true;  // Global Visibility for all Markers
      Chart1[0].Marks[0].Text.Text := 'First-line';
    end;
end;

Нажатие кода кнопки Move Mark:

procedure TForm2.btnMoveMarkClick(Sender: TObject);
begin
  Chart1[0].Marks.Positions[0].Custom := true;
  Chart1[0].Marks.Positions[0].Offset(point(50,70));
//  Chart1[0].Marks.Positions[0].LeftTop := point(150,200);  // It is moving the Mark but not drawing the line to Series point
  Chart1.Repaint; // It doesn't work without this Repaint
end;

Будет создан следующий экран: enter image description here Теперь, нажав 2-ю кнопку, чтобыизмените Пометить заголовок следующим образом:

procedure TForm2.btnChangeMarkContentClick(Sender: TObject);
begin
  Chart1[0].Marks[0].Text.Text := 'First-line'+#13+'Second-line';
end;

Как видите, размер желтого фона не изменился: enter image description here

Мой обходной путь брут-форсадля удаления пользовательской позиции, это изменит размер Марки, затем снова переместит Марку следующим образом:

procedure TForm2.btnResizeMarkClick(Sender: TObject);
var
  LastPoint: tpoint;
begin
  LastPoint := Chart1[0].Marks.Positions[0].LeftTop;
  Chart1[0].Marks.Positions.Automatic(0);
  Chart1.Repaint;

  Chart1[0].Marks.Positions[0].Custom := true;
  Chart1.Repaint;
//  Chart1[0].Marks[0].MoveTo(LastPoint); // It doesn't work - Why?
  Chart1[0].Marks.Positions[0].LeftTop := LastPoint; // Better to use Offset
  Chart1.Repaint;
end;

Это делает работу, но с мерцанием из-за движения Марка, как показано ниже: enter image description here

Спасибо за любую подсказку, как изменить размер метки, не удаляя ее пользовательское положение, которое вызывает мерцание.Reron

Ответы [ 2 ]

0 голосов
/ 18 октября 2018

Yeray решил основную проблему.Кроме того, стрелки должны быть скорректированы следующим образом:

type
  tCustomTextShapeAccess = class(tCustomTextShape); // Yeray: tCustomTextShapeAccess class to get access to the protected CalcBounds method

const
  tcaTopLeft = 0;
  tcaArrowTo = 1;

procedure TeeChart_ResizeCustomMark(aChart: tChart; aSeriesInx, aMarkInx, aAnchor: integer);
// Resize Custom Mark area shape. It is required after Title text modification
// aAnchor: tcaTopLeft(0), tcaArrowTo(1); Choose which point to keep
var
  aSeries: tChartSeries;
  aMark  : tMarksItem;
  aMarkPosision: tSeriesMarkPosition;
begin
  // Assignments for more readable code
  aSeries       := aChart[aSeriesInx];
  aMark         := aChart[aSeriesInx].Marks[aMarkInx];
  aMarkPosision := aSeries.Marks.Positions[aMarkInx];

  // Bounds Calculation of the new Mark. Yeray solution.
  tCustomTextShapeAccess(aMark).CalcBounds(aChart); // Yeray: tCustomTextShapeAccess class to get access to the protected CalcBounds method
  aMarkPosision.Height := aMark.Height;
  aMarkPosision.Width  := aMark.Width;

  // Set Mark position based on aAnchor
  case aAnchor of
    tcaTopLeft: // Keep LeftTop point. Set new ArrowTo point.
      begin
        aMarkPosision.ArrowTo.X := aMarkPosision.LeftTop.X + (aMarkPosision.Width div 2);
        if aSeries.CalcYPos(aMarkInx) > aMarkPosision.ArrowTo.Y then // Mark above Series point
          aMarkPosision.ArrowTo.Y := aMarkPosision.LeftTop.Y + aMarkPosision.Height
        else
          aMarkPosision.ArrowTo.Y := aMarkPosision.LeftTop.Y;
      end;
    else        // Set ArrowTo point. Set a New LeftTop point.
      begin
        aMarkPosision.LeftTop.X := aMarkPosision.ArrowTo.X - (aMarkPosision.Width div 2);
        if aSeries.CalcYPos(aMarkInx) > aMarkPosision.ArrowTo.Y then // Mark above Series point
          aMarkPosision.LeftTop.Y := aMarkPosision.ArrowTo.Y - (aMarkPosision.Height -1)
        else                                                         // Mark below Series point
          aMarkPosision.ArrowTo.Y := aMarkPosision.LeftTop.Y;
      end;
  end; // case

  aChart.Repaint;
end;
0 голосов
/ 18 октября 2018

Вы можете пересчитать границы Mark и присвоить Width и Height соответствующей позиции:

  TCustomTextShapeAccess(Chart1[0].Marks[0]).CalcBounds(Chart1);
  Chart1[0].Marks.Positions[0].Height:=Chart1[0].Marks[0].Height;
  Chart1[0].Marks.Positions[0].Width:=Chart1[0].Marks[0].Width;
  Chart1.Repaint;

Обратите внимание, что вы должны объявить класс TCustomTextShapeAccess, чтобы получить доступ к защищенным CalcBounds метод:

type TCustomTextShapeAccess=class(TCustomTextShape);
...