70
1 Extreme Xbasic Dr. Peter Wayne

1 Extreme Xbasic Dr. Peter Wayne. 2 Elements of a programming language variables assignment flow control

Embed Size (px)

Citation preview

1

Extreme Xbasic

Dr. Peter Wayne

2

Elements of a programming language

• variables

• assignment

• flow control

3

Variables - Simple Types

• character

• date

• logical

• numeric

4

Variable Declaration and Assignment

Explicit:

dim myname as c

myname="peter"

Implicit: hisname="selwyn"

5

Character Variablesdim fname as c

dim lname as c

dim myname as c

fname="peter"

lname="wayne"

myname=fname + " " + lname

? myname= "peter wayne"

6

Date Variables

dim today as d

today=date()

? today

= {02/15/2002}

7

Logical Variables

dim istrue as l

istrue="alpha">"microsoft"

? istrue

= .F.

8

Variables - numeric

dim x as n

x=12

y=2*x ' * is the multiplication operator

? y

= 24.000000

9

Assignment is Not Algebra

x=12

x=x*2

10

Variables - Complex

• “any” or variant

• pointer

• blob

• time

• function

• collection

11

“Any” variable typedim anyvar as A anyvar=12? anyvar= 12.000000

anyvar=date()? anyvar= {02/15/2002}

anyvar="today is "+anyvar? anyvar= "today is 02/15/2002"

12

Pointer variables

• tables, indexes, queries

• fields

• layout objects (forms, buttons, etc.)

• chunks of memory

13

Pointer Example: Table Pointer

14

Properties and Methods of Table Pointers

15

Pointer to Form

16

17

18

19

Here all properties are restricted except for changing the record:

20

Navigation and querying is prevented by the property settings.

21

Flow Control

• if (something) then…(else)...end if

• for…next

• while…end while

• select…case…end while

• end

• on error goto…resume

• *for_each() (advanced)

22

if…end if

x=1

for i=1 to 5

x=x*2

if x>10 then

exit for

end if

next i

ui_msg_box("x is",str(x))

23

For…Next

x=1

for i=1 to 5

x=x*2

next

? x

= 32.000000

24

User Defined FunctionsFUNCTION reverse AS C (input AS C )

dim i as n

dim length as n

length=len(input)

output=""

for i=length to 1 step -1

output=output + substr(input,i,1)

next i

reverse=output

end function

25

26

Creating a New Script

27

Structure of MyCheckbook.dbf

28

Creating a script

29

t=table.open("mycheckbook")balance=0t.index_primary_put("date")t.fetch_first()while .not. t.fetch_eof()

amt=if(t.type$"DIE",t.amount,-t.amount)balance=balance+amtt.fetch_next()

end whilet.close()ui_msg_box("balance is",str(balance,10,2))

Calculate current checkbook balance

Can you follow this script?

30

t=table.open("mycheckbook")credits=0query.filter="type$'DIE'"query.order=""query.options=""qry=t.query_create()t.fetch_first()while .not. t.fetch_eof()

credits=credits+t.amountt.fetch_next()

end whileqry.drop()t.close()ui_msg_box("total credits is",str(credits,10,2))

Applying a Query to a Table

31

Events

• Form, Browse, and Object events

• Record and Field Events

32

Form, Browse, Object Events

• Simplest Example: OnPush event for button

• The OnPush event for a button is triggered when the button is pressed.

• You can attach Xbasic code to any event for any object. Of course, the code may not make sense if you attach it to the wrong event!

33

Sample OnPush event script

• This next form starts with multiple restrictions. The "Allow Edits" button removes the restrictions.

• An if..then..else..end if construct is used to toggle the form in and out of editing mode.

34

35

Right-click on the object, then choose Events to see a list of the events defined for the type of object. Different objects have different events. Buttons and hotspots have OnPush events:

36

if this.text="Allow edits" thentopparent.Restrict_change = .f.topparent.Restrict_delete = .f.topparent.Restrict_enter = .f.topparent:Browse1.Browse.Readonly = .f.this.text="Prevent edits"this.fill.forecolor="Red"

elsetopparent.Restrict_change = .t.topparent.Restrict_delete = .t.topparent.Restrict_enter = .t.topparent:Browse1.Browse.Readonly = .t.this.text="Allow edits"this.fill.forecolor="Bright Green"

end if

OnPush event script for "Allow edits" button. "this" refers to the object containing the script, and "topparent" refers to the form containing the button.

37

Events

• With few exceptions, there are 2 basic event types:

• CanXXX events, whose scripts can be used to deny permission for an event, using cancel()

• OnXXX events, whose scripts fire after the named event occurs

• Examples: CanSave and OnSave form level events

38

Example of CanXXX event: CanExit

39

40

Pressing the Close button produces this:

41

By contrast, OnExit event:

42

Sometimes events behave in ways that are not immediately obvious.

Button OnPush code:

parent.close()

This bypasses the CanExit event, but the OnExit event still fires.

43

Xbasic can work on tables or objects, with similar results.

Example: Program a "mark" button for a set-based form that marks either the active child record or the parent and all its children, depending on what has focus before the delete button is pressed.

We can use the form's .active_prev() method to determine what had focus before "mark" is pressed.

44

name_of_active=parent.active_prev()if name_of_active="Browse1" then do_it=ui_msg_box("Confirm","Mark single detail item?",\ UI_YES_NO+UI_SECOND_BUTTON_DEFAULT)else do_it=ui_msg_box("Confirm","Mark entire transaction and all detail items?",\ UI_YES_NO+UI_SECOND_BUTTON_DEFAULT) end ifif do_it=UI_NO_SELECTED then endend if

First, verify that the user wants to perform the marking operation.

45

if name_of_active="Browse1" then browse1.mark_record()else lastrec=0 browse1.fetch_first() rec=table.current(2).recno() ' record number of the first browse record

while rec<>lastrec lastrec=rec

browse1.mark_record() browse1.fetch_next() rec=table.current(2).recno() end while parent.mark_record()end if

And then perform the mark, in this case with form-level methods:

46

t2=table.current(2)t1=table.current(1)if name_of_active="Browse1" then

t2.change_begin() t2.mark()t2.change_end(.t.)

else t2.fetch_first() while .not. t2.fetch_eof() t2.change_begin() t2.mark() t2.change_end(.t.) t2.fetch_next() end while t1.change_begin()

t1.mark() t1.change_end(.t.)end if

Alternatively, one can mark the record at the

table level using Table-Level Methods

47

Form-level vs Table-Level

• Form-level methods:– Imitate a live user– Field rules are respected

• Table-level methods– Field rules are overridden

48

Example of field rule• CanChangeRecord event for table:

49

t=table.get("mycheckbook")status=t.statusif status="R" then

cancel()ui_msg_box("Error",\

"Changes not allowed to reconciled transactions!")else

dim shared old_date as d old_date=t.date

end if

CanChangeRecord event for mycheckdetail.dbf

50

Here is a reconciled transaction (status="R"):

51

Pressing "Mark at form level" produces this error:

52

Pressing "Mark at table level" generates no error, because

The Xbasic commands to mark the record override the Xbasic in the CanChangeRecord event.

There is a drawback to table-level methods:

To show the changes on the form after table-level changes, you must either press {F5} or issue a

parent.resynch()

53

Deleting a sequence of records

Deleted records disappear from the table's index. They require special handling. This is the code we used for marking the child records:

while .not. t2.fetch_eof()

t2.change_begin()

t2.mark()

t2.change_end()

t2.fetch_next()

end while

54

while .not. t2.fetch_eof()

t2.change_begin()

t2.delete()

t2.change_end()

t2.fetch_first()

end while

In Deleting, we change the fetch_next() to fetch_first(). Do you see why?

55

Controlling the User through Xbasic

1) Keep the form in read-only mode until the user explicitly requests to change or enter a new record.

2) Do not allow the user to make deletions with Ctrl-D. If deletions are rare, do not allow them at all--only let a supervisor make deletions.

3) If the child record has too many fields to fit comfortably on a browse, open a new form for the child record. Disable "zoom to record" in the menu--it lets the user pick the default form for the child record.

56

1) Keep the form in read-only mode when it starts up.

OnInit event for a typical form:

topparent.Restrict_change = .t.topparent.Restrict_delete = .t.topparent.Restrict_enter = .t.topparent:Browse1.Browse.Readonly = .t.

57

Use an Allow Edits button to put form in read-write mode (we've seen this one before).

if this.text="Allow edits" thentopparent.Restrict_change = .f.topparent.Restrict_delete = .f.topparent.Restrict_enter = .f.topparent:Browse1.Browse.Readonly = .f.this.text="Prevent edits"this.fill.forecolor="Red"

elsetopparent.Restrict_change = .t.topparent.Restrict_delete = .t.topparent.Restrict_enter = .t.topparent:Browse1.Browse.Readonly = .t.this.text="Allow edits"this.fill.forecolor="Bright Green"

end if

58

Write code for the OnRowDblClick event for the browse to open a form specifically for editing and viewing detail records.f=form.load("detail form")f:Tables:mycheckdetail.filter_expression="recno()="+alltrim(str(table.current(2).recno()))f:Tables:mycheckdetail.order_expression=""f:Tables:mycheckdetail.query()t=table.current()if t.status="R" then f.restrict_enter=.t. f.restrict_change=.t. f.restrict_delete=.t.end iff.show()f.activate()parent.hide()

59

The "detail form" comes up with the fields in form view, rather than browse view:

60

The Close button on the detail form makes the calling form visible again:

f=obj("Checkbook Entry2")if is_object(f) then f.show() f.activate()else

f=form.load("Checkbook Entry2")f:Tables:mycheckbook.filter_expression="transactionid='"+\table.current().transactionid+"'"f:Tables:mycheckbook.order_expression=""f:Tables:mycheckbook.query()f.show()f.activate()

end ifparent.close()

61

Problem: Controlling and Coordinating a New Detail Record

62

if table.current().status="R" then ui_msg_box("Error","This transaction already reconciled.") endend ift2=table.open("mycheckdetail")t2.enter_begin()

t2.Transactionid=table.current().transactionidt2.enter_end(.t.)rec=t2.recno()t2.close()parent.refresh_layout()' now to open the detail form

"New Detail" button OnPush Script

63

f=form.load("detail form")f:Tables:mycheckdetail.filter_expression="recno()="+\alltrim(str(rec))f:Tables:mycheckdetail.order_expression=""f:Tables:mycheckdetail.query()f.show()f.activate()parent.hide()

Open the detail form, synchronized to the new record

64

if parent.mode_get()<>"VIEW" then parent.commit()end iff=obj("Checkbook Entry2")(continued next screen)

Detail Form's Close button script

65

if is_object(f) then' requery both tables in the form to display the newly entered detailf:Tables:mycheckdetail.filter_expression="transactionid='"+\table.current().transactionid+"'" f:Tables:mycheckdetail.order_expression="" f:Tables:mycheckdetail.query() f:Tables:mycheckbook.filter_expression="transactionid='"+\table.current().transactionid+"'" f:Tables:mycheckbook.order_expression="" f:Tables:mycheckbook.query()' remove the restriction to allow navigation

f:Tables:mycheckbook.filter_expression="" f:Tables:mycheckbook.order_expression="" f:Tables:mycheckbook.query() f.show() f.activate()end ifparent.close()

Continuation of Close button's script

66

Scripts to modify scripts

' add password to all scripts in database

script_name = a5.script_enum("")while script_name<>""

script_text=script_load(script_name,"shazaam")if .not. ("'password shazaam"$script_text) then script_text="'password shazaam"+\ chr(13)+chr(10)+script_text script_save(script_name,script_text)end ifscript_name=a5.script_enum(script_name)

end while

67

password_len=len("'password shazaam")script_name = a5.script_enum("")

while script_name<>""script_text=script_load(script_name,"shazaam")if left(script_text,password_len)="'password shazaam" then

script_text_len=len(script_text) script_text=right(script_text,\

script_text_len-password_len-2) script_save(script_name,script_text,"shazaam")end ifscript_name=a5.script_enum(script_name)

end while

Remove the password

68

Scripts to modify forms

dim frm as cdim onflycode as cdim onleavecode as c

onflycode=<<%code%this.fill.forecolor="red"%code%

onleavecode=<<%code%this.fill.forecolor="white"%code%

69

function design as v(frm as c, oncode as c, onleave as c)dim nchildren as ndim i as ndim f as pdim o as pf=form.load(frm)f.command("SYSTEM_DESIGN")nchildren=f.children()for i=1 to nchildren

o=f.child(i)if o.class()="type-in field" then o.code.OnFlyover=oncode o.code.OnFlyoverLeave=onleaveend if

next if.command("FILE_SAVE")f.close()end function

70

forms_all=a5.form_enum()xbasic_asynchronous() 'forces each command to complete in order

code=*for_each(frm,"design("+quote(frm)+",onflycode,onleavecode)",\forms_all)

result=evaluate_template(code)if result<>"" then

ui_msg_box("Error in evaluate_template",result)end if