Recent

Author Topic: onkeydown event question  (Read 30810 times)

wpflum

  • Sr. Member
  • ****
  • Posts: 287
Re: onkeydown event question
« Reply #15 on: September 03, 2010, 07:52:49 pm »
Ok, now I'm wondering if something I've been seeing isn't a bug in Free Pascal or Lazarus.

Here is the code I'm using.
-----------------------------------------------------------------------------------------
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  ComCtrls, StdCtrls,Functions;

type

  { TForm1 }

  TForm1 = class(TForm)
    Edit1: TEdit;
    PageControl1: TPageControl;
    TabSheet1: TTabSheet;
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);

  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{ TForm1 }



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

Form1.Edit1.Caption := 'HI';
MyKeyPress(Sender,Key,Shift);
end;

initialization
  {$I unit1.lrs}

end.
---------------------------------------------------------------------------------

unit Functions;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils,Dialogs,Forms,Graphics;

Function MyKeyPress(Sender: TObject; var Key: Word; Shift: TShiftState):Boolean;

implementation
uses unit1;
Function MyKeyPress(Sender: TObject; var Key: Word; Shift: TShiftState):Boolean;


begin

if Sender is TForm then
   begin
   showmessage(tform(sender).ActiveControl.Name ) ;
   showmessage(tform(sender).ActiveControl.Caption);
   showmessage(tform(Sender).ControlByName('Edit1').Caption);
   end;

end;

end.
                         
--------------------------------------------------------------------------------------

This works for the first 2 showmessages.  If you run this, click on the edit box and press a key you'll see the name of the current control shown, Edit1, in the popup, press ok and you'll see another popup with the word 'HI' in it.  press ok again and you get a

'Project project1 raised exception class 'External: SIGSEGV'.

Seems like the info is there in the TFORM object but when I try to access it by name the entire program goes belly up.  I think I can get away with using just the ActiveControl but just for the record I'd like to know why it crashes??
                         

mas steindorff

  • Hero Member
  • *****
  • Posts: 555
Re: onkeydown event question
« Reply #16 on: September 03, 2010, 08:12:51 pm »
you may be right about the bug.  But It depends on how you are capturing the key down.  I've not read your code but the key down can be grabbed at the form level or the component level.

I've always accessed "Sender" as one of the of the controls that live on the form, not the form itself.  when I need to access the panel/form the control lives on, then I grab the controls' parent (like mypanel := sender.Gettopparent if my memory is correct)

look at the tedit inheritance at
http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/tedit.html

and then the Tform at
http://lazarus-ccr.sourceforge.net/docs/lcl/forms/tform.html

you can see they share some Tcontrol and other lower elements
windows 10 &11, Ubuntu 21+ IDE 3.4 general releases

wpflum

  • Sr. Member
  • ****
  • Posts: 287
Re: onkeydown event question
« Reply #17 on: September 03, 2010, 08:24:58 pm »
I'm grabbing the key press at form level since in my final code I have to grab cursor keys as well and the only way I've seen to do that is at form level.   

I'm leaning more toward bug but I'm trying to see if I can 'find' the control by other means like FindComponent which seems partially work but I still can't retrieve the contents of the tedit but I don't get the crash.

The Sender being sent by the form keydown action is the entire TForm, I've checked this by adding the 'if Sender is TForm' statement and watching the code drop into it in single step mode. 

I think my brain is swelling  %)

wpflum

  • Sr. Member
  • ****
  • Posts: 287
Re: onkeydown event question
« Reply #18 on: September 03, 2010, 09:04:30 pm »
Ok, exactly what DOES the ControlByName do??  I thought you could use that to get a control on a form like

Form1.ControlByName('Edit1').Text := 'Hi';

But if I try that I get that there is no member Text.

If I use (Form1.ControlByName('Edit1') as TEdit).Text  I get the same External: SIGSEGV I was getting in the Function but this is being used on the main form.

The good news is that if I use:

(tform(sender).FindComponent('Edit1') as TEdit).Text := 'BYE';

I can read and write to the TEdit control on the form through the TObject sent to the function.   

Ow, I think my brain is trying to escape  :o

Maybe I can get on with the rest of the code now..........

mas steindorff

  • Hero Member
  • *****
  • Posts: 555
Re: onkeydown event question
« Reply #19 on: September 03, 2010, 09:14:50 pm »
I can not fine ControlByName in my docs and a search on the net show one comment that it only work on the mac (2008)

I think you are looking for form.components[] and form.componentCount so you can scan/check all of the controls on the form.

windows 10 &11, Ubuntu 21+ IDE 3.4 general releases

wpflum

  • Sr. Member
  • ****
  • Posts: 287
Re: onkeydown event question
« Reply #20 on: September 03, 2010, 09:26:53 pm »
I'm not sure where I came up with it, I might have even seen it by just scrolling down the list after a putting a dot after a form name.  :)

At least I know that I was on the right track, I just went back to the original program I was working on and moved a PageControl incrementing procedure to the new KeyPress function and it worked like a charm.

(tform(Sender).FindComponent('Pagecontrol1') as TPageControl).ActivePageIndex := (tform(Sender).FindComponent('Pagecontrol1') as TPageControl).ActivePageIndex + 1;


A bit long winded, I might look into defining a few things so I can shrink the character count down a bit to be more concise.

But it works  ;D

fabienwang

  • Sr. Member
  • ****
  • Posts: 449
  • Lazarus is the best
    • My blog
Re: onkeydown event question
« Reply #21 on: September 03, 2010, 10:12:27 pm »
your code worked well if you just had your MyKeyPress function in the first unit.
I'm using Arch Linux.
Known for: CPickSniff, OpenGrabby
Contributed to: LazPaint

theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1932
Re: onkeydown event question
« Reply #22 on: September 03, 2010, 10:20:50 pm »
(tform(Sender).FindComponent('Pagecontrol1') as TPageControl).ActivePageIndex := (tform(Sender).FindComponent('Pagecontrol1') as TPageControl).ActivePageIndex + 1;

I really don't understand why you insist in doing it in such a complicated and error prone way.

Why not:
Code: Pascal  [Select][+][-]
  1. uses Unit1;
  2.  
  3. Form1.PageControl1.ActivePageIndex:=...
  4.  

There is nothing sloppy about this. Please think again.
Your code is for Form1 anyway. So why not reference it directly?

wpflum

  • Sr. Member
  • ****
  • Posts: 287
Re: onkeydown event question
« Reply #23 on: September 05, 2010, 07:53:12 pm »
Why do you consider it error prone?? 

I want a main code unit that calls or references sub code pages for functions or procedures and I do not want extraneous circular references.  Heck I think I figured out a way to embed my global variables in a class so I can have then all declared on the main page and then pass them as an object to functions and sub procedures.  To me global variables and circular referencing are sloppy code, I repeat, to ME global variables and circular referencing are sloppy coding, it's just the way I think.  Now if I couldn't have done this the way I wanted I might have 'cheated' and put the code on the main page.

Here is a short outline of how I like to see code, so you will see how I like to program.

I. Main Program
    1. Initialize all
        a. clear all variables
        b. set defaults
        c. read in settings file
    2. Clear Screen
    3. Display Screen
    4. Watch for Keypress
        a.check keypress
      1. verify input type
                2. verify valid entry
                3. verify additional info base on entry
         b. move to correct next field based on entry
    5.  Do totals
         a. verify all data
    6.  Print report
    7.  Save Data to external device
    8.  Check for new entry or exit
    9.  Exit

To me there shouldn't be much in the way of logic or coding in the main program/form.  Think root system and not Tree branches, I have the main trunk of the tree and it's held up by smaller and smaller branching roots.  What I don't want is a sucker root comming off the main trunk and hooking into the roots, circular reference, everything should be directed through the root structure from the top down.  This way I know exactly what is going were and if I have problems I can narrow it down rather quickly to a specific root.  Like I said this is 'MY' idea of programming, YOUR mileage may vary. :)   

wpflum

  • Sr. Member
  • ****
  • Posts: 287
Re: onkeydown event question
« Reply #24 on: September 05, 2010, 08:00:36 pm »
One other thing, although in this simple program I only had one form or screen I might have a main form calling a dozen or more screens all of which would use the same keypress routines.  If I have it on the form I'm using I'd have to replicate on every form I use, if I use a generic keypress function and pass the form as an object like I'm doing then all I need to do is have one set or on function for as many forms as I wish and just have the routine determine from the form itself what is has to do.  Believe me nothing sucks worse than being most of the way through a program and realizing that you should add something to a similar routine and having to go through many many forms to add in the code, been there done that and have to thinning hair to prove it. :)

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: onkeydown event question
« Reply #25 on: September 06, 2010, 02:36:30 pm »
well you have an idea of things the program shoul do:
Here is a short outline of how I like to see code, so you will see how I like to program.

I. Main Program
    1. Initialize all
        a. clear all variables
        b. set defaults
        c. read in settings file
    2. Clear Screen
    3. Display Screen
    4. Watch for Keypress
        a.check keypress
      1. verify input type
                2. verify valid entry
                3. verify additional info base on entry
         b. move to correct next field based on entry
    5.  Do totals
         a. verify all data
    6.  Print report
    7.  Save Data to external device
    8.  Check for new entry or exit
    9.  Exit
IMHO Ithink you should stop and start making a model of your program. And a good advise is:
   1- LET FORM ISSUES INSIDE THE FORM!!: if you change the form, you will have to do the same thing with the unit (believe me, it's a pain in the butt).
   2- IT'S BETTER TO CREATE A CLASS FOR DATA HANDLING: If you need to make complex (or simple) data validation put your data (for example "Item", "Price" "Quantity", etc.) in a class which validates input, integrity or what ever you think necessary (it can be done easilly in the property setter). Let's call it TDatilItem.
   3- IF NEEDED YOU CAN CONSTRUCT A COLLECTION OF YOUR CLASS: If you need to handle a set of your TDatailItem and a Dataset is not needed, then Construt a Collection class of your detail items (i would create a TObject descendant wit a TCollection property). and in the "Add" function you can do checks of DataItem in a context (if needed) like uniqueness, etc. if DataItem validation is TOO SIMPLE you can create a RECORD and a POINTER to that record to use it on the TList object.

wpflum

  • Sr. Member
  • ****
  • Posts: 287
Re: onkeydown event question
« Reply #26 on: September 07, 2010, 03:36:14 pm »
I do have a model of the program, its the original application :)
I'm working on mimicking a telnet session to a custom software server so the remote stores can do invoices on a pc instead of hand writing them if our data streams are down.

I understand the general idea of keeping the form code on the form but I'm talking about generic key handeling routines that will be the same for multiple forms, why duplicate them and take the chance that I miss a set if I have to change something.

The idea of creating a class for my data occurred to me a day or so ago but I haven't had the chance to delve into creating a class yet.  I should know today if I can do it in a way I like.  I would be a nice idea since then I can pass the class object between functions and procedures instead of having global variables and I could embed the validation procedures in it as well like you mentioned.

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: onkeydown event question
« Reply #27 on: September 07, 2010, 05:20:04 pm »
Well now it's clearer!!
I understand the general idea of keeping the form code on the form but I'm talking about generic key handeling routines that will be the same for multiple forms, why duplicate them and take the chance that I miss a set if I have to change something.
Can you tell us what you call "generic key handling routines"?

wpflum

  • Sr. Member
  • ****
  • Posts: 287
Re: onkeydown event question
« Reply #28 on: September 07, 2010, 05:35:46 pm »
I want the specific keys to do specific things on similar pages so I set up the function that handles the key press as a generic 'This is a tab key press do something' in the function keypress and then point any tab key presses on any form to that function.  Most of my keypress functions do multiple validations based on what field the tab was pressed in including validating all of the data on the current screen if the tab key is pressed at the end of the screen.  Since the validations are all similar in nature I can use one tab keypress function to handle as may screens as I need and if I need to make a modification on how a specific key is handled I can make the change on the function level and have it propagate through any form using keypress function. 

If I were doing a one off form/screen then I'd say that it would be easier to just keep the code on the form but since I expect to have multiple forms/screens I like my code in one place.  ;)

Here's a question about building a class..... how do I do it  :-[

Can you point me at a simple example or tutorial that can walk me through creating one with properties and functions??  I think I have the general idea of how but some of the specifics are getting by me.   %)

   

 

 

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: onkeydown event question
« Reply #29 on: September 07, 2010, 11:24:33 pm »
Well, you can do the following:

Utilitie's Unit:
Code: [Select]
{ TIP: Try to create general functions and procedures as if you plan to use them for different project. Believe me, it really helps to keep your code clean and easy to maintain. }

{ You can declare many diffrent functions like this one }
procedure MyKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState {if needed, you can add any extra parameters that you need to adjust the procedure execution});
begin
   // place your code here.
end;

Your form:
Code: [Select]

procedure TMyForm.GeneralKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
   MyKeyDown(Sender, Key, Shift);
end;


then you can assign the same event to as many components as you wish like mas steindorff said:
sender is a tobject.  tobject is a common base class that mostly all of the controls are derived from.  It only has basic properties as compared to the controls you use on the form like a tedit.  You can access the "advanced" eleaments of the control by casting (upgrading) the sender to the control with the "as" command.

... but the problem is that I'm dealing with forms that might have 20 or 30 tedit controls so I'd have to have a lot of code on the form page to handle it.

you can assign all of the tedit key down events to the same function.  then all you need is one function.  you can sort out which one is the active one by (simple) looking at the sender's tag or you can dig into the sender's as tedit. properties like top,left or parent to make your selection.


This is a lot safer than assigning to each component an event handler at runtime (to do so you would have to create an object with your custom method in it, create it and then assign the procedure address to the event for each component, and clean everything before destroy your app if any thing goes wrong .... then bad hapens).

Sorry, I couldn't find a direct link for creating a class  :-[, but, as Leledumbo would say: "Check our Holly Wiki" http://www.freepascal.org/docs.var it's a good place to start.

or you can ask for ObjectPascal tutorials over the net there are plenty of them.

 

TinyPortal © 2005-2018