Recent

Author Topic: Intercept an event for a datasource in a move my component.  (Read 6880 times)

xinyiman

  • Hero Member
  • *****
  • Posts: 2261
    • Lazarus and Free Pascal italian community
If I were to create a new component in my private variables how do I put a TDataSource to notice inside the new object that is a change in the datasource? Which in turn is initialized with an external data source I use to populate a TDBGrid?

Code: [Select]
unit ExtDBListBox;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Grids, sqldb, db;

type
  TExtDBListBox = class(TStringGrid)
  private
    { Private declarations }
    MyDataSourceList: TDataSource; { il datasource che mi fa vedere i dati nel componente }
    MyDataSourceIn: TDataSource; { il datasource che contiene i record sorgenti }
    MySQLOut: TSQLQuery; { il datasource che contiene i record in output, ovvero quelli che vado a modificare }
    ItemsSelected: array of boolean; { mi serve per capire se una (o più) riga è selezionata }
    Intestazione: boolean; { se TRUE vuol dire che devo far vedere l'intestazione dei dati nel componente }
    MyFieldList: string;
    MyFieldIn: string;
    MyFieldOutList, MyFieldOutIn: string;
    MyAutoSizeColumns: BOOLEAN;

    procedure InserisciRecord();
    procedure EliminaRecord();
    procedure ColoraComponente();
    function EsisteRecord(ValIn: variant; ValoreList: variant): BOOLEAN;

  protected
    { Protected declarations }
    procedure SetDataSourceList(DataSourceList: TDataSource);
    procedure SetDataSourceIn(DataSourceIn: TDataSource);
    procedure SetQuerySQLOut(SQLOut: TSQLQuery);
    procedure SetTitleColumns(TitleColumns: BOOLEAN);
    procedure SetFieldList(FieldList: string);
    procedure SetFieldIn(FieldIn: string);
    procedure SetFieldOutList(FieldOutList: string);
    procedure SetFieldOutIn(FieldOutIn: string);
    procedure SetAutoSizeColumns(ColumnsAutoSize: BOOLEAN);
  public
    { Public declarations }
    constructor Create(TheOwner: TComponent); override;
    procedure Requery();
    procedure ColumnVisible(ColIndex: integer; Value: boolean);
    procedure ColumnAlign(ColIndex: integer; Value: TAlignment);
    procedure Click; override;
    procedure DrawCell(aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  published
    { Published declarations }
    //property OnClick;
    property DataSourceList: TDataSource read MyDataSourceList write MyDataSourceList;
    property DataSourceIn: TDataSource read MyDataSourceIn write MyDataSourceIn;
    property SQLOut: TSQLQuery read MySQLOut write MySQLOut;
    property TitleColumns: BOOLEAN read Intestazione write Intestazione;
    property FieldList: string read MyFieldList write MyFieldList;
    property FieldIn: string read MyFieldIn write MyFieldIn;
    property FieldOutList: string read MyFieldOutList write MyFieldOutList;
    property FieldOutIn: string read MyFieldOutIn write MyFieldOutIn;
    property ColumnsAutoSize: BOOLEAN read MyAutoSizeColumns write MyAutoSizeColumns;
  end;

procedure Register;

implementation

procedure Register;
begin
  {$I ExtDBListBox_icon.lrs}
  RegisterComponents('Standard',[TExtDBListBox]);
end;

constructor TExtDBListBox.Create(TheOwner: TComponent);
begin
     inherited Create(TheOwner);
     {cambio il layout della griglia per far si che si veda come se fosse una listbox}
     Self.ColCount:=1;
     Self.FixedCols:=0;
     Self.FixedRows:=0;
     Self.AutoEdit:=false;
     Self.GridLineWidth:=0;
     Intestazione:=FALSE;
     Self.SetDataSourceList(nil); //mi prendo il datasource dal quale lavorare
     Self.SetDataSourceIn(nil); //mi prendo il datasource dal quale lavorare
     Self.SetQuerySQLOut(nil); //mi prendo il TSQlQuery dal quale lavorare
     MyFieldList:='';
     MyFieldIn:='';
     MyFieldOutList:='';
     MyFieldOutIn:='';
     MyAutoSizeColumns:=FALSE;
end;

procedure TExtDBListBox.Requery();
var
   NumRighe, NumColonne: LongInt;
   Colonna, Riga: integer;
   app:string;
   MyTextStyle: TTextStyle;
begin
     Self.SetDataSourceList(DataSourceList); //mi prendo il datasource dal quale lavorare
     Self.SetDataSourceIn(DataSourceIn); //mi prendo il datasource dal quale lavorare
     Self.SetQuerySQLOut(MySQLOut); //mi prendo il datasource dal quale lavorare

     Self.SetFieldList(FieldList);
     Self.SetFieldIn(FieldIn);
     Self.SetFieldOutList(FieldOutList);
     Self.SetFieldOutIn(FieldOutIn);

     Self.Clear; //pulisco la listbox dai dati
     {ora disegno il dataset}
     if ((MyDataSourceList<>nil)AND(not MyDataSourceList.DataSet.EOF)) then
     begin
          {mi ricavo il numero di colonne che devo stampare a video}
          NumColonne:=MyDataSourceList.DataSet.FieldCount;
          For Colonna:=0 to (NumColonne-Self.Columns.Count)-1 do
              Self.Columns.Add;
          {mi scorro velocemente il recordset per capire quante righe ho}
          MyDataSourceList.DataSet.First;
          NumRighe:=0;
          while not MyDataSourceList.DataSet.EOF do
          begin
               Inc(NumRighe);
               MyDataSourceList.DataSet.Next;
          end;
          {ora che ho il numero di righe mi stampo la griglia}
          if Intestazione=TRUE then
          begin
               Self.RowCount:=NumRighe+1;
               {ora inserisco la testata}
               for Colonna:=0 to NumColonne-1 do
               begin
                    app:=MyDataSourceList.DataSet.FieldDefs[Colonna].Name;
                    if Length(Trim(app))<=0 then
                       app:='Col' + IntToStr(Colonna);
                    Self.Cells[Colonna,0]:=app;
               end;
               Riga:=1;
          end
          else
          begin
               //Self.Columns.Add.Create(nil);
               Self.RowCount:=NumRighe;
               Riga:=0;
          end;
          {ora inserisco i dati}
          MyDataSourceList.DataSet.First;
          while not MyDataSourceList.DataSet.EOF do
          begin
               {disegno la singola riga}
               for Colonna:=0 to NumColonne-1 do
               begin
                    Self.Cells[Colonna,Riga]:=MyDataSourceList.DataSet.Fields[Colonna].AsString;
               end;
               Inc(Riga);
               MyDataSourceList.DataSet.Next;
          end;

          SetLength(ItemsSelected,NumRighe); //dimensiono il vettore che mi contiene se la riga è selezionata oppure no
          For Riga:=0 to NumRighe-1 do
              ItemsSelected[Riga]:=FALSE;
          if Self.MyAutoSizeColumns=TRUE then
             Self.AutoSizeColumns; //dimensiona le colonne correttamente
          Self.ColoraComponente();
          MyDataSourceList.DataSet.First; { se non faccio questo passo al prossimo requery che faccio mi trovo già al fondo e non posso fare niente }
     end;
end;

procedure TExtDBListBox.ColumnVisible(ColIndex: integer; Value: boolean);
begin
     Self.Columns[ColIndex].Visible:=Value;
end;

procedure TExtDBListBox.ColumnAlign(ColIndex: integer; Value: TAlignment);
begin
     Self.Columns[ColIndex].Alignment:=Value;
end;

procedure TExtDBListBox.SetDataSourceList(DataSourceList: TDataSource);
begin
     Self.MyDataSourceList:=DataSourceList;
end;

procedure TExtDBListBox.SetDataSourceIn(DataSourceIn: TDataSource);
begin
     Self.MyDataSourceIn:=DataSourceIn;
end;

procedure TExtDBListBox.SetQuerySQLOut(SQLOut: TSQLQuery);
begin
     Self.MySqlOut:=SqlOut;
end;

procedure TExtDBListBox.SetTitleColumns(TitleColumns: BOOLEAN);
begin
     Self.Intestazione:=TitleColumns;
end;

procedure TExtDBListBox.SetFieldList(FieldList: string);
begin
     Self.MyFieldList:=FieldList;
end;

procedure TExtDBListBox.SetFieldIn(FieldIn: string);
begin
     Self.MyFieldIn:=FieldIn;
end;

procedure TExtDBListBox.SetFieldOutList(FieldOutList: string);
begin
     Self.MyFieldOutList:=FieldOutList;
end;

procedure TExtDBListBox.SetFieldOutIn(FieldOutIn: string);
begin
     Self.MyFieldOutIn:=FieldOutIn;
end;

procedure TExtDBListBox.SetAutoSizeColumns(ColumnsAutoSize: BOOLEAN);
begin
     Self.MyAutoSizeColumns:=ColumnsAutoSize;
end;

procedure TExtDBListBox.Click;
var
   Cont: integer;
begin
     inherited Click;
     if ((MyDataSourceList<>nil)AND(not MyDataSourceList.DataSet.EOF)) then
     begin
          MyDataSourceList.DataSet.First;
          for Cont:=0 to Self.Row-1 do
              MyDataSourceList.DataSet.Next;
     end;
end;

procedure TExtDBListBox.DrawCell(aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState);
var
   app: integer;
   app2: boolean;
begin
     inherited DrawCell(aCol, aRow,aRect, aState);
     Self.Canvas.Font.Color := clBlack;  // colore di default
     Self.Canvas.Brush.Color := clWhite;
     if ((Intestazione = TRUE) AND (ARow = 0)) then   // In primo luogo verificare se la riga o colonna fissa
      begin
       Self.Canvas.Brush.Color := clBtnFace;
      end
     else
      begin
         app:=Self.Row - 1;
         app2:=ItemsSelected[Self.Row - 1];
         if (ItemsSelected[aRow - 1] = True) then
         begin        // Will only color selected rows
              Self.Canvas.Font.Color := clWhite;
              Self.Canvas.Brush.Color := clBlue;
         end;
      end;
     Self.Canvas.FillRect(aRect);
     Self.Canvas.TextOut(aRect.Left, aRect.Top, Self.Cells[ACol, ARow]);
end;

procedure TExtDBListBox.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
   mycol, myrow : Integer;
begin
     inherited MouseUp(Button, Shift, X, Y);
     Self.MouseToCell(X, Y, mycol, myrow);  // This will tell us what cell (we need row) was selected
     if ((row < Self.RowCount)) then  // Again don't select fixed or blank row
        if (((myrow > 0)AND(Intestazione=TRUE))OR(myrow >= 0)) then
           if (ItemsSelected[Self.Row - 1] = True) then
           begin
                ItemsSelected[Self.Row - 1] := False;
                Self.EliminaRecord();
           end
           else
           begin
                ItemsSelected[Self.Row - 1] := True;
                Self.InserisciRecord();
           end;
     Self.Invalidate;
end;

procedure TExtDBListBox.ColoraComponente();
var
   Cont: integer;
begin
     Cont:=0;
     MyDataSourceList.DataSet.First;
     while not MyDataSourceList.DataSet.EOF do
     begin
          if Self.EsisteRecord(MyDataSourceIn.DataSet.FieldByName(MyFieldIn).Value,MyDataSourceList.DataSet.FieldByName(MyFieldList).Value)=TRUE then
          begin
             //colora la riga
             ItemsSelected[Cont-1]:=TRUE;
          end
          else
          begin
              //non colorare la riga
              ItemsSelected[Cont-1]:=FALSE;
          end;
          Inc(Cont);
          MyDataSourceList.DataSet.Next;
     end;
end;

function TExtDBListBox.EsisteRecord(ValIn: variant; ValoreList: variant): BOOLEAN;
begin
     MySqlOut.First;
     while not MySqlOut.EOF do
     begin
          if ((MySqlOut.FieldByName(MyFieldOutList).Value=ValoreList)AND(MySqlOut.FieldByName(MyFieldOutIn).Value=ValIn)) then
          begin
               EsisteRecord:=TRUE;
               Exit;
          end;
          MySqlOut.Next;
     end;
     EsisteRecord:=FALSE;
end;

procedure TExtDBListBox.InserisciRecord();
begin
     if Self.EsisteRecord(MyDataSourceIn.DataSet.FieldByName(MyFieldIn).Value, MyDataSourceList.DataSet.FieldByName(MyFieldList).Value)=FALSE then
     begin
          MySqlOut.Append;
          MySqlOut.FieldByName(MyFieldOutIn).Value:=MyDataSourceIn.DataSet.FieldByName(MyFieldIn).Value;
          MySqlOut.FieldByName(MyFieldOutList).Value:=MyDataSourceList.DataSet.FieldByName(MyFieldList).Value;
          MySqlOut.Post;
          MySqlOut.ApplyUpdates;
     end;
end;

procedure TExtDBListBox.EliminaRecord();
begin
     MySqlOut.First;
     while not MySqlOut.EOF do
     begin
          if ((MySqlOut.FieldByName(MyFieldOutIn).Value=MyDataSourceIn.DataSet.FieldByName(MyFieldIn).Value)AND(MySqlOut.FieldByName(MyFieldOutList).Value=MyDataSourceList.DataSet.FieldByName(MyFieldList).Value)) then
          begin
               MySqlOut.Delete;
               MySqlOut.ApplyUpdates;
               Exit;
          end
          else
          begin
               MySqlOut.Next;
          end;
     end;
end;

end.
Win10, Ubuntu and Mac
Lazarus: 2.1.0
FPC: 3.3.1

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: Intercept an event for a datasource in a move my component.
« Reply #1 on: June 23, 2011, 03:29:35 pm »
You can do this:
Code: Pascal  [Select][+][-]
  1.    procedure SetMyDataSourceIn(const AValue: TDataSource);
  2.    ....
  3.    property DataSourceIn: TDataSource read MyDataSourceIn write SetMyDataSourceIn;
  4. end;
  5.  
  6. procedure xxxx.SetMyDataSourceIn(const AValue: TDataSource);
  7. begin
  8.    if AValue = DataSourceIn then begin
  9.       Exit;
  10.    end;
  11.    // Notify a change in DataSourceIn!!
  12. end;
  13.  

And you always have to use the property to get it working. Is that what you need?

xinyiman

  • Hero Member
  • *****
  • Posts: 2261
    • Lazarus and Free Pascal italian community
Re: Intercept an event for a datasource in a move my component.
« Reply #2 on: June 23, 2011, 03:47:24 pm »
I have to run the Requery procedures every time I move on record datasourceIn

But it does not work I go wrong for some reason. Any other solution?
Win10, Ubuntu and Mac
Lazarus: 2.1.0
FPC: 3.3.1

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: Intercept an event for a datasource in a move my component.
« Reply #3 on: June 23, 2011, 04:05:44 pm »
what do you mean with
... move on record datasourceIn

I think I can't understand what you are trying to do nor what you need...
« Last Edit: June 23, 2011, 04:08:17 pm by garlar27 »

xinyiman

  • Hero Member
  • *****
  • Posts: 2261
    • Lazarus and Free Pascal italian community
Re: Intercept an event for a datasource in a move my component.
« Reply #4 on: June 23, 2011, 04:09:39 pm »
I mean that I have a datasource that is connected to a TDBGrid, and I read the input data from this datasource. But I want to understand how I can intercept the transmission of records within TDBGrid, so that you can perform a procedure.
Win10, Ubuntu and Mac
Lazarus: 2.1.0
FPC: 3.3.1

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: Intercept an event for a datasource in a move my component.
« Reply #5 on: June 23, 2011, 06:42:35 pm »
Detect the message with data from DataSource to DBGrid (I think) should be done in a TDBGrid event which should exist but, should be private. If you are using FPC 2.5.1 maybe a class helper would do the trick.
Anyway it is beyond my knowledge.

xinyiman

  • Hero Member
  • *****
  • Posts: 2261
    • Lazarus and Free Pascal italian community
Re: Intercept an event for a datasource in a move my component.
« Reply #6 on: June 24, 2011, 07:40:46 am »
I would really understand how to do it, why make the component that it is done by creating really useful. No one else has any advice to give?
Win10, Ubuntu and Mac
Lazarus: 2.1.0
FPC: 3.3.1

 

TinyPortal © 2005-2018