Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Lazarus, FreePascal, Kylix, etc. (https://www.clubdelphi.com/foros/forumdisplay.php?f=14)
-   -   Marca días inahbiles, periodo vacacional en un calendario stringGrig (https://www.clubdelphi.com/foros/showthread.php?t=88647)

El_Chava 09-07-2015 17:14:13

Marca días inahbiles, periodo vacacional en un calendario stringGrig
 
1 Archivos Adjunto(s)
Hola amigos esperando que se encuentren bien aquí de nuevo con una situación que espero me puedan ayudar a solucionar y es la siguiente. Estoy desarrollando un calendario de labores en el cual se deben especificar los días inhábiles, así como los 2 periodos vacacionales que se tienes en el año. Para eso lo que hice fue usar stringGrid para cada mes ya el procedimiento de llenar los meses con sus respectivos días y dependiendo del día en que comienzan en la semana ya esta programado el detalle es el siguiente. tengo un popmenu que al dar click sobre algún día del calendario del stringGrid le saldrá la opciones de día inhábil, primer periodo vacacional y segundo periodo vacacional. El detalle aquí es como puedo hacer que al dar click por ejemplo el día inhábil del popmenu me cambie de color esa celda por ejemplo color gris (como se ve en el archivo adjunto). ya que posteriormente de guardara en una base de datos. Espero me puedan ayudar de antemano muchas gracias.
p.d. Estoy usando lazarus y los componentes de calendario no cuenta con multselect por eso opte por usar StringGrid.

Estos son los códigos que he encontrado en el foro y he usado
Evento onDrawCell
Código Delphi [-]
procedure TFrmCalendarioOficial.StrEneroDrawCell(Sender: TObject; aCol,
  aRow: Integer; aRect: TRect; aState: TGridDrawState);
begin
   with TStringGrid(Sender) do
  begin
    if not (gdFixed in aState) then
    begin
      if ((gdSelected in aState) and (Cells[Acol,Arow]<>'')) then
        Canvas.Brush.Color := clHighlight
      else
        Canvas.Brush.Color := clWindow;
      Canvas.FillRect(aRect);
    end;
    Canvas.TextRect(aRect, ACol, ARow, Cells[ACol, ARow]);
  end;
end;
Evento OnMouseDown
Código Delphi [-]

//con este procedimientos de selecciona y se pinta la celda al dar click derecho del ratón para que el usario detecte que día va a marcar como inhábil o periodo vacacional
procedure seleccionar_dia(X, Y: Integer;StrMes:TStringGrid);
var aCol, aRow :integer;
       p:TPoint;
 begin
   with FrmCalendarioOficial do
    begin
     StrMes.MouseToCell(X, Y, aCol, aRow);
     StrMes.Row := aRow;
     StrMes.Col := aCol;
     p := StrMes.ClientToScreen(Point(x,y));
     PopupMenu1.popup(p.x, p.y);
    end;
 end; 

procedure TFrmCalendarioOficial.StrEneroMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  var aCol, aRow :integer;
      p:TPoint;
begin
      if button = mbright then
      seleccionar_dia( X, Y,StrEnero);
end;

Neftali [Germán.Estévez] 09-07-2015 18:41:17

Lo lógico es que guardes el estado de los días en alguna estructura que luego te servirá para almacenarlos.
Cuando seleccionas un día como inhabil, debes almacenarlo en la estructura, al pintar en el StringGrid, sólo debes consultar la estructura para saber qué días pintar de cada color.

El_Chava 09-07-2015 20:25:53

1 Archivos Adjunto(s)
hola Neftali

Cita:

Lo lógico es que guardes el estado de los días en alguna estructura que luego te servirá para almacenarlos.
Cuando seleccionas un día como inhabil, debes almacenarlo en la estructura, al pintar en el StringGrid, sólo debes consultar la estructura para saber qué días pintar de cada color.
Gracias por tu respuesta. Hasta el momento ya logre que al dar click con el botón izquierdo del mouse seleccionando el día y luego si le da click derecho en el popupmenu selecciona día inábil se ponga del color que hace referencia a los dias inahbiles. el problema es que si en el mismo mes hay otro día inhabil y deseo registrarlo pues me borra la marca del día que ya había marcado como inhabil. así que la pregunta aquí es ¿como mantener la celda con el color asignado sin que se borre? Espero me puedan ayudar a encontrar al solucion. En el archivo adjunto podra ver una imagen del avance. :)

tmsanchez 09-07-2015 22:32:23

HOla, no tengo delphi a la mano, pero ésta es una idea de cómo podría ser:

Guarda la información en un arreglo de dos dimensiones:

Código Delphi [-]
type
  TCalendarioMes = Array[1..7,1..5] of Integer;
var
  enero : TCalendarioMes;

procedure inicializaCalendario;
var
  i,j : Integer;
begin
  for i:= 1 to 7 do
    for j := 1 to 5 do
      enero[i,j] := 0;  // sin asignar
end;

procedure marcaAsignado(fila, columna: Integer);
begin
  enero[fila,columna] := 1;
end;

procedure desmarcaAsignado(fila, columna: Integer);
begin
  enero[fila,columna] := 0;
end;


Cuando selecciones la celda en el grid cambias el estado en el arreglo

Código Delphi [-]
procedure seleccionar_dia(X, Y: Integer;StrMes:TStringGrid);
var
  aCol, aRow :integer;
  p:TPoint;
begin
  with FrmCalendarioOficial do
  begin
    StrMes.MouseToCell(X, Y, aCol, aRow);      
    StrMes.Row := aRow;      
    StrMes.Col := aCol;
    marcaAsignado(aCol,aRow);          
    p := StrMes.ClientToScreen(Point(x,y));
    PopupMenu1.popup(p.x, p.y);
  end;
end;

procedure TFrmCalendarioOficial.StrEneroMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  aCol, aRow :integer;
  p:TPoint;
begin
  if button = mbright then
    seleccionar_dia( X, Y,StrEnero);
end;


Cuando verifiques si se tiene que resaltar consultas el arreglo

Código Delphi [-]
procedure TFrmCalendarioOficial.StrEneroDrawCell(Sender: TObject; aCol,   
  aRow: Integer; aRect: TRect; aState: TGridDrawState);
begin
  with TStringGrid(Sender) do
  begin
    if not (gdFixed in aState) then
    begin       // aqui puedes verificar si esta encendido o asignado
      if ((gdSelected in aState) and (Cells[Acol,Arow]<>'')) then
        Canvas.Brush.Color := clHighlight
      else
        Canvas.Brush.Color := clWindow;
      Canvas.FillRect(aRect);
    end;
  Canvas.TextRect(aRect, ACol, ARow, Cells[ACol, ARow]);
  end;
end;

Neftali [Germán.Estévez] 10-07-2015 10:14:09

Cita:

Empezado por El_Chava (Mensaje 494222)
...el problema es que si en el mismo mes hay otro día inhabil y deseo registrarlo pues me borra la marca del día que ya había marcado como inhabil. así que la pregunta aquí es ¿como mantener la celda con el color asignado sin que se borre?

Lo que no se es cómo guardas la información de los días inhabiles.
Si marcas 2 días inhabiles en un mes, debes tenerlos almacenados en algún sitio, de forma que luego cuando pintes el grid (en el evento DrawCell) debes consultar esos días y pintarlos.

En el pintado de cada celda del stringgrid se debe hacer una consulta a la estructura, y si la celda que se está dibujando corresponde a un día inhabil, entonces debes pintarla.

¿Cómo se guardan esos días?
¿Qué estructura estás utilizando?
¿Qué función estás utilizando en el OnDrawColumnCell -o similar-?

ecfisa 10-07-2015 15:15:53

Hola El_Chava.

Como te comenta Neftali todo puede variar según programes la estructuración de los datos.

Te pongo una idea de tantas en que podrías realizarlo. El ejemplo hace uso del mouse tanto para la elección única como múltiple de días y usa un PopupMenu cuyos ítems ponen el día o la selección en día feriado o laboral.

Por la imágen que adjuntaste pareciera que usas 12 StringGrids, el ejemplo usa uno solo (StringGridEnero), pero es muy simple modificarlo para que funcione con los restantes.
Código Delphi [-]
...
type
  TForm1 = class(TForm)
    RadioGroup1: TRadioGroup;
    StringGridEnero: TStringGrid;
    PopupMenu1: TPopupMenu;
    pmiFeriado: TMenuItem;
    pmiLaboral: TMenuItem;
    
    btSave: TButton;
    btReset: TButton;
    btLoad: TButton;
    procedure FormCreate(Sender: TObject);
    procedure PopupItemsClick(Sender: TObject);
    procedure StringGridDrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure btSaveClick(Sender: TObject);
    procedure btLoadClick(Sender: TObject);
    procedure btResetClick(Sender: TObject);
  private
    FFileName : string;
    procedure SaveStringGrid(SG: TStringGrid; const aFileName: string);
    procedure LoadStringGrid(SG: TStringGrid; const aFileName: string);
  public
  end;

var
  Form1: TForm1;

implementation

const
  NOPRN     = #144;   // caracter no imprimible, dado la forma de cargarlo que uso (CommaText) 

// Carga unos datos en el StringGrid
procedure IniciarDemo(StringGrid: TStringGrid);
var
  c, r : Integer;
begin
 with StringGrid do
  begin
    FixedCols:= 0;
    FixedRows:= 1;
    ColCount := 7;
    RowCount := 6;
    Options  := Options + [goRangeSelect] - [goEditing];
    for r := 0 to RowCount-1 do Rows[r].QuoteChar:= #0;
    Rows[0].CommaText := 'LUN,MAR,MIE,JUE,VIE,SAB,DOM';
    Rows[1].CommaText := NOPRN+','+NOPRN+','+NOPRN+',1,2,3,4';
    Rows[2].CommaText := '5,6,7,8,9,10,11';
    Rows[3].CommaText := '12,13,14,15,16,17,18';
    Rows[4].CommaText := '19,20,21,22,23,24,25';
    Rows[5].CommaText := '26,27,28,29,30,31,'+NOPRN;
    for r := FixedRows to RowCount -1 do
      for c:= FixedCols to ColCount-1 do
        Objects[c, r] := TObject(False);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FFileName := ExtractFilePath(Application.ExeName)+'enero.dat';
  IniciarDemo(StringGridEnero);
end;

// OnDrawCell, evento asignado a cada StringGrid
procedure TForm1.StringGridDrawCell(Sender: TObject; ACol,
  ARow: Integer; Rect: TRect; State: TGridDrawState);
const
  COLORCELL : array[Boolean] of TColor = (clWindow, clGray);
  FLAGS = DT_SINGLELINE or DT_CENTER or DT_VCENTER;
begin
  with TStringGrid(Sender) do
  begin
    if Boolean(Objects[ACol,ARow]) and (Cells[ACol,ARow] <> NOPRN) then
    begin
      Canvas.Brush.Color := COLORCELL[Boolean(Objects[ACol,ARow])];
      Canvas.FillRect(Rect);
      DrawText(Canvas.Handle, PChar(Cells[ACol, ARow]), -1, Rect, FLAGS);
    end;
  end;
end;

// PopupMenu OnClick (Feriado/Laboral). Asociado a cada StringGrid
procedure TForm1.PopupItemsClick(Sender: TObject);
var
  c,r : Integer;
begin
  with TStringGrid(PopupMenu1.PopupComponent) do
    for c := Selection.Left to Selection.Right do
      for r := Selection.Top to Selection.Bottom do
         Objects[c,r] := TObject(TMenuItem(Sender).MenuIndex = 0);
end;

// Botón Guardar
procedure TForm1.btSaveClick(Sender: TObject);
begin
  SaveStringGrid(StringGridEnero, FFileName);
end;

// Botón Reset
procedure TForm1.btResetClick(Sender: TObject);
begin
  IniciarDemo(StringGridEnero);
end;

// Botón Cargar
procedure TForm1.btLoadClick(Sender: TObject);
begin
  LoadStringGrid(StringGridEnero, FFileName);
end;

// Guardar StringGrid
procedure TForm1.SaveStringGrid(SG: TStringGrid; const aFileName: string);
var
  c, r: Integer;
  d: Byte;
  b: Boolean;
begin
  with TFileStream.Create(aFileName, fmCreate) do
  try
    for c := SG.FixedCols to SG.ColCount-1 do
      for r := SG.FixedRows to SG.RowCount-1 do
      begin
        d := StrToIntDef(SG.Cells[c, r], 0);
        WriteBuffer(d, SizeOf(Byte));
        b := Boolean(SG.Objects[c, r]);
        WriteBuffer(b, SizeOf(Boolean));
      end;
  finally
    Free;
  end;
end;

// Cargar StringGrid
procedure TForm1.LoadStringGrid(SG: TStringGrid; const aFileName: string);
var
  c, r: Integer;
  d: Byte;
  b: Boolean;
begin
  with TFileStream.Create(aFileName, fmOpenRead) do
  try
    for c := SG.FixedCols to SG.ColCount-1 do
      for r := SG.FixedRows to SG.RowCount-1 do
      begin
        ReadBuffer(d, SizeOf(Byte));
        if d = 0 then
          SG.Cells[c, r] := NOPRN
        else
          SG.Cells[c,r] := IntToStr(d);
        ReadBuffer(b, Sizeof(Boolean));
        SG.Objects[c, r] := TObject(b);
      end;
  finally
    Free;
  end;
end;

Muestra:


Saludos :)

El_Chava 10-07-2015 19:04:56

Hola ecfisa, Neftali y tmsanchez primeramente muchas gracias por responder. Al fin logre lo que quería hacer y era que por el momento solo me marcaran los días en el stringGrid antes de guardarlos en la base de datos.Investigando por la red(y claro en el foro) encontre ejemplos y los adapte a los requerimientos que necesitaba Les dejo el código espero le sean de utilidad. Saludos.

procedimientos
Código:

procedure seleccionar_dia(X, Y: Integer;StrMes:TStringGrid);
var aCol, aRow :integer;
      p:TPoint;
 begin
  with FrmCalendarioOficial do
    begin
    StrMes.MouseToCell(X, Y, aCol, aRow);
    StrMes.Row := aRow;
    StrMes.Col := aCol;
    p := StrMes.ClientToScreen(Point(x,y));
    PopupMenu1.popup(p.x, p.y);
    end;
 end;
 
procedure celda_seleccionada(Sender: TObject);
var
  aRect:TRect;
begin
    with TStringGrid(sender) do
    begin
    aRect:= CellRect(Col,Row);
      if Cells[Col,Row]<>'' then
      begin
        Objects[Col, Row] := TObject(clSilver);
        Canvas.Brush.Color := TColor(Objects[Col, Row]);
        Canvas.FillRect(aRect);
        Canvas.Font.Color := clBlack;
        Canvas.TextOut(aRect.Left+2, aRect.Top+2, Cells[Col, Row]);
      end;
    end;
end;

En el evento OnCreate del formulario
Código:


procedure TFrmCalendarioOficial.FormCreate(Sender: TObject);
var
  c, f: Integer;
begin
  with StrEnero do
  begin
    for c := FixedCols to ColCount-1 do
      for f := FixedRows to RowCount-1 do
      begin
        Objects[c, f]:= TObject(clWhite); // color por defecto
      end;
  end;
end;

En el evento OnDrawCell del StringGrid
Código:


procedure TFrmCalendarioOficial.StrEneroDrawCell(Sender: TObject; aCol,
  aRow: Integer; aRect: TRect; aState: TGridDrawState);
begin
  with TStringGrid(Sender) do
  begin
    if (ARow >= FixedRows) then
    begin
    if ((gdSelected in aState) and (Cells[Acol,Arow]<>'')) then
        Canvas.Brush.Color := clHighlight
    else
      Canvas.Brush.Color := TColor(Objects[ACol, ARow]);
      Canvas.FillRect(aRect);
      Canvas.Font.Color := clBlack;
      Canvas.TextOut(aRect.Left+2, aRect.Top+2, Cells[ACol, ARow]);
    end;
  end;
end;

En el evento MouseDown del StringGrid
Código:


procedure TFrmCalendarioOficial.StrEneroMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  var aCol, aRow :integer;
      p:TPoint;
begin
  with TStringGrid(Sender) do
    begin
      MouseToCell(X, Y, ACol, ARow);
    case Button of
      // mbLeft :seleccionar_dia( X, Y,StrEnero);
        mbRight:  seleccionar_dia( X, Y,StrEnero);
      end;
    end;
end;

en el popupmenu al seleccionar Día inhábil
Código:


procedure TFrmCalendarioOficial.MenudiainhabilClick(Sender: TObject);
begin
 if strEnero.Focused then
  celda_seleccionada(StrEnero);
end;

Resultado

Soa Pelaez 17-10-2017 17:59:37

Podrías subir tu proyecto o el formulario donde hiciste eso, estoy necesitando algo parecido, te agradecería que me colaboraras. Gracias.


La franja horaria es GMT +2. Ahora son las 05:08:19.

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