Recent

Author Topic: Keep user from moving off current record  (Read 21545 times)

dodgebros

  • Full Member
  • ***
  • Posts: 169
Keep user from moving off current record
« on: April 13, 2015, 07:07:06 pm »
I have a form with a DBGrid and a DBNavigator on it.  In Delphi I could use the folowing code to keep a user from moving off the record ( any changes they have made are automatically saved if they move off the record ) if  the Dataset was in dsEdit or dsInsert mode.   I tried using the same code in this Lazarus project and it doesn't work.  Any ideas why it isn't working?  BTW, I'm new to Freepascal and the Lazarus IDE.   Below is the code.

Thanks,
TD

Code: [Select]
procedure TfrmMain.DBNavigator1BeforeAction(Sender: TObject;
  Button: TDBNavButtonType);
begin
  try
     // cancels navigation when in INSERT or EDIT mode
     if DataModule1.Datasource1.State in [dsInsert, dsEdit] then
       begin
         if (Button = nbFirst) Or (Button = nbPrior)
           Or (Button = nbNext) Or (Button = nbLast) then
             begin
               Beep;
               SysUtils.Abort;
             end;
       end;
     // cancels insert, delete, and refresh button click while in EDIT mode
     if DataModule1.Datasource1.State in [dsEdit] then
       begin
         if (Button = nbInsert) Or (Button = nbRefresh)
             Or (Button = nbDelete) then
           begin
             Beep;
             SysUtils.Abort;
           end;
       end;
     // cancels delete and refresh button click while in INSERT mode
     if DataModule1.Datasource1.State in [dsInsert] then
       begin
         if (Button = nbRefresh) Or (Button = nbDelete) then
           begin
             Beep;
             SysUtils.Abort;
           end;
       end;
   except
     on E : Exception do
        begin
           showmessage('Exception message = '+E.Message);
        end;
   end;
end
« Last Edit: April 13, 2015, 07:09:16 pm by dodgebros »

Cyrax

  • Hero Member
  • *****
  • Posts: 836
Re: Keep user from moving off current record
« Reply #1 on: April 13, 2015, 08:50:30 pm »
In FPC,  SysUtils.Abort doesn't work like it does in Delphi. Use Exit instead of Abort and save changes manually to record.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Keep user from moving off current record
« Reply #2 on: April 13, 2015, 10:29:03 pm »
In FPC,  SysUtils.Abort doesn't work like it does in Delphi. Use Exit instead of Abort and save changes manually to record.

I have no idea how to do it in Lazarus too but how calling exit is going to help? What will happen?
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

Cyrax

  • Hero Member
  • *****
  • Posts: 836
Re: Keep user from moving off current record
« Reply #3 on: April 13, 2015, 10:33:51 pm »
In FPC,  SysUtils.Abort doesn't work like it does in Delphi. Use Exit instead of Abort and save changes manually to record.

I have no idea how to do it in Lazarus too but how calling exit is going to help? What will happen?

From FPC RTL documentation : "Exit exits the current subroutine, and returns control to the calling routine."

See : http://www.freepascal.org/docs-html/rtl/system/exit.html

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Keep user from moving off current record
« Reply #4 on: April 13, 2015, 10:54:02 pm »
In FPC,  SysUtils.Abort doesn't work like it does in Delphi. Use Exit instead of Abort and save changes manually to record.

I have no idea how to do it in Lazarus too but how calling exit is going to help? What will happen?

From FPC RTL documentation : "Exit exits the current subroutine, and returns control to the calling routine."

See : http://www.freepascal.org/docs-html/rtl/system/exit.html
I know what exit does how is that going to stop dataset from moving to the next record?
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

Cyrax

  • Hero Member
  • *****
  • Posts: 836
Re: Keep user from moving off current record
« Reply #5 on: April 13, 2015, 10:56:22 pm »
In FPC,  SysUtils.Abort doesn't work like it does in Delphi. Use Exit instead of Abort and save changes manually to record.

I have no idea how to do it in Lazarus too but how calling exit is going to help? What will happen?

From FPC RTL documentation : "Exit exits the current subroutine, and returns control to the calling routine."

See : http://www.freepascal.org/docs-html/rtl/system/exit.html
I know what exit does how is that going to stop dataset from moving to the next record?

You need to prevent that manually by code.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Keep user from moving off current record
« Reply #6 on: April 13, 2015, 10:59:13 pm »
In FPC,  SysUtils.Abort doesn't work like it does in Delphi. Use Exit instead of Abort and save changes manually to record.

I have no idea how to do it in Lazarus too but how calling exit is going to help? What will happen?

From FPC RTL documentation : "Exit exits the current subroutine, and returns control to the calling routine."

See : http://www.freepascal.org/docs-html/rtl/system/exit.html
I know what exit does how is that going to stop dataset from moving to the next record?

You need to prevent that manually by code.
Yes, yes that is the question what kind of code would do that?
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

ausdigi

  • Jr. Member
  • **
  • Posts: 52
  • Programmer
    • RNR
Re: Keep user from moving off current record
« Reply #7 on: April 14, 2015, 03:00:04 am »
taazz, I feel your pain. :)

Calling Abort raises an exception and is a back-door way of aborting further event processing up the chain. Unfortunately this relies on code for the controls not handling exceptions, which Lazarus obviously does differently for this control than Delphi. Just because it worked for your version of Delphi also doesn't mean it would work in future versions as it was always a presumptuous hack.

I don't do DB type programming so don't encounter this issue but I noticed that the TDBCustomNavigator has a protected Buttons property. You could perhaps create your own descendant that allows access to these buttons and disables them based on state? You wouldn't have to install a new component as you just need to cast it to your type whenever needed to access the buttons (as long as you don't create new member fields). This may not be ideal but something that occurred to me and may help. Disabling the buttons looks better too as the user knows under certain situations that some buttons can't be clicked.
Win10/64: CT 5.7 32&64

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Keep user from moving off current record
« Reply #8 on: April 14, 2015, 04:12:35 am »
taazz, I feel your pain. :)

Calling Abort raises an exception and is a back-door way of aborting further event processing up the chain. Unfortunately this relies on code for the controls not handling exceptions, which Lazarus obviously does differently for this control than Delphi. Just because it worked for your version of Delphi also doesn't mean it would work in future versions as it was always a presumptuous hack.

No, its not a hack (I really don't know what a "presumptuous hack" is) its by design haven't looked to close to be 100% sure but I think the main differences between lazarus and delphi is when the events are raised. From the observed behavior I would say that in delphi the event is raised before the internal cursor moves to the next record while in lazarus after the cursor was moved to the next record. Both are valid options it just makes it a bit more user friendly the delphi way. I doubt that delphi or lazarus handle the by design silent exception EAbort that the abort function raises anywhere else than the application exeception handler.

I don't do DB type programming so don't encounter this issue but I noticed that the TDBCustomNavigator has a protected Buttons property. You could perhaps create your own descendant that allows access to these buttons and disables them based on state? You wouldn't have to install a new component as you just need to cast it to your type whenever needed to access the buttons (as long as you don't create new member fields). This may not be ideal but something that occurred to me and may help. Disabling the buttons looks better too as the user knows under certain situations that some buttons can't be clicked.

No, again the events are for the dataset  what happens if for some reason the dataset is moved to the next record outside the TDBCustomNavigator by lets say scrolling a TDBGRid to the next record then what create a new dbgrid  as well? No the solution should be to either write a custom dataset descendant where he will overwrite this behavior making it delphi compatible or looking around if there is an other event to be used which I assume he already did.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

mangakissa

  • Hero Member
  • *****
  • Posts: 1131
Re: Keep user from moving off current record
« Reply #9 on: April 14, 2015, 09:35:30 am »
@dodgebros,

This code doesn't make any sense. You only create an exeption to give the users the message that they moving to a another record when they are inserting/modifying. The changed fields are still saved.
This behaviour can't be fixed by a dbnavigator. DBGrid has his own way to work with records. DBNavigator is only visualize your needs.
Quote
In Delphi I could use the folowing code to keep a user from moving off the record ( any changes they have made are automatically saved if they move off the record ) if  the Dataset was in dsEdit or dsInsert mode.
That's not true. Delphi and Lazarus/FPC has excactly the same behaviour of your code.
Lazarus 2.06 (64b) / FPC 3.0.4 / Windows 10
stucked on Delphi 10.3.1

dodgebros

  • Full Member
  • ***
  • Posts: 169
Re: Keep user from moving off current record
« Reply #10 on: April 14, 2015, 05:08:44 pm »
OK ... this code did in fact work in Delphi XE.  However, it doesn't work in Lazarus.  I changed the SysUtils.Abort to Exit but that doesn't work either.

So, how can I accomplish this?  I want the user to have to click a button to either save the record or click another button to cancel any changes made BEFORE they are allowed to move off the record by clicking on one of the navigation buttons OR by clicking on another record in the DBGrid OR by scrolling with the mouse wheel.

There must be a way to accomplish this in Lazarus. 

Thanks guys for trying to help,
TD
« Last Edit: April 14, 2015, 05:14:44 pm by dodgebros »

balazsszekely

  • Guest
Re: Keep user from moving off current record
« Reply #11 on: April 14, 2015, 08:44:47 pm »
The proper way to accomplish this is to implement an OnGetCanScroll event by modifying db.pas and dataset.inc. OnGetCanScroll is called right before dataset scroll. It has two parameters: OnGetCanScroll(Dataset: TDataset; var CanScroll: Boolean). If CanScroll is false the whole scrolling process is aborted.
So you should create a patch first, after is committed to trunk:
Code: [Select]
procedure TForm1.qMainOnGetCanScroll(DataSet: TDataSet; var CanScroll: Boolean);
begin
  CanScroll := not (Dataset.State in [dsEdit, dsInsert]);
end;
Without OnGetCanScroll , I'm afraid is almost impossible to implement that kind of behaviour.  You can try to implement a workaround with DataSet.DisableControls and DataSet.BookMark.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Keep user from moving off current record
« Reply #12 on: April 14, 2015, 10:23:29 pm »
all datasets already have a beforescroll event.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

balazsszekely

  • Guest
Re: Keep user from moving off current record
« Reply #13 on: April 15, 2015, 05:37:14 am »
Code: [Select]
all datasets already have a beforescroll event.Yes, there is a beforescroll event, but when is fired, the whole scrolling process is already set in motion. There is no way to stop it. That's why the OP should implement a OnGetCanScroll or CanScroll if you like, which can prevent the scroll, as a described in my previous post. Many database components(IBObjects for example) does exactly the same thing.

rvk

  • Hero Member
  • *****
  • Posts: 6814
Re: Keep user from moving off current record
« Reply #14 on: April 15, 2015, 10:20:49 am »
Something like this works in Delphi XE. A class helper which sets the FEOF and FBOF to true. Doing so prevents the MoveBy-function to do its work.

But somehow FPC doesn't allow access to a private-variable when the base-class isn't defined in the same unit (which Delphi does).
Is that a bug or intended behavior ??

(I didn't test what other implications this could have but it does stop the dataset from moving)
Code: [Select]
type
  TMyDataset = class helper for TDataset
  public
    procedure StopMoving;
    procedure AllowMoving;
  end;

procedure TMyDataset.StopMoving;
begin
  Self.FEOF := true; // access to private variable. Doesn't work in Lazarus
  Self.FBOF := true;
end;

procedure TMyDataset.AllowMoving;
begin
  Self.FEOF := false;
  Self.FBOF := false;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  IBQuery1.StopMoving;
end;

 

TinyPortal © 2005-2018