Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Selección de una parte de un Chart (https://www.clubdelphi.com/foros/showthread.php?t=72412)

McK 17-02-2011 13:16:47

Selección de una parte de un Chart
 
Hola delphimaniacos,

Pues hoy vengo con un tema que podría resolverme un buen dilema.
A ver tengo una gráfica, y de la misma tengo que coger solo una parte para grabar esos puntos.

Por poner un ejemplo sencillo. Imaginad que tengo en un ListBox 10 items y necesito grabar (coger para los españoles) solo 5 que se encuentran en medio de la lista. Esto se resolvería con un simple ListBox.Multiselect:= TRUE y listo.

Pues algo así necesito hacer con una gráfica que sale de un archivo de puntos. No controlo mucho de gráficas, lo mismo hay un componente mejor que un TChart....

Si alguien me puede ayudar se lo agradezco desde ya.

Salu2!

rounin 17-02-2011 17:11:42

Hola,

Necesitas seleccionar el diapason de X y despues calcular los
puntos seleccionados?
O seleccionar los puntos en Chart y marcarlos?

McK 17-02-2011 19:40:59

Cita:

Empezado por rounin (Mensaje 391232)
Hola,

Necesitas seleccionar el diapason de X y despues calcular los
puntos seleccionados?
O seleccionar los puntos en Chart y marcarlos?

Gracias por la contestación rounin.

Lo suyo sería lo segundo ya que necesito guardar X e Y y se vería más clarito.

rounin 18-02-2011 09:44:39

Puedes guardar X y Y en ambos casos.
La differencia es que en segundo caso es posible seleccionar 5, 7, 9
y en primero solo 5, 6, 7, 8, 9.

Segundo caso, ejemplo muy simple:

Código Delphi [-]
 
 
procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  for i := 0 to 30 do
    Series1.AddXY(i, Random(i));
 
  Chart1.AllowPanning := pmNone;
  Chart1.AllowZoom := False;
  Chart1.OnAfterDraw := Chart1AfterDraw;
  Chart1.OnMouseDown := Chart1MouseDown;
  Chart1.OnMouseMove := Chart1MouseMove;
  Chart1.OnMouseUp   := Chart1MouseUp;

  FSelection := TSelection.CreateEx(Self, Chart1, Series1);
end;
procedure TForm1.Chart1AfterDraw(Sender: TObject);
begin
  FSelection.Draw(Chart1);
end;
procedure TForm1.Chart1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  FSelection.HandleMouse(X, Y, evMouseDown, Shift);
end;
procedure TForm1.Chart1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  FSelection.HandleMouse(X, Y, evMouseMove, Shift);
end;
procedure TForm1.Chart1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  FSelection.HandleMouse(X, Y, evMouseUp, Shift);
end;
procedure TForm1.BGetSelectionClick(Sender: TObject);
var i, idx: Integer;
begin
  ListBox1.Items.Clear;
  for i := 0 to FSelection.Count-1 do
  begin
    idx := FSelection.Indexes[i];
    ListBox1.Items.Add(
      Format('%f  %f', [FSelection.Series.XValue[idx], FSelection.Series.YValue[idx]])
    );
  end;
end;
 
{-------------------------------------------------------------------}
unit XYSel;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, TeEngine, Series, ExtCtrls, TeeProcs, Chart;            // RTypes RCore RDiapason
type
  TEventID = (evNone, evDraw, evMouseDown, evMouseMove, evMouseUp, evKeyDown, evKeyUp);
  TSelection = class(TComponent)
  private
    FSeries: TChartSeries;
    FChart: TChart;
    FIndexes: TList;
    FSelectionInProgress: Boolean;
    FDownPt: TPoint;
    FPrevPt: TPoint;
    function GetCount: Integer;
    function GetIndexes(I: Integer): Integer;
  public
    property Series: TChartSeries read FSeries;
    property Chart: TChart read FChart;
    property Count: Integer read GetCount;
    property Indexes[I: Integer]: Integer read GetIndexes;
    constructor Create(AOwner: TComponent); override;
    constructor CreateEx(AOwner: TComponent; AChart: TChart; ASeries: TChartSeries);
    destructor Destroy; override;
    procedure Clear;
    procedure Draw(Chart: TChart);
    procedure HandleMouse(X, Y: Integer; Event: TEventID; Shift: TShiftState);
  end;
implementation
{ TSelection }
constructor TSelection.Create(AOwner: TComponent);
begin
  inherited;
  FIndexes := TList.Create;
  FSeries := nil;
end;
constructor TSelection.CreateEx(AOwner: TComponent; AChart: TChart; ASeries: TChartSeries);
begin
  Create(AOwner);
  FSeries := ASeries;
  FChart := AChart; 
end;
destructor TSelection.Destroy;
begin
  FIndexes.Free;
  inherited;
end;
procedure TSelection.Clear;
begin
  FIndexes.Clear;
end;
function TSelection.GetCount: Integer;
begin
  Result := FIndexes.Count;
end;
function TSelection.GetIndexes(I: Integer): Integer;
begin
  Result := Integer( FIndexes[i] );
end;
procedure TSelection.Draw(Chart: TChart);
var i: Integer;
    procedure DrawSelectedMarker(Idx: Integer);
    var xx, yy, hh, ww: Integer;
    begin
      if Idx >= Series.Count then Exit;
      xx := Chart.BottomAxis.CalcPosValue(Series.XValues[Idx]);
      yy := Chart.LeftAxis.CalcPosValue  (Series.YValues[Idx]);
      hh := 7;
      ww := 7;
      if Series is TCustomSeries then
      begin
        hh := (Series as TCustomSeries).Pointer.VertSize + 2;
        ww := (Series as TCustomSeries).Pointer.HorizSize + 2;
      end;
      Chart.Canvas.Pen.Style := psSolid;
      Chart.Canvas.Pen.Mode := pmCopy;
      Chart.Canvas.Pen.Color := clBlack;
      Chart.Canvas.Brush.Style := bsClear;
      Chart.Canvas.Rectangle(xx-ww, yy-hh, xx+ww+1, yy+hh+1);
      Chart.Canvas.Rectangle(xx-ww-1, yy-hh-1, xx+ww+2, yy+hh+2);
    end;
begin
  if not Assigned(FSeries) then Exit;
  for i := 0 to FIndexes.Count-1 do
  begin
    DrawSelectedMarker( Integer(FIndexes[i]) );
  end;
end;
procedure OrientRect(var Rect: TRect);
    procedure Swap(var A, B: Integer);
    var tmp: Integer;
    begin
      tmp := A; A := B; B := tmp;
    end;
begin
  if Rect.Left > Rect.Right then Swap(Rect.Left, Rect.Right);
  if Rect.Top > Rect.Bottom then Swap(Rect.Top, Rect.Bottom);
end;
type
  TAddMode = (amPlus, amXor, amMinus);
procedure TSelection.HandleMouse(X, Y: Integer; Event: TEventID; Shift: TShiftState);
var
  selRect: TRect;
  i, xx, yy: Integer;
   procedure AddToSelection(Idx: Integer; Mode: TAddMode);
   begin
     if FIndexes.IndexOf(Pointer(Idx)) > -1 then
     begin
       if Mode in [amMinus, amXor] then FIndexes.Remove(Pointer(Idx))
     end
     else
     begin
       if Mode in [amPlus, amXor] then FIndexes.Add(Pointer(Idx));
     end;
   end;
begin
  if not Assigned(FSeries) then Exit;
  if (Event = evMouseDown)and(ssLeft in Shift) then {--------------------------}
  begin
    FSelectionInProgress := True;
    FDownPt := Point(X, Y);
    FPrevPt := Point(X, Y);
    if not (ssShift in Shift) then FIndexes.Clear;
    Chart.Invalidate;
  end
  else
  if (Event = evMouseMove)and(FSelectionInProgress) then {---------------------}
  begin
    Chart.Canvas.Pen.Style := psSolid; //psDot;
    Chart.Canvas.Pen.Mode := pmNot;
    Chart.Canvas.Brush.Style := bsClear;
    Chart.Canvas.Rectangle(FDownPt.X, FDownPt.Y, FPrevPt.X, FPrevPt.Y);
    Chart.Canvas.Rectangle(FDownPt.X, FDownPt.Y, X, Y);
    FPrevPt := Point(X, Y);
  end
  else
  if (Event = evMouseUp) then {------------------------------------------------}
  begin
    if FSelectionInProgress then
    begin
      selRect := Rect(FDownPt.X, FDownPt.Y, X, Y);
      OrientRect(selRect);
      for i := 0 to Series.Count-1 do
      begin
        xx := Chart.BottomAxis.CalcPosValue(Series.XValues[i]);
        yy := Chart.LeftAxis.CalcPosValue  (Series.YValues[i]);
        if PtInRect(selRect, Point(xx, yy)) then AddToSelection(i, amXor);
      end;
    end;
    Chart.Invalidate;
    FSelectionInProgress := False;
  end;
end;
end.
 
{-------------------------------------------------------------------}

McK 18-02-2011 12:36:36

Gracias!! Te lo agradezco mucho, ese codigo me va a venir de perlas.

Soy un poco novato con los gráficos... :)

efirvida 08-02-2012 08:42:23

hola estoy tratando de utilizar tu codigo y me da unos cuantos errores el primero es que FSelection no esta definido no se si hice bien, pero lo defini como un TSelection,en las variables glovales, pero lo que no me compila es BGetSelectionClick que tampoco esta declarado, bueno despues de declarar el Fselection y borrar el procedimiento de BGetSelectionClick, me compilo bien solo que no me coje los datos para el listbox.
?que me falta por hacer??

efirvida 08-02-2012 08:59:41

Cita:

Empezado por efirvida (Mensaje 424488)
hola estoy tratando de utilizar tu codigo y me da unos cuantos errores el primero es que FSelection no esta definido no se si hice bien, pero lo defini como un TSelection,en las variables glovales, pero lo que no me compila es BGetSelectionClick que tampoco esta declarado, bueno despues de declarar el Fselection y borrar el procedimiento de BGetSelectionClick, me compilo bien solo que no me coje los datos para el listbox.
?que me falta por hacer??

repondiendome a mi mismo, que bruto soy jejeje, defini BGetSelectionClick y ya lo otro si tuve que hacer un oequeño cambio para que funcionara -->

Código Delphi [-]
procedure TTForm1.Chart1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  FSelection.HandleMouse(X, Y, evMouseUp, Shift);
  BGetSelectionClick(sender);
end;

ahora mi pregunta es la siguiente si en vez de quere capturar lo svalores lo que quiero es hacerle zoom a esa area que es lo que tendria que hacer???

rounin 09-02-2012 11:33:45

Una manera de hacer esto es herramienta "Zoom" y herramienta "Seleccion" y
dos botones (TSpeedButton o TToolButton) por seleccionar las.

Otra manera es hacer Zoom cuando "Ctrl" o "Alt" botones estan presionado.

He hecho la ejemplo de primera manera.

Código Delphi [-]
unit main;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, TeEngine, Series, ExtCtrls, TeeProcs, Chart, StdCtrls,
  XYSel, Buttons;
type
  TForm1 = class(TForm)
    Chart1: TChart;
    Series1: TLineSeries;
    ListBox1: TListBox;
    BGetSelection: TButton;
    BSelectTool: TSpeedButton;
    BZoomTool: TSpeedButton;
    procedure FormCreate(Sender: TObject);
    procedure BGetSelectionClick(Sender: TObject);
    procedure Chart1AfterDraw(Sender: TObject);
    procedure Chart1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure Chart1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure Chart1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure BToolClick(Sender: TObject);
  private
    FSelection: TSelection;
    FMouseHandled: Boolean;
    FZoomMode: Boolean;
  public
    procedure SetZoomMode(ZoomOn: Boolean);
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  BZoomTool.GroupIndex := 1;
  BSelectTool.GroupIndex := 1;
  BSelectTool.AllowAllUp := False;
  BSelectTool.Down := True; 
  BZoomTool.OnClick := BToolClick;
  BSelectTool.OnClick := BToolClick;
  for i := 0 to 30 do
    Series1.AddXY(i, Random(i));
  SetZoomMode(False);
  Chart1.OnAfterDraw := Chart1AfterDraw;
  Chart1.OnMouseDown := Chart1MouseDown;
  Chart1.OnMouseMove := Chart1MouseMove;
  Chart1.OnMouseUp   := Chart1MouseUp;
  BGetSelection.OnClick := BGetSelectionClick;
  FSelection := TSelection.CreateEx(Self, Chart1, Series1);
end;
procedure TForm1.SetZoomMode(ZoomOn: Boolean);
begin
  FZoomMode := ZoomOn;
  if ZoomOn then
  begin
    Chart1.AllowPanning := pmBoth;
    Chart1.AllowZoom := True;
  end
  else
  begin
    Chart1.AllowPanning := pmNone;
    Chart1.AllowZoom := False;
  end;
end;
procedure TForm1.Chart1AfterDraw(Sender: TObject);
begin
  FSelection.Draw(Chart1);
end;
procedure TForm1.Chart1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  FMouseHandled := FZoomMode;
  FSelection.HandleMouse(X, Y, evMouseDown, Shift, FMouseHandled);
end;
procedure TForm1.Chart1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  FMouseHandled := FZoomMode;
  FSelection.HandleMouse(X, Y, evMouseMove, Shift, FMouseHandled);
end;
procedure TForm1.Chart1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  FMouseHandled := FZoomMode;
  FSelection.HandleMouse(X, Y, evMouseUp, Shift, FMouseHandled);
end;
procedure TForm1.BGetSelectionClick(Sender: TObject);
var i, idx: Integer;
begin
  ListBox1.Items.Clear;
  for i := 0 to FSelection.Count-1 do
  begin
    idx := FSelection.Indexes[i];
    ListBox1.Items.Add(
      Format('%f  %f', [FSelection.Series.XValue[idx], FSelection.Series.YValue[idx]])
    );
  end;
end;
procedure TForm1.BToolClick(Sender: TObject);
begin
  SetZoomMode(Sender = BZoomTool);
end;
end.

efirvida 14-03-2012 02:06:21

muchisimas gracias esto me servira de mucho, solo permitame hacerle unas observaciones que me dieron error, cuando se utiliza
Código Delphi [-]
FSelection.HandleMouse(X, Y, evMouseDown, Shift, FMouseHandled);

paraque funcionara tuve que dejarlo como

Código Delphi [-]
FSelection.HandleMouse(X, Y, evMouseDown, Shift);
que es asi como esta declarado en XYSel.pas

solo eso muchisimas gracias por todo nuevamente, y disculpenme por no haber respondido antes.


La franja horaria es GMT +2. Ahora son las 04:15:38.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi