-3

I had a form which has a DataSource,AdoQuery,AdoConnection,DBgrid plus couple edit and a memo. User enter his username,street address, etc.. and hit 'save' button. On that time the application is write the details in a comma separated txt file, which is connected to an Access linked table. When user hit 'save' button it write into the memo instantly but not live update the dbgrid database, only when reopen the app.

I search a lot but everybody has different suggestions: do a dbgrid refresh, adorequery, post, append, showmodal, open and close the database etc.

My question is why the dbgrid liveupdate doesn't work?

Sourcecode is the following:


unit test;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, StrUtils, Grids, Buttons, pngimage, ExtCtrls,
  ComCtrls, DBGrids, DB, DBTables, ColorGrd, DirOutln, ADODB,
  FMTBcd, SqlExpr, DBCtrls, DBClient, jpeg;

    type
      TForm1 = class(TForm)
        Memo1: TMemo;
        exit: TButton;
        resetbtn: TButton;
        Label3: TLabel;
        GroupBox1: TGroupBox;
        Label7: TLabel;
        Label8: TLabel;
        GroupBox2: TGroupBox;
        Label1: TLabel;
        Edit1: TEdit;
        Edit2: TEdit;
        Edit3: TEdit;
        Generate: TButton;
        GroupBox3: TGroupBox;
        Label5: TLabel;
        Label6: TLabel;
        CheckBox1: TCheckBox;
        Image1: TImage;
        Image2: TImage;
        Button6: TButton;
        DateTimePicker1: TDateTimePicker;
        GroupBox4: TGroupBox;
        Label10: TLabel;
        Label9: TLabel;
        dellastentry: TButton;
        ADOConnection1: TADOConnection;
        ADOQuery1: TADOQuery;
        DataSource1: TDataSource;
        DBGrid1: TDBGrid;
        Label13: TLabel;
        Label14: TLabel;
        Label16: TLabel;
        Label17: TLabel;
        Label18: TLabel;
        Label2: TLabel;
        Label4: TLabel;
        Label11: TLabel;
        Label15: TLabel;
        ADOQuery1Username: TWideStringField;
        ADOQuery1RequestedNumber: TWideStringField;
        ADOQuery1AllocatedNumber: TWideStringField;
        ADOQuery1DateofRequest: TWideStringField;
        procedure exitClick(Sender: TObject);
        procedure resetbtnClick(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure dellastentryClick(Sender: TObject);
        procedure GenerateClick(Sender: TObject);
        procedure CheckBox1Click(Sender: TObject);
        procedure FormShow(Sender: TObject);
        procedure Button6Click(Sender: TObject);
        procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);



      private
        { Private declarations }
      public
        { Public declarations }
      end;

    var
      Form1: TForm1;

    implementation


    {$R *.dfm}

    function GetCurrentUserName: string;
     const
      cnMaxUserNameLen = 50;
    var
      sUserName: string;
      dwUserNameLen: DWORD;
     begin
      dwUserNameLen := cnMaxUserNameLen - 1;
      SetLength(sUserName, cnMaxUserNameLen);
      GetUserName(PChar(sUserName), dwUserNameLen);
      SetLength(sUserName, dwUserNameLen);
      Result := sUserName;
     end;


    procedure TForm1.exitClick(Sender: TObject);
    begin
     Memo1.Lines.SaveToFile('C:\Numbergen\NumberDB.txt');
     form1.Close;

    end;

    procedure TForm1.resetbtnClick(Sender: TObject);
    begin
     edit1.Clear;
     edit2.Clear;
    end;


    procedure TForm1.FormCreate(Sender: TObject);
    begin
       Memo1.Lines.LoadFromFile('C:\Numbergen\NumberDB.txt');
        Memo1.WordWrap := true;
    end;

    procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    begin
      form1.ShowModal;
       form1.Free;
    end;

    procedure TForm1.FormShow(Sender: TObject);
       var lStrings: TStringList;
    begin
     DataSource1.DataSet.Append;
     Label6.Caption :=GetCurrentUserName;

      lStrings := TStringList.Create;
      LStrings.Delimiter := ',';
      lStrings.DelimitedText := Memo1.Lines[Memo1.Lines.Count-1];
      Label8.Caption:= lStrings.Strings[0];
      Label13.Caption:= lStrings.Strings[1];
      Label14.Caption:= lStrings.Strings[2];
      Label15.Caption:= lStrings.Strings[3];
    end;

    procedure TForm1.dellastentryClick(Sender: TObject);
    begin
     Memo1.Lines.Delete(Memo1.Lines.Count-1);
    end;

    procedure TForm1.Button6Click(Sender: TObject);
    var val2, sum: Integer;
     begin
      val2 := StrToInt(Edit3.Text);
      sum := val2;
      Edit3.Text := (IntToStr(sum+1));
     end;

    procedure TForm1.CheckBox1Click(Sender: TObject);
    begin
     if checkbox1.Checked
      then
       Edit1.Text :=  Label6.Caption
      else Edit1.Text :='';
    end;

    procedure TForm1.GenerateClick(Sender: TObject);
     var  val1, val2, sum: Integer;
    begin
     val1 := StrToInt(Edit2.Text);
     val2 := StrToInt(Edit3.Text);
     sum := val1 + val2;
     Edit3.Text :=  IntToStr(sum);
     Memo1.Lines.SaveToFile('C:\Numbergen\NumberDB.txt');

      if edit1.Text =('')
       then MessageDlg('Invalid/Blank Username! Please enter one!',mtError, mbOKCancel, 0)
      else
      memo1.Lines.Add(edit1.Text+',' +edit2.Text+','+IntToStr(sum-val1)+'-'+edit3.text+ ','+formatdatetime('yyyy/mm/dd', datetimepicker1.date) );
    end;
    end.

Thank you

LoneRanger
  • 25
  • 1
  • 9

2 Answers2

2

It's not the responsibility of a TDBGrid to save changes to data, you need to do that yourself. In other words, the reason your data isn't getting saved is that you aren't actually calling the "save" method of AdoQuery1. This method is actually called Post, so somewhere in your code, e.g. the non-existent "save" button's OnClick handler you should be doing

if AdoQuery1.State in [dsEdit, dsInsert] then
  AdoQuery1.Post;

Btw, the reason your data gets saved at all with your current code is that certain dataset operations (not DBGrid ones) cause any changes to the dataset to be Posted. These include causing the dataset's logical cursor to scroll, e.g. by clicking in a different row in the DBGrid or closing the dataset. But it is extremely bad practice to rely on this - your form should always provide the user with an explicit way to save and cancel changes to a dataset.

Also btw, never write code like you have in your FormKeyDown - it is an accident waiting to happen.

MartynA
  • 30,454
  • 4
  • 32
  • 73
  • is it better if i work with sql rather than ms access and text based docs? – LoneRanger Aug 20 '17 at 11:38
  • What do you mean by "sql", MS Sql Server, or what? – MartynA Aug 20 '17 at 11:41
  • Well, MS Sql Server is a far more capable and powerful system than Access, with far better tools available. As to "text-based docs", if you mean data stored on text files on your local file system, why use them at all if you have something like MS Sql Server available? – MartynA Aug 20 '17 at 12:02
  • `procedure TForm1.Button1Click(Sender: TObject); begin if AdoQuery1.State in [dsEdit, dsInsert] then AdoQuery1.Post; DataSource1.DataSet.Append; end;` that's for the save button, and it insert an empty line at the end of the dbgrid, and after remove it. if i use Sami's solution, with `DataSource.DataSet.Post;` the application start with error.. – LoneRanger Aug 20 '17 at 12:25
  • 2
    "it insert an empty line at the end of the dbgrid" Of course it does - it adds another row to the dataset. You don't need to call `Append` immediately after `Post`. I really do wonder if you know what you are doing. – MartynA Aug 20 '17 at 14:09
  • Btw, try adding a TDBNavigator and connecting it to your DataSource1 - it may give you a better idea of the way a dataset like a TAdoQuery works. – MartynA Aug 20 '17 at 14:15
  • I try to understand how the codes represent a whole program. I m just a beginner . I will check with the dbnavigator. Anyway thanks for the help – LoneRanger Aug 20 '17 at 14:40
  • @LoneRanger `Append` mean that you will add a record, if you don't call `Post` after, then all data will be lost, So append -> add data -> post(save the data). – Ilyes Aug 20 '17 at 15:15
0

As you can see here:

 procedure TForm1.FormShow(Sender: TObject);
       var lStrings: TStringList;
    begin
     DataSource1.DataSet.Append;
     Label6.Caption :=GetCurrentUserName;

The DataSet is in dsInsert here , so you have to save changes.

There is two ways to do that:

  • Check the DataSet state as MartynA answer

  • Add a line DataSource.DataSet.Post; in your code.

btw, I don't see in your code that you save the data in the database.

Ilyes
  • 14,640
  • 4
  • 29
  • 55