การสร้างฟอร์ม VFOX

ฟอร์มเป็นตัวกลางที่สำคัญตัวหนึ่งที่จะทำการติดต่อระหว่างผู้ใช้งานกับข้อมูลต่างๆ ไม่ว่าจะเป็นการป้อนข้อมูล การแสดงข้อมูล หรือการแสดงข่าวสารต่างๆที่เกิดขึ้นในระบบงาน การที่เราจะทำการสร้างฟอร์มขึ้นมาสักฟอร์มหนึ่งนั้นมันไม่ได้ยากอะไรหรอก แต่การที่จะควบคุมการทำงานของฟอร์มนั้นมันไม่ได้ง่ายสักเท่าใด คุณจะคุมการทำงานของฟอร์มได้อย่างไรนั้นก็ขึ้นอยู่กับการออกแบบ และการจิตนาการของท่านทั้งหลาย ถ้าคุณเข้าใจหลักการและวิธีการที่ผมจะแนะนำในบทนี้แล้ว ก็คิดว่าจะเป็นแนวทางในการออกแบบและสร้างฟอร์มของคุณต่อๆไป
ลักษณะของฟอร์มในการป้อนข้อมูลโดยทั่วๆไปแล้วจะมีอยู่ 2 แบบคือ
1.ฟอร์มการป้อนข้อมูลทีละเรคคอร์ด เช่น ฟอร์มที่ใช้ป้อนข้อมูล ลูกค้า, สินค้า , พนักงานขาย เป็นต้น
2.ฟอร์มการป้อนข้อมูลที่มีความสัมพันธ์แบบหนึ่งต่อหลายๆเรคคอร์ด เช่น ฟอร์มที่ใช้ป้อนข้อมูลใบส่งสินค้า เป็นต้น

การสร้างฟอร์มป้อนข้อมูลทีละเรคคอร์
อย่างที่กล่าวไว้ข้างต้นว่า การสร้างฟอร์มนั้นไม่ยากแต่การควบคุมการทำงานนั้นไม่ได้ง่ายเหมือนกับการสร้างฟอร์ม ก่อนอื่นเราต้องนึกก่อนว่าฟอร์มที่เราจะสร้างต้องการให้มีลัษณะเป็นอย่างไร และต้องคำนึงถึงข้อผิดพลาดที่จะเกิดจากการป้อนข้อมูล เพื่อที่จะได้ทำการควบคุมข้อผิดพลาดเหล่านั้น ซึ่งสิ่งหลังนี้แหละจะบ่งบอกถึงความสามารถในการเขียนโปรแกรมของคุณ
เรามาลองทำฟอร์มป้อนข้อมูล สินค้ากันก่อน
หลักการทำฟอร์มป้อนข้อมูลจะประกอบไปด้วย 4 ส่วนใหญ่ๆ (ของผู้เขียนเอง)
ส่วนแรกเป็นส่วนของ ฟอร์มการป้อนข้อมูล
ส่วนที่สองเป็นส่วนของปุ่มควบคุม(toolbar) ในบทนี้ผมไม่ได้แสดงวีธีสร้างไว้ ให้ไปดูในหัวข้อง Visual Class Libary
ส่วนที่สามเป็นส่วนของเมธอตคำสั่งในการควบคุมการทำงานของฟอร์ม
ส่วนที่สี่เป็นส่วนของการตรวจสอบความผิดพลาดในการป้อนข้อมูล(check error)
เรามาเริ่มกันเลย

ส่วนของฟอร์มการป้อนข้อมูล
1. ที่ command windows ป้อนคำสั่ง
SET DEFA TO C:\MYAPP
MODIFY COMMAND MYPROJECT
(โปรเจ็ก myproject คุณสามารถ download โปรแกรมตัวอย่างได้ที่ เริ่มสร้างระบบงาน)
2. คลิ๊กที่แท็ป Docs แล้วเลือก New จากนั้นให้ทำการคลิ๊กที่ New Form
3. กำหนด form properites โดยคลิ๊กเมาส์ปุ่มขวา แล้วเลือก properties กำหนดคุณสมบัติของฟอร์ม ดังนี้
Caption = แฟ้มข้อมูลสินค้า
Icon = C:\myapp\bmp\thai.ico
MaxButton = .F.
MinButton = .F.
Top = 60
4. ที่ Form Control คลิ๊กที่คอนโทล View Class (c7003.JPG (956 bytes)) เพื่อนำ Sub-Class MyToolbar ที่ผมได้สร้างเตรียมไว้ให้นำมาไว้ใน ฟอร์ม ของเรา(วิธีการสร้าง Class ใหม่ ดูที่ Visual Class Library) แล้วคลิ๊กที่ Add จากนั้นให้เลือก ไฟล์ mytoolbar แล้วคลิ๊กที่ปุ่ม Open จากนั้นให้คลิ๊กที่ ปุ่ม toolbar1 แล้วมาคลิ๊กที่ฟอร์ม แล้วตอบ YES ทีนี้ในฟอร์มของคุณก็จะมีปุ่มทูลบาร์ปรากฎอยู่ ซึ่งเรียกรวมทั้งทูลบาร์ และฟอร์มว่า เป็น ฟอร์มเซ็ต(form set)

แนะนำ คุณสามารถเพิ่ม หรือลบฟอร์ม ในฟอร์มเซ็ตได้โดยการเลือกเมนู Form แล้วเลือก Add New Form เพื่อทำการเพิ่มฟอร์ม หรือ Remove Form เพื่อทำการลบ ฟอร์ม หรือ Visual Class Library

เมื่อคุณต้องการให้ Form Control กลับมาเป็นปรกติของ Visual FoxPro ก็ให้คลิ๊กที่ c7003.JPG (956 bytes) แล้วเลือก Standard
5. ให้ทำการคลิ๊กเมาส์ปุ่มขวาที่ ฟอร์ม แล้วเลือก Data Environment… จากนั้นให้ทำการเลือก แฟ้ม product แล้วคลิ๊กปุ่ม Add เมื่อเลือกเสร็จแล้วให้คลิ๊กที่ปุ่ม Close
6. ที่แฟ้ม product ให้คลิ๊กเมาส์ปุ่มขวา แล้วเลือก Properties แล้วกำหนดค่าดังนี้
BufferModeOverried = 3
Order = prod_id

BufferModeOveried   จะเป็นการกำหนดการป้องกันการป้อนข้อมูลในตาราง(table)   ซึ่งการกระทำนั้นจะทำการโอนข้อมูลของคุณเก็บไว้ที่หน่วยความจำของคอมพิวเตอร์ก่อน เมื่อได้กระทำกับข้อมูลใน บัฟเฟอร์เรียบร้อยแล้วเราจะใช้คำสั่ง TABLEUPDATE() ในการ update ขอมูลลงสู่ตารางอีกที หรือถ้าต้องการยกเลิกการเปลี่ยนแปลงให้ใช้คำสั่ง TABLEREVERT() ในการกำหนด บัฟเฟอร์นั้นเราจำเป็นต้องคำนึงถึงฟอร์มที่ใช้ในการป้อนข้อมูลด้วยว่าควรจะกำหนดบับเฟอร์เป็นแบบใด ดังต่อไปนี้
1     ไม่มีการกำหนดบัฟเฟอร์
2     เป็นการกำหนดบัฟเฟอร์เพื่อป้องกันเรคคอร์ที่ทำงานอยู่ ณ.ขณะนั้นไม่ให้ผู้อื่นเข้ามาใช้งานได้อีก(lock record) จนกว่าเรคคอร์นั้นจะถูกปล่อยออกมา(unlock record)
3     เป็นการกำหนดบัฟเฟอร์เพื่อป้องกันเรคคอร์ ที่ทำงานอยู่ไม่ให้ผู้อื่นเข้ามาใช้งานเฉพาะตอนที่จะ update ข้อมูล
4     เป็นการกำหนดบัฟเฟอร์เพื่อป้องกันตาราง จนกว่าตารางนั้นจะถูกปล่อยออกมา(unlock record)
5     เป็นการกำหนดบัฟเฟอร์เพื่อป้องกันตาราง เฉพาะตอนที่จะ update

ส่วนของปุ่มควบคุม
5. ที่ Form Control คลิ๊กที่คอนโทล View Class (c7003.JPG (956 bytes)) เพื่อนำ Sub-Class MyControl ที่ผมได้สร้างเตรียมไว้ให้นำมาไว้ใน ฟอร์มแล้วคลิ๊กที่ Add จากนั้นให้เลือก ไฟล์ mycontrol แล้วคลิ๊กที่ปุ่ม Open
แล้วทำการสร้างฟอร์มตามภาพด้านล่าง
c9301.gif (7484 bytes)

กำหนด Properties ของ คอนโทรแต่ละตัวดังนี้
Mtextbox1
ControlSource = Product.Prod_id
InputMark = XXXXX
Mtextbox2
ControlSource = Product.Name
Mtextbox3
ControlSource = Product.Um
InputMark = XXXXXXXXXX
Mtextbox4
Alignment = 1
ControlSource = Product.UnitPrice
InputMark = 9,999,999.99
Mtextbox5
Alignment = 1
ControlSource = Product.On_Hand
InputMark = 9,999,999
เอาละครับถึงตรงนี้ก็เสร็จสิ้นสำหรับการสร้างรูปแบบของฟอร์ม ง่ายไหมครับ แต่ยังไม่จบหรอกครับยังหรือวิธีการควบคุมฟอร์ม และการตรวจสอบการป้อนข้อมูล(check error)
เรามาดูกันว่าเราจะควบคุมให้ฟอร์มทำงานอย่างไรเมื่อเรากดปุ่มต่างๆบนทูลบาร์
6. ให้คุณทำการสร้าง method ขึ้นมาดังนี้
ที่เมนู Form เลือก New Method… พิมพ์ชื่อ เมธอตว่า msetenabledoff กดปุ่ม Add แล้วพิมพ์ชื่อ msetenabledon กดปุ่ม Add สองเมธอตที่สร้างนี้จะเป็นตัวกำหนดลักษณะของคอนโทรต่างๆว่าจะทำอย่างไร ให้กดปุ่ม Close เพื่อทำการปิดหน้าต่าง New Method
ที่เมนู Form เลือก New Property… พิมพ์ชื่อ property ว่า m_newrecord กดปุ่ม Add แล้วกดปุ่ม Close
7. ทำการป้อนคำสั่งในส่วนของเมธอต โดยทำการคลิ๊กขวาที่ฟอร์ม เลือก Properties ใน List box ให้เปลี่ยนจาก Form1 เป็น Formset1 ซึ่งจะอยู่เหนือ Form1 ขึ้นไปอีกบรรทัด จากนั้นคลิ๊กที่แท๊ป Method แล้วกำหนด เมธอต ดังนี้
ที่ msetenabledoff     ทำการป้อนคำสั่งดังนี้
_Screen.Activeform.Setall(“Enabled”,.F.,”MtextBox”)
ที่ msetenabledon     ทำการป้อนคำสั่งดังนี้
_Screen.Activeform.Setall(“Enabled”,.T.,”MtextBox”)
8. ต่อมากำหนด Properties ในส่วนของเมธอตของ toolbar1 ดังนี้
CmdEdit ที่ Click Event ป้อนคำสั่ง
thisformset.form1.setall(“Enabled”,.T.,”Mtextbox”)
thisformset.form1.Mtextbox1.Enabled=.F.
thisformset.setall(“Enabled”,.F.,”Mcommandbutton”)
thisformset.Toolbar1.cmdSave.Enabled=.T.
thisformset.Toolbar1.cmdCancel.Enabled=.T.
thisformset.form1.Mtextbox2.Setfocus
_SCREEN.ActiveForm.Refresh
คงจะสงสัยว่าทำไมผมให้ป้อนคำสั่งแต่ในเฉพาะ CmdEdit เท่านั้น เนื่องจากว่าคำสั่งต่างๆผมได้กำหนดไว้ใน Visual Class Library เรียบร้อยแล้ว ซึ่งการกำหนดคำสั่งต่างๆคุณสามารถเข้าไปดูได้ใน Visual Class Library
9. ให้กำหนด Properties ในส่วนของ Form1 ดังนี
Init Event ทำการป้อนคำสั่ง
thisform.SetAll(“Enabled”,.F. ,”Mtextbox”)
if recc() > 0
thisformset.toolbar1.cmdtop.click
endif
Activate Event ทำการป้อนคำสั่ง
thisformset.toolbar1.Visible = .T.
thisformset.form1.closable = .T.
thisformset.toolbar1.Dock(0)
select product
thisformset.form1.refresh
Deactivate Event ทำการป้อนคำสั่ง
thisformset.toolbar1.Visible = .F.

ส่วนของการตรวจสอบข้อผิดพลาด
เมื่อคุณได้ทำการสร้างฟอร์มมาถึง ณ. จุดนี้คุณก็สามารถที่จะ run ฟอร์มได้แล้ว แต่ฟอร์มของคุณนั้นก็ยังขาดส่วนที่สำคัญที่สุดไปอีกส่วนหนึ่งก็คือการตรวจสอบข้อผิดพลาด ก่อนที่เราจะทำการทำในส่วนนี้ผมขออธิบายวิธีการซักหน่อยก่อน
ในการเช็คข้อผิดพลาดนั้นสามารถทำได้หลายแบบหลายวิธี แต่ที่ผมจะกล่าวถึงนี้จะก็จะเป็นอีกวิธีการหนึ่งในการตรวจสอบขอผิดพลาดที่เกิดขึ้น ซึ่งจะแบ่งเป็น 2 ส่วนด้วยกันคือ
ส่วนของการเช็คข้อผิดพลาดทั้งหมด ก่อนการเก็บข้อมูล เนื่องจากว่าลัษณะการทำงานของ windows นั้นเราจะใช้ เมาส์เป็นหลักจึงทำให้ผู้ใช้งานสามารถไป ที่ใดก็ได้ใน windows บางครั้งอาจจะทำการกดปุ่ม บันทึกข้อมูลทั้งๆที่ไม่ได้ป้อนข้อมูลอะไรไว้เลย เราจึงทำเป็นที่จะต้องมีส่วนนี้เพื่อดักข้อผิดพลาดที่อาจเกิดขึ้น
ส่วนของการเช็คข้อผิดพลาดระหว่างการป้อนข้อมูล ในส่วนนี้จะเป็นการเช็คข้อผิดพลาดระหว่างการป้อนข้อมูล (invalid input) เช่นในกรณีที่ผู้ใช้ทำการป้อนรหัสสินค้าที่มีอยู่แล้วซ้ำเข้าไปอีก เราก็สามารถแจ้งเตือนให้ผู้ใช้ทราบได้ ณ. ขณะนั้นได้ทันที เป็นต้น
ส่วนของการเช็คข้อผิดพลาดทั้งหมด ก่อนการเก็บข้อมูล
10. ให้คุณทำการสร้าง method ขึ้นมาดังนี้
ที่เมนู Form เลือก New Method… พิมพ์ชื่อ เมธอตว่า mcheckerror กดปุ่ม Add แล้วกดปุ่ม Close เพื่อทำการปิดหน้าต่าง New Method
11. ทำการป้อนคำสั่งในส่วนของเมธอต mcheckerror โดยทำการคลิ๊กขวาที่ฟอร์ม เลือก Properties ใน List box ให้เปลี่ยนจาก Form1 เป็น Formset1 ซึ่งจะอยู่เหนือ Form1 ขึ้นไปอีกบรรทัด จากนั้นคลิ๊กที่แท๊ป Method แล้วป้อนคำสั่งในเมธอต mcheckerror   ดังนี้

With ThisFormset.FORM1
if ThisFormSet.m_newrecord
if empty(.mTextBox1.Value)
.mTextBox1.setfocus
messagebox(“กรุณาป้อนรหัสสินค้า”,288,””)
return .f.
endif
endif
if empty(.mTextBox2.Value)
.mTextBox2.setfocus
messagebox(“กรุณาป้อนชื่อสินค้า”,288,””)
return .f.
endif
Endwith
return .t.

ในส่วนของการตรวจสอบข้อผิดพลาดนี้จะเป็นการตรวจสอบทั้งฟอร์ม ซึ่งจะเกิดตอนที่ผู้ใช้งานจะทำการเก็บข้อมูล ถ้าต้องการที่จะเพิ่มการเช็คข้อมลูอย่างอื่นอีกคุณก็สามารถเพิ่มเข้าไปในส่วนนี้ได้เลย

ส่วนของการเช็คข้อผิดพลาดระหว่างการป้อนข้อมูล
ในการเช็คข้อผิดพลาดระหว่างการป้อนข้อมูลนั้นมีอยูหลายแบบอีกเหมือนกัน แต่ที่นิยมใช้กันมากก็คือ ใช้ในส่วนของ Valid Event

เคล็ดไม่ลับ   การตรวจสอบการป้อนข้อมูลซ้ำ (duplicate record) เราสามารถทำได้โดยใช้คำสั่ง TABLEUPDATE() โดยมีหลักอยู่ว่า ถ้าสามารถทำการ update ข้อมูลได้สำเร็จ ค่า TABLEUPDATE() จะเป็น .T. แต่ถ้าไม่สามารถทำการ update ได้ไม่ว่ากรณีใดๆก็ตาม ค่า TABLEUPDATE() จะมีค่าเป็น .F.

เราจะมาดูว่าจะทำการเช็ครหัสสินค้าที่ได้ป้อนไแล้วอย่างไร
12. ให้คุณคลิ๊กเมาส์ปุ่มขวาที่   Mtextbox1 เลือก Properties… แล้วทำการป้อนคำสั่งใน Valid Event ดังนี้
if .not. tableupdate()
messagebox(‘มีรหัสสินค้า ‘ + allt(this.value) + ‘นี้อยู่แล้ว’)
return 0
endif
13. ทำการ Save ฟอร์มโดยตั้งชื่อว่า PRODUCT แล้วลองเรียกฟอร์มขึ้นมาดู

เคล็ดไม่ลับ ใน Valid Event คำสั่ง return เป็นการบอกให้ทราบว่าจะสามารถผ่านออกจากฟิลด์การป้อนข้อมูลนี้ไปได้หรือไม่ ถ้ามีค่าเป็น .T. แสดงว่าสามารถผ่านออกจากฟิลด์ได้ ถ้ามีค่าเป็น .F. แสดงว่าไม่สามารถออกจากฟิลด์นี้ได้แล้วจะขึ้น ข้อความแจ้งว่า Invalid Input ซึ่งเป็นข้อความแจ้งข้อผิดพลาดของ Visual FoxPro เราสามารถทำให้ไม่แสดงได้โดยการใช้ return 0 แทน .F.

Data Session

ดาต้าเซสชัน(data session) มันคืออะไรกันแน่ ?
เมื่อก่อนการเขียนโปรแกรม dBASE , Foxbase จะเป็นงานในลักษณะเปิดโปรแกรมขึ้นมาแล้ก็ทำการป้อนข้อมูล เพียงอย่างใดอย่างหนึ่งเท่านั้น เช่นป้อนข้อมูลใบส่งสินค้า แต่ถ้าเราต้องการป้อนข้อมูลลูกค้า เราก็ต้องออกจากการป้อนใบส่งสินค้าก่อนแล้วถึงจะค่อยเข้าสู่โปรแกรมป้อนข้อมูลลูกค้า แต่ในปัจจุบันเมื่อเรามาใช้ Visual FoxPro เราสามารถเปิดงานหลายๆงาน(เปิดฟอร์ม)พร้อมกันได้ ปัญหาเรื่องการเปิดปิดไฟล์จึงเกิดขึ้น เพราะว่าใน Main Visual FoxPro นั้นยอมให้เราเปิดแฟ้มข้อมูลได้เพียงครั้งเดียว เช่น ถ้าเราเปิด customer.dbf แล้ว เราก็ไม่สามารถเปิดได้อีกเป็นต้น หรือถ้าเราปิดฟอร์มที่มีแฟ้ม customer.dbf อยู่สักสองฟอร์ม แล้วปิดไปสักฟอร์มหนึ่ง แฟ้ม customer.dbf ก็จะถูกปิดไปด้วย ฟอร์มที่เปิดเหลืออยู่อีกฟอร์มหนึ่งก็จะเกิด Error (ในกรณี่ที่เรากำหนด properties ใน Data Environment เป็น AutoClose Table เป็น .T.) เอาล่ะที่กล่าวมาทั้งหมดเพื่อที่จะทำให้เห็นภาพอย่างคร่าวๆว่าทำไมจึงต้องมี ดาต้าเซสชัน(data session)
ดาต้าเซสชัน มีอยู่สองประเภทคือ
1.  Default Data Session ใน Visual FoxPro จะกำหนดให้เป็น Defalut เสมอถ้าเราไม่ทำการเปลี่ยน
2. Private Data Session จะกำหนดให้การปิดแฟ้มข้อมูลแยกออกจากกันเป็นเอกเทศแต่ละฟอร์มก็จะแยกออกจากกัน
แล้วเราจะกำหนดเป็นแบบใหนดี? ขอแนะนำว่าให้กำหนดเป็นแบบ Private Data Session จะดีกว่าซึ่งจะทำให้เราไม่ต้องกังวลในการสร้างฟอร์ม หรือเมื่อเราทำการเขียนโปรแกรมในแบบหลายผู้ใช้ (LAN)
เราจะกำหนดดาต้าเซสชัน ไว้ที่ไหน? เราจะกำหนดดาต้าเซสชัน ไว้ใน Form Properties หรือ Formset Properties ในส่วนของ DataSession
มาถึงตอนนี้ผมก็ของให้คุณไปทำการเปลี่ยน ดาต้าเซสชัน ที่อยู่ในฟอร์มของโปรแกรมตัวอย่างให้เป็น Private Data session

ก่อนที่เราจะไปเรียนรู้เรื่อง ฟอร์มการป้อนข้อมูลที่มีความสัมพันธ์แบบหนึ่งต่อหลายๆเรคคอร์ด เรามาดูกันในเรื่องเทคนิคและวิธีการใช้งาน คอนโทล(Control) ต่างๆที่มีอยู่ใน Form Designer กันก่อน

เทคนิคนำมาเล่าสู่กันฟัง คุณสามารถนำไปประยุกต์ได้อีกหลากหลายและหลายหลาก

เทคนิคเกี่วยกับ Form
จะทำการ Refresh ฟอร์มหลายๆฟอร์มพร้อมกันทำอย่างไร ?

ให้ใช้คำสั่ง
FOR I = 1 TO _SCREEN.FORMCOUNT
_SCREEN.FORMS(I).REFRESH)
ENDFOR

ส่งผ่านค่าออกจากฟอร์ม
ตอนเรียกฟอร์มขึ้นมาใช้งานให้ใช้คำสั่ง DO FORM MyForm TO MyVar หลังจากที่ออกจากฟอร์มแล้วเราจะนำค่า MyVar ไปทำอะไรต่อก็ได้
ในฟอร์มของเราให้กำหนดดังนี้
1. ที่เมนู Form เลือก New Properties แล้วกำหนดชื่อเป็น MyReturnVar
2. ที่ฟอร์มกำหนด Properties ในส่วนของ Windowtype เป็น 1
3. นำค่าที่ต้องการส่งกลับมาใส่ไว้ใน MyReturnVar (อันนี้ขึ้นอยู่ว่าคุณจะใ่ส่ไว้ในส่วนใหน่เช่นใน Click Event ของ Command Button เป็นต้น)
THISFORM.MyReturnVar = THISFORM.TEXT1.Value
4. ค่าที่ส่งกลับนำไปใส่ไว้ที่  Form Properties ในส่วนของ Unload Method โดยพิมพ์คำสั่ง
RETURN THISFORM.MyReturnVar

ส่งผ่านค่าเข้าสู่ฟอร์ม
ตอนเรียกฟอร์มขึ้นมาใช้งานให้ใช้คำสั่ง DO FORM MyForm WITH  MyVar
ในฟอร์มของเราให้กำหนดดังนี้
1. ที่ฟอร์มในส่วนของ Init Event ให้ใ่ส่
PARAMETER MyVar
THISFORM.TEXT1.Value = MyVar      && เป็นการนำค่าที่ส่งผ่านมาใส่ไว้ใน Text1

ส่งผ่านค่าอะเรย์ (Array) เข้าสู่ฟอร์ม
    ตอนเรียกฟอร์มขึ้นมาใช้งานให้ใช้คำสั่ง DO FORM MyForm WITH  MyArray1
ในฟอร์มของเราให้กำหนดดังนี้
1. ที่เมนู Form เลือก New Properties แล้วกำหนดชื่อเป็น MyArray2(1)
2. ที่ฟอร์มในส่วนของ Init Event ให้ใ่ส่
PARAMETER MyArray1
DIMENSION MyArray2(ALEN(MyArray1))  && สร้างอะเรย์ขนาดเท่ากับค่าอะเรย์ที่ส่งผ่านเข้ามา
=ACOPY(MyArray1,THIS.MyArray2)    && ย้ายตัวแปรอะเรย์ที่ส่งผ่านเข้ามาไปไว้ที่ตัวแปรอะเรย์ในฟอร์ม

เทคนิคเกี่ยวกับ Label Control
กำหนดข้อความ(Label) แบบแนวตั้ง
    เมื่อคุณทำการสร้าง Label ขึ้นมาแล้วต้องการให้แสดงในแนวตั้ง(Vertical) สามารถทำได้ดังนี้
1. ที่ Label Properties ในส่วนของ Caption พิมพ์
=”T” + CHR(13) + “E” + CHR(13) + “S” + CHR(13) + “T”
2. ที่ Label Properties ในส่วนของ AutoSize กำหนดเป็น .F. แล้วทำการปรับขนาดของ Label ให้แสดงตามต้องการ

เทคนิคเกี่ยวกับ TextBox Control
กำหนดแถบแสงให้กับข้อความ
ในการกำหนดแถบแสงให้กับข้อความใน textbox นั้นมีอยู่หลายวิธีด้วยกัน ดังนี้
วิธีแรก จะเป็นการกำหนดแถบแสดงโดยทั่วๆไป
กำหนดใน textbox  properties ในส่วนของ Format เป็น K และกำหนด SelectedBackColor เป็น 0,0,128
วิธีที่สอง จะเป็นการกำหนดแถบแสดงโดยทั่วๆไปเหมือนกันแต่ขี้เกียจกำหนดในทุกๆ object
กำหนดที่ Form ในส่วนของ Init Event โดยใช้คำสั่ง Setall มาช่วย เช่น
THISFORM.SetAll(“Format”,”K”,”TextBox”)
THISFORM.SetAll(“SelectedBackColor”,RGB(0,0,128),”TextBox”)
วิธีที่สาม
กำหนดที่ textbox properties ในส่วนของ GotFocus Method ดังนี้
IF NOT EMPTY(THIS.Value)
KEYBOARD”{END}”
KEYBOARD”{SHIFT+HOME}”
ENDIF

เทคนิกเกี่ยวกับ Grid Control
ตั้งแต่ Visual FoxPro เป็นต้นมา กริดก็เป็นพระเอกมาตลอด ผมพูดแบบนี้คงไม่ผิด เนื่องจากว่าในการเขียนฟอร์มนั้นกริดเป็นตัวหนึ่งที่มีประโยชน์มาก สามารถทำงานได้หลายอย่าง ซึ่งวิธีการใช้งานถ้าดูกันไปลึกๆแล้วมันมีวิธีการมากมายเหลือเกินสุดแต่ผู้เขียนโปรแกรมจะจัดการกับมัน ในตอนนี้ผมจะสรุปเป็นตัวอย่างให้ดูว่าจะมีวิธีการควบคุมมันอย่างไรโดยจะแยกออกเป็นฉากๆไป
ขอเริ่มด้วยฉากแรกก่อนซึ่งเป็นการทำ Increment Search หรือโปรแกรมสอบถามข้อมูล

การทำ Increment Search โดยใช้กริด  (Download)
การค้นหาข้อมูลใน Visual FoxPro นั้นมีด้วยกันหลายวิธีหลายแบบ คุณอาจใช้ combo box หรือ
list box ช่วยก็ได้ แต่สำหรับผมแล้วถ้าข้อมูลมากๆละก็ต้องใช้กริดช่วย ซึ่งอาจเป็นวิธีโบราณไปสักหน่อยแต่ก็ไม่ล้าสมัยครับ และมันยังสามารถนำไปประยุกต์ได้มากมายหลายอย่างขึ้นอยู่กับคุณๆทั้งหลาย

ก่อนอื่นคุณจะทำการค้นหาข้อมูลในฟิลด์ใดนั้นคุณต้องไปสร้างดัชนีให้กับฟิลด์นั้นๆก่อน ในที่นี้ผมจะทำการสร้างโปรแกรมสำหรับค้นหาชื่อลูกค้า ดังนั้นเราก็ต้องไปทำการสร้างดัชนีให้กับฟิลด์ชื่อลูกค้า (NAME) โดยทำดังนี้
1. ให้เรียกโปรเจ็กขึ้นมาแก้ไข โดยพิมพ์ MODIFY PROJECT MYPROJECT
2. เข้าไปแก้ไขแฟ้มข้อมูล(table) ของ CUSTOMER ซึ่งอยู่ใน แท๊ป DATA ในส่วนของ Databases -> MyDatabase -> Table
3. ที่ Table Designer ให้คลิ๊กที่แท๊ป Indexes ที่ช่อง Name ให้พิมพ์ NAME  ช่อง Type เลือก Regula ช่อง Expression พิมพ์ NAME เสร็จแล้วคลิ๊กที่ปุ่ม OK เพื่อทำการเก็บข้อมูล

เคล็ดไม่ลับ แก้ปัญหาจัดเรียงลำดับตามภาษาไทยด้วยการเข้าไปกำหนดที่ เมนู Tools เลือก Options… คลิ๊กที่แท๊ป Data ที่ช่อง Collating sequence เปลี่ยนเป็น Thai หรือใช้คำสั่ง SET COLLATE TO “THAI”

ทีนี้เราก็มาทำการสร้างฟอร์มที่ใช้ในการค้นหาข้อชื่อลูกค้ากันต่อ
1. ให้คุณทำการสร้างฟอร์มขึ้นมาโดยทำการคลิ๊กที่แท๊บ Documents แล้วเลือก Form แล้วทำการคลิ๊กที่ปุ่ม New แล้วเลือก New Form
2. ทำการคลิ๊กขวาที่ฟอร์มแล้วเลือกเมนู Data Environment… เลือกแฟ้มข้อมูล CUSTOMER แล้วคลิ๊กที่ปุ่ม Add จากนั้นคลิ๊กที่ปุ่ม Close
3. คลิ๊กขวาที่แฟ้ม CUSTOMER เลือก Properties แล้วกำหนด
Order = Name
4. ทำการสร้าง Text box ขึ้นมา แล้วกำหนด Properties ดังนี้
FontName = MS Sans Serif
High = 23
Width = 300
5. ทำการสร้าง Grid ขึ้นมา จากนั้นให้ทำการคลิ๊กปุ่มขวาที่ กริดที่เราได้สร้างขึ้นแล้วเลือก Builder… จากนั้นให้ทำการเลือกแฟ้ม CUSTOMER แล้วเลือกฟิลด์ Name และ Cust_ID แล้วทำการคลิ๊กที่ปุ่ม OK
6. กำหนด properties ของ Grid ดังนี้
DeleteMark = .F.
FontName = MS Sans Serif
GridLines = 0
Hight = 200
ReadOnly = .T.
RecordMark = .T.
ScrollBar = 2
Width = 350
7. กำหนด properties ของ Grid -> Column1 ดังนี้
Resizeable = .F.
Width = 280
8. กำหนด properties ของ Grid -> Column1 -> Header1 ดังนี้
Alignment = 2
Caption = ชื่อลูกค้า
9. กำหนด properties ของ Grid -> Column1 -> Text1 ดังนี้
ForeColor  = 255,255,255
BackColor  = 0,0,128
10. กำหนด properties ของ Grid -> Column2 ดังนี้
Resizeable = .F.
Width = 50
11. กำหนด properties ของ Grid -> Column2 -> Header1 ดังนี้
Alignment = 2
Caption = รหัส
12. กำหนด properties ของ Grid -> Column2 -> Text1 ดังนี้
Enabled  = .F.
13. ทำการกำหนด method ดังนี้
ที่ Text1 -> InteractiveChange Event พิมพ์
SET NEAR ON
SEEK ALLTRIM(THIS.VALUE)
nRecno = RECNO()
THISFORM.grid1.&cSetBack
THISFORM.grid1.&cSetFore
THISFORM.REFRESH
ที่ Grid1 -> AfterRowColChange Event พิมพ์
nRecno = RECNO()
THIS.REFRESH
ที่ Grid1 -> Init Event พิมพ์
PUBLIC nRecno , cSetBack , cSetFore
nRecno = RECNO()
cSetBack = ‘setall(“Dynamicbackcolor”,”IIF(RECNO()=nRecno,RGB(0,0,128),RGB(255,255,255))”,”Column”)’   &&เป็นการกำหนดสีฉากหลัง
cSetFore = ‘setall(“Dynamicforecolor”,”IIF(RECNO()=nRecno,RGB(255,255,255),RGB(0,0,0))”,”Column”)’   &&เป็นการกำหนดสีตัวอักษร
THIS.&cSetBack
THIS.&cSetFore
14. จากนั้นก็ทำการ save ฟอร์ม ให้ตั้งชื่อเป็น CUSTINQ แล้วลองเรียกมาดูว่าเป็นอย่างไร ส่วนคุณจะนำไปประยุกต์อย่างไรนั้นก็ขึ้นอยู่กับความต้องการของคุณ

การนำคอนโทรมาไว้ในกริด (Download)
เราสามารถนำคอนโทรต่างๆมาใส่ไว้ในกริดได้เช่น Text Box , Combo Box , Edit Box เป็นต้น ซึ่งมีวิธีการง่ายๆดังต่อไปนี้
1. ให้คุณทำการสร้างฟอร์มขึ้นมาโดยทำการคลิ๊กที่แท๊บ Documents แล้วเลือก Form แล้วทำการคลิ๊กที่ปุ่ม New แล้วเลือก New Form
2. ทำการคลิ๊กขวาที่ฟอร์มแล้วเลือกเมนู Data Environment… เลือกแฟ้มข้อมูล CUSTOMER แล้วคลิ๊กที่ปุ่ม Add แล้วก็เลือกแฟ้มข้อมูล Salesman แล้วคลิ๊กปุ่ม Add จากนั้นคลิ๊กที่ปุ่ม Close
3. ถ้าใน Data Enviroment มีการสร้างความสัมพันธ์ระหว่างแฟ้ม Customer กับ Salesman ก็ให้เอาออกเพราะเราไม่ได้ใช้ เอาออกได้โดยคลิ๊กเมาส์ที่เส้นโยงความสัมพันธ์ระหว่างแฟ้มแล้วกดปุ่ม Delete
4. ทำการสร้าง Grid ขึ้นมา โดยคลิ๊กเมาส์ที่แฟ้ม Customer ใน Data Environment แล้วลากมาไว้ในฟอร์ม คุณก็จะได้กริดของ แฟ้ม Customer
5. จากนั้นให้กำหนด Properties ของ Form1 ดังนี้
Hight = 300
Width = 600
6. จากนั้นให้กำหนด Properties ของ Grid1 ดังนี้
FontName = MS Sans Serif
RowHight = 30
Left   = 15
Hight = 300
Width = 600
ถ้าเราสังเกตดูที่กริดในส่วนของ Properties ในคอลัมน์ต่างๆของฟิลด์นั้นจะประกอบไปด้วย 3 ส่วนคือ Column -> Header -> Control ซึ่งก็เป็นที่มาของเรื่องนี้ไงครับ
7. จากนั้นให้ทำการนำคอนโทรมาใส่ไว้ที่ Term_Day โดยทำการคลิ๊กขวาที่กริด แล้วเลือกเมนู Edit ต่อจากนั้นก็ทำการคลิ๊กที่คอนโทร Spinner ที่ Form Control เมื่อทำการคลิ๊กเรียบร้อยก็ทำการคลิ๊กที่ตรงกรอบ   ab| ที่ฟิลด์ Term_Day เท่านี้คุณก็จะได้คอนโทร Spiner มาเรียบร้อยโรงเรียนจีน
8. เนื่องจากตอนนี้ที่คอลัมน์ของ Term_Day ยังเป็นคอนโทร Text Box อยู่คุณต้องทำการเปลี่ยนให้เป็นคอนโทร   Spinner โดยทำการกำหนด Properties ของ Column5 ดังนี้
CurrentControl = Spinner1
9. ให้คุณเปลี่ยน Column6 (ฟิลด์ Sales_ID) ให้เป็นคอนโทร Combo Box โดยทำการคลิ๊กเมาส์ขวาที่กริด แล้วเลือกเมนู Edit เหมือนเดิม แล้วก็ทำคล้ายๆกับข้อ 7 โดยเปลี่ยนเป็น คอนโทร Combo Box แทน แล้วก็กำหนด CurrentControl ให้เป็น Combo1
10. เห็นไหมครับว่าการที่เราจะเพิ่มคอนโทรต่างๆเข้ามาในกริดมันไม่ได้ยากอะไรเลย แต่เมื่อเราทำการเพิ่มคอนโทรเข้ามาแล้วก็ยังมีคอนโทรส่วนเกินที่เราไม่ต้องการเช่น Text1 ใน Column5 กับ Column6 ถ้าต้องการที่จะลบทิ้งก็สามารถทำได้โดย ให้คุณเลือกคอนโทรของกริดที่ต้องการลบจาก properties dialogbox แล้วทำการเลือกคอนโทรจาก list box ของ properties ซึ่งตอนนี้เราต้องการลบ ที่ Text1 ใน Column5 ของกริด ดังรูป จากนั้นก็ไปทำการคลิ๊กที่ title ของฟอร์ม แล้ก็กดปุ่ม Delete เท่านี้ก็เรียบร้อย (ปล.อธิบายเป็นภาษาเขียนนี่มันยากจริงๆ)
c9302.gif (8218 bytes)

ส่วน คอนโทร Text1 ของ Column6 ก็ทำในลักษณะเดียวกัน
11. ให้คุณกำหนด properties ของ Spinner1 ในกริดดังนี้
KeyboardHighValue = 999
KeyboardLowValue = 0
SpinnerHighValue = 999
SpinnerLowValue = 0
12. ให้คุณกำหนด properties ของ Combo1 ในกริดดังนี้
BoundColumn = 1
ColumnCount = 2
ColumnWidths = 0,200
FontName = MS Sans Serif
RowSource = Salesman.Sales_ID , Name
RowSourceType = 6

การทำ header ของกริดให้สามารถแสดงได้หลายบรรทัด (เป็นการยืมคอนโทรอื่นมาใช้แทน)
        13. ให้คุณกำหนด properties ของ Grid1 ดังนี้
HeaderHight = 45
14. ให้คุณกำหนด properties ของ Grid1 -> Column1 -> Header1 ดังนี้
Caption = เคาะ Spacebar หนึ่งครั้ง
15. ให้คุณสร้าง Label ขึ้นมาแล้วนำมาแปะไว้ที่ส่วนของ header ของกริดตามแต่คุณต้องการว่าจะไว้ที่ไหนใน header แล้วกำหนด properties ของ Label ดังนี้
BackStyle =   0
Caption =       =”รหัสลูกค้า” + CHR(13) + “Customer ID”
16. จากนั้นก็ทำการ save ฟอร์ม ให้ตั้งชื่อเป็น CUSTGRD แล้วลองเรียกมาดูว่าเป็นอย่างไร

การเพิ่ม ลบ แก้ไข ข้อมูลบนกริด (Download)
และแล้วเราก็มาสู่ส่วนที่สำคัญที่สุดส่วนหนึ่งของ Visual FoxPro ก็ว่าได้ ถ้าคุณสามารถทำความเข้าใจในหลักการและ วิธีการที่ผมจะอธิบายในตอนนี้ได้ก็ถือว่าคุณประสบความสำเร็จไปอีกขั้นหนึ่ง แต่คุณต้องรู้จักประยุกต์อีกนิดหน่อยเพื่อที่จะได้ในสิ่งที่ต้องการ
อธีบายโปรแกรม…ก่อน
ตัวอย่างที่ผมจะนำเสนอต่อไปนี้เป็นเพียงวิธีการหนึ่งเท่านั้น โดยจะเป็นการแสดงแฟ้มข้อมูลลูกค้า(CUSTOMER) ขึ้นมาแก้ไข เพิ่ม หรือลบ ก็ได้ ซึ่งจะประกอบไปด้วย Shortcut Menu โดยการคลิ๊กเมาส์ขวาที่คอลัมน์ รหัสลูกค้า แล้วจะมีเมนูให้เลือกว่าจะ เพิ่ม หรือ ลบข้อมูล ส่วนการแก้ไขข้อมูลนั้นคุณก็สามารถแก้ไขได้ตลอดเวลา แต่โปรแกรมจะทำการตรวจสอบว่า ในรายการ(record)   ใดมีการเปลี่ยนแปลง โปรแกรมจะแสดงข้อความ(message) เพื่อให้ confirm ว่าจะเก็บข้อมูลหรือไม่ หรือคุณอาจจะทำการคลิ๊กเมาส์ปุ่มขวาก็จะมีเมนูว่าจะให้ Save หรือ Cancel รายการนั้นๆ   และก็แถมท้ายด้วยการเช็ค Error Duplicate ของรายการในกริด
        1. ให้คุณทำการสร้าง shotcut menu ขึ้นมาก่อน (คุณอาจใช้ command button แทนก็ได้ แต่ผมมีความชอบส่วนตัวเลยอยากให้ทำ) โดยพิมพ์คำสั่งที่ command window ดังนี้
CREATE MENU CUSTGRD1
เลือก Shortcut
แล้วทำการกำหนดรายการดังรูป
c9303.gif (4563 bytes)
คลิ๊กที่ปุ่ม Edit ของ Append New Record แล้วป้อนคำสั่งดังนี้
APPEN BLANK
GO BOTT
_Screen.Activeform.lSkip = .T.
_Screen.Activeform.lAppend = .T.
_Screen.Activeform.Refresh
คลิ๊กที่ปุ่ม Option ของ Append New Record ในส่วนของ Skip for ทำการป้อนคำสั่งดังนี้
_Screen.ActiveForm.LSkip   && เป็นการ skip รายการเมนู้เมื่อ LSkip มีค่าเป็น .T.
คลิ๊กที่ปุ่ม Edit ของ Delete A Record แล้วป้อนคำสั่งดังนี้
IF MESSAGEBOX(“ต้องการลบรายการ ” + Customer.Cust_ID, 292, “”)
Delete
=Tableupdate(.T.)
_Screen.ActiveForm.Refresh
ENDIF
คลิ๊กที่ปุ่ม Option ของ Delete A Record ในส่วนของ Skip for ทำการป้อนคำสั่งดังนี้
_Screen.ActiveForm.LSkip   && เป็นการ skip รายการเมนู้เมื่อ LSkip มีค่าเป็น .T.
หลังจากนั้นก็ทำการคลิ๊กที่เมนู Menu แล้วเลือก Generate… เพื่อทำการสร้างเมนูโปรแกรม เมื่อสร้างเสร็จกด Ctrl + W เพื่อทำการ Save เมนู

2. ให้คุณทำการสร้าง shotcut menu ขึ้นมาอีกตัว โดยพิมพ์คำสั่งที่ command window ดังนี้
CREATE MENU CUSTGRD2
เลือก Shortcut
แล้วทำการกำหนดรายการดังรูป
c9304.gif (4292 bytes)

คลิ๊กที่ปุ่ม Edit ของ Save แล้วป้อนคำสั่งดังนี้
=Tableupdate(.T.)
_Screen.ActiveForm.LSkip = .F.
_Screen.Activeform.lAppend = .F.
คลิ๊กที่ปุ่ม Edit ของ Cancel แล้วป้อนคำสั่งดังนี้
=Tablerevert(.T.)
_Screen.ActiveForm.LSkip = .F.
_Screen.Activeform.lAppend = .F.
หลังจากนั้นก็ทำการคลิ๊กที่เมนู Menu แล้วเลือก Generate… เพื่อทำการสร้างเมนูโปรแกรม เมื่อสร้างเสร็จกด Ctrl + W เพื่อทำการ Save เมนู

        3. เมื่อคุณทำการสร้าง shortcut menu เรียบร้อยแล้วให้คุณทำการเรียกฟอร์ม CUSTGRD ที่ได้สร้างไว้ขึ้นมาแก้ไข โดยพิมพ์คำสั่ง
MODIFY FORM CUSTGRD
4. ทำการคลิ๊กเมาส์ปุ่มขวาที่ฟอร์ม แล้วเลือกรายการ Data Environment… ทำการคลิ๊กเมาส์ปุ่มขวาที่ table CUSTOMER แล้วเลือกรายการ Properties… แล้วกำหนดค่าดังนี้
                BufferModeOverride = 5
เพราะในการทำงานที่เกี่ยวกับการปรับปรุงข้อมูลโดยใช้ คำสั่ง TABLEUPDATE() เราจำเป็นต้องกำหนด tabel เป็นแบบ buffer เสมอ
        5. ทำการสร้าง property โดยเลือกที่เมนู Form แล้วคลิ๊กที่ New Property… ป้อน
                nRecNum คลิ๊กปุ่ม Add
nWhatRow คลิ๊กปุ่ม Add
LAppend คลิ๊กปุ่ม Add
LSkip คลิ๊กปุ่ม Add แล้วคลิ๊กปุ่ม Close อีกครั้ง
        6. ทำการสร้าง method โดยเลือกที่เมนู Form แล้วคลิ๊กที่ New Method… ป้อน
                mShortcut คลิ๊กปุ่ม Add แล้วคลิ๊กปุ่ม Close อีกครั้ง
        7. คลิ๊กขวาที่ฟอร์ม เลือกรายการ Properties แล้วกำหนด คุณสมบัติของ Form ดังนี้
                nRecNum = 0
nWhatRow = 0
LAppend = .F.
LSkip = .F.
ส่วนเมธอต mShortcut ป้อนคำสั่งดังนี้
cChange = GetFldState(-1,”Customer”)
IF AT(‘2’, cChange) > 0 .OR. AT(‘4’, cChange) > 0
DO CUSTGRD2.MPR
ELSE
DO CUSTGRD1.MPR
ENDIF
        8. ที่ Form ในส่วนของ Init Event ป้อนคำสั่ง SET DELETE ON

ทำการเช็คว่ามีการป้อนข้อมูลในรายการ(record)
9. ที่ Grid1 ในส่วนของ AfterRowColChange ป้อนคำสั่งดังนี้

LPARAMETERS nColIndex
IF ThisForm.lAppend
ThisForm.nWhatRow = This.ActiveRow
ThisForm.lAppend = .F.
ELSE
lMov = .F.
IF ThisForm.nWhatRow # This.ActiveRow
ThisForm.nWhatRow = This.ActiveRow
nHold= RECNO()
GO ThisForm.nRecNum
cChange = GetFldState(-1,’Customer’)
IF AT(‘2’, cChange)>0 .or. AT(‘4’,cChange) > 0
This.Refresh
lMov = .T.
IF MessageBox(“Update Record”,4)= 6
=TableUpdate(.T.)
ELSE
=TableRevert(.T.)
ENDIF
ThisForm.lSkip = .F.
ELSE
IF AT(‘4’,cChange) = 0 .and. AT(‘1’,cChange) = 0
= TableRevert(.T.)
ThisForm.nRecNum = nHold
ThisForm.lSkip = .F.
ENDIF
ENDIF
GO nHold
IF lMov
lMov =.F.
ENDIF
ENDIF
ENDIF
This.Refresh

แนะนำคำสั่ง ในการกระทำกับ record ที่เรากำหนดตารางเป็นแบบบับเฟอร์(table buffer) นั้นเราจะทราบได้อย่างไรว่ามีการเพิ่มเรคคอร์ด ลบเรคอร์ด แก้ไขฟิลด์ ใดๆบ้าง เพื่อที่เราจะได้ทำการปรับปรุงข้อมูลที่ถูกต้องเข้าสู่ตาราง (TABLEUPDATE) Visual FoxPro ได้มีคำสั่งเตรียมไว้ให้เราเรียบร้อยแล้วซึ่งก็คือ GETFLDSTATE()
รูปแบการใช้งาน
 GETFLDSTATE(cFieldName | nFieldNumber [, cTableAlias | nWorkArea])
            หลังจากที่ทำการเรียกใช้งานคำสั่งแล้วจะส่งค่ากลับมาเป็นตัวเลข ซึ่งมาค่าอยู่ระหว่าง 1 ถึง 4
1 = บอกให้รู้ว่าฟิลด์นี้ยังไม่มีการแก้ไข
2 = บอกให้รู้ว่าฟิลด์นี้ได้มีการแก้ไขข้อมูล หรือ ลบเรคคอร์ด
3 = จะเป็นสถานะของการเพิ่มข้อมูล และยังไม่มีการป้อนข้อมูลเข้าไป
4 = จะเป็นสถานะของการเพิ่มข้อมูล และได้มีการป้อนข้อมูลเข้า หรือ ลบเรคคอร์ด
nFieldNumber ถ้ามีค่า -1 จะเป็นการแสดงสถานะของทั้งเรคคอร์ด เช่นค่าที่ได้จะเป็น 121121 โดยที่ค่าตัวแรกจะหมายถึงว่าเรคคอร์ดนั้นๆได้ถูกลบออกไปหรือไม่ ส่วนค่าถัดไปแสดงถึงฟิลด์ต่างว่าเปลี่ยนแปลงหรือไม่
ตัวอย่าง
ให้คุณทำการเรียกแฟ้มข้อมูล ลูกค้าขึ้นมา โดยพิมพ์คำสั่งที่ command window ดังนี้
SET MULTILOCKS ON
USE CUSTOMER
=CURSORSETPROP(“BUFFERING”,5,”CUSTOMER”)
GO 2
DELETE
?GETFLDSTATE(-1,”CUSTOMER”)  && โปรแกรมจะแสดงค่า 2111111
GO 1
REPLACE NAME WITH “abc”
?GETFLDSTATE(-1,”CUSTOMER”)  && โปรแกรมจะแสดงค่า 1121111 บอกให้ทราบว่าฟิลด์ NAME ได้ถูกแก้ไข
?GETFLDSTATE(“NAME”)  && โปรแกรมจะแสดงค่า 2 บอกให้ทราบว่าฟิลด์  NAME ได้มีการแก้ไข
APPEN BLANK
?GETFLDSTATE(-1)   && โปรแกรมจะแสดงค่า 3333333 บอกให้ทราบว่ามีการเพิ่มเรคคอร์ดใหม่และยังไม่มีการแก้ไข
TABLEREVERT(.T.)   && ยกเลิกสิ่งที่เราทำไปทั้งหมด

9. ที่ Grid1 ในส่วนของ BeforeRowColChange ป้อนคำสั่ง
IF EOF()
GO BOTT
ENDIF
ThisForm.nRecNum = RECNO()
10. ที่ Grid1 ในส่วนของ Init ป้อนคำสั่ง ThisForm.nRecNum = RECNO()
11. ที่ Grid1 ในส่วนของ RightClick ป้อนคำสั่ง =thisform.MShortcut()
12. ที่ Grid1 ในส่วนของ Column1->Text1 ใน RightClick ป้อนคำสั่ง =thisform.MShortcut()
13. เมื่อคุณทำเสร็จแล้วให้ทำการเก็บฟอร์มนี้เป็นชื่อใหม่ โดยการคลิ๊ก เมนู File เลือก Save As แล้วพิมพ์ชื่อเป็น CUSTGRD1 คลิ๊กที่ปุ่ม Save จากนั้นก็ลองเรียกฟอร์มขึ้นมาลองป้อนข้อมูลดู
ส่วนการเช็ค Duplicate Record ก็ใช้วิธีเดียวกันกับตัวอย่างข้างต้น ที่ใช้ IF .NOT. TABLEUPDATE()

การสร้างฟอร์มแบบที่มีความสัมพันธ์หนึ่งต่อหลาย (one to meny) Download
หลังจากที่คุณได้ทำการเรียนรู้วิธีการสร้างฟอร์มแบบต่างๆไปบ้างแล้ว ต่อมาในส่วนนี้ก็จะกล่าวถึงหลักและวิธีการสร้างฟอร์ม one to meny ในตัวอย่างต่อไปนี้สอนการทำใบส่งสินค้า (invoice) ซึ่งจะประกอบไปด้วยตาราง(table) หลายๆตารางมาเชื่อมความสัมพันธ์กัน(relation) เอาละครับเรามาเริ่มกันเลยแล้วกัน ให้คุณทำการป้อนคำสั่งที่ command windows ดังนี้
CLOSE ALL
OPEN DATABASE MYDATABASE
CREATE FORM INVOICE
แล้วเข้าไปกำหนด property ของฟอร์มในส่วนของ Load Event โดยป้อนคำสั่ง SET DELETE ON
ทำการสร้าง Property โดยเข้าไปที่เมนู Form แล้วเลือก New Property ป้อนชื่อ LNew
เมื่อคุณทำการสร้างฟอร์มแล้วให้คุณทำตามขั้นตอนต่อไปนี้

กำหนดความสัมพันธ์ของตาราง
        1. ทำการคลิ๊กเมาส์ปุ่มขวาที่ฟอร์มแล้วเลือก Data Enviroment…
2.ที่ Data enviroment ให้ทำการคลิ๊กเมาส์ปุ่มขวาแล้วเลือก Add…
คลิ๊กที่ตาราง INV_HEAD แล้วคลิ๊กปุ่ม Add
คลิ๊กที่ตาราง INV_DTL แล้วคลิ๊กปุ่ม Add
คลิ๊กที่ตาราง CUSTOMER แล้วคลิ๊กปุ่ม Add
คลิ๊กที่ตาราง PRODUCT แล้วคลิ๊กปุ่ม Add แล้วคลิ๊กที่ปุ่ม Close อีกที
3. ถึงตอนนี้คุณก็จะได้ตารางข้อมูล และก็มีเส้นเชื่อมโยงความสัมพันธ์แสดงอยู่ที่ Data Environment ผมอยากให้คุณเอามันออกให้หมดก่อน โดยทำการคลิ๊กเมาส์ที่เส้นเชื่อมโยงความสัมพันธ์แล้วกดปุ่ม Del ที่ keyboard
4. ตอนนี้เรามาสำรวจความสัมพันธ์ระหว่างตารางกันก่อนว่าอะไรควรจะเชื่อมกับอะไร
ตาราง INV_HEAD เชื่อมกับตาราง INV_DTL โดยใช้ฟิลด์ INV_NO
ตาราง INV_HEAD เชื่อมกับตาราง CUSTOMER โดยใช้ฟิลด์ CUS_ID
ตาราง INV_DTL เชื่อมกับตาราง PRODUCT โดยใช้ฟิลด์ PROD_ID
5. การโยงความสัมพันธ์ระหว่างตารางนั้นทำได้โดยการคลิ๊กที่ฟิลด์ในตารางแม่(parent) แล้วลากไปวางที่ฟิลด์ในตารางลูก(child) ให้คุณทำดังนี้
คลิ๊กที่ฟิลด์ INV_NO ในตาราง INV_HEAD แล้วทำการลากไปวางไว้ที่ ฟิลด์ INV_NO ของตาราง INV_DTL
คลิ๊กที่ฟิลด์ CUS_ID ในตาราง INV_HEAD แล้วทำการลากไปวางไว้ที่ ฟิลด์ CUS_ID ของตาราง CUSTOMER
คลิ๊กที่ฟิลด์ PROD_ID ในตาราง INV_DTL แล้วทำการลากไปวางไว้ที่ ฟิลด์ PROD_ID ของตาราง PRODUCT

ข้อควรจำ ในการกำหนดความสัมพันธ์ให้กับตารางใดๆนั้น เราต้องกำการสร้างแฟ้มดัชนี(index) ให้กับฟิลด์ในตารางลูก (child table) ที่เราจะทำการเชื่อมโยงก่อนเสมอ

c9305.gif (8259 bytes)

6. จากนั้นให้กำหนด property ของแต่ละตาราง โดยทำการคลิ๊กเมาส์ที่ปุ่มขวาของตารางแล้วเลือก Properties… ให้กำหนด property ของแต่ละตารางดังนี้
ตาราง INV_HEAD
BufferModeOverried = 2
Order = INV_NO
ตาราง INV_DTL
BufferModeOverried = 4
Order = INV_NO
ตาราง CUSTOMER
Order = CUST_ID
ตาราง PRODUCT
Order = PROD_ID

สร้างฟอร์มตามตัวอย่าง
c9306.gif (10708 bytes)
        6. ทำการสร้าง Command Button ตัวแรกแล้วกำหนด property ดังนี้
Caption = เพิ่มใบส่งสินค้า
Name = CmdAppend
Click Event ป้อนคำสั่งดังนี้

thisform.lNew = .T.
sele inv_head
go bott
nInv_No = inv_head.inv_no + 1
INSERT INTO INV_HEAD (inv_no,date) ;
VALUES (nInv_no,date())
with thisform
.txtDate.Enabled = .T.
.txtCust_id.Enabled = .T.
.txtDate.setfocus
.cmdAppend.Enabled = .F.
.cmdChange.Enabled = .F.
.cmdSave.Enabled = .T.
.cmdCancel.Enabled = .T.
.Grid1.Enabled = .T.
.Grid1.Column1.Text1.Enabled = .F.
.Grid1.Column5.Text1.Enabled = .F.
.cmdAppendItem.Enabled = .T.
.cmdDeleteItem.Enabled = .T.
.refresh
endwith

7. ทำการสร้าง Command Button ตัวที่สองแล้วกำหนด property ดังนี้
Caption = แก้ไขใบส่งสินค้า
Name = CmdChange
Click Event ป้อนคำสั่งดังนี้

thisform.lNew = .F.
with thisform
.txtDate.Enabled = .T.
.txtCust_id.Enabled = .T.
.txtDate.setfocus
.cmdAppend.Enabled = .F.
.cmdChange.Enabled = .F.
.cmdSave.Enabled = .T.
.Grid1.Enabled = .T.
.Grid1.Column1.Text1.Enabled = .F.
.Grid1.Column5.Text1.Enabled = .F.
.cmdAppendItem.Enabled = .T.
.cmdDeleteItem.Enabled = .T.
.refresh
endwith

8. ทำการสร้าง Command Button ตัวที่สามแล้วกำหนด property ดังนี้
Caption = บันทึกใบส่งสินค้า
Name = CmdSave
Enabled = .F.
Click Event ป้อนคำสั่งดังนี้

sele inv_head
=tableupdate(.F.)
sele inv_dtl
=tableupdate(.T.)
sele inv_head
with thisform
.txtDate.Enabled = .F.
.txtCust_id.Enabled = .F.
.combo1.setfocus
.cmdAppend.setfocus
.cmdAppend.Enabled = .T.
.cmdChange.Enabled = .T.
.cmdSave.Enabled = .F.
.cmdCancel.Enabled = .F.
.cmdAppendItem.Enabled = .F.
.cmdDeleteItem.Enabled = .F.
.Grid1.Enabled = .F.
.refresh
endwith

9. ทำการสร้าง Command Button ตัวที่สี่แล้วกำหนด property ดังนี้
Caption = ยกเลิก
Name = CmdCancel
Enabled = .F.
Click Event ป้อนคำสั่งดังนี้

sele inv_head
=tablerevert(.T.)
sele inv_dtl
=tablerevert(.T.)
sele inv_head
if eof() .and. Thisform.lNew
GO BOTT
endif
with thisform
.txtDate.Enabled = .F.
.txtCust_id.Enabled = .F.
.combo1.setfocus
.cmdAppend.setfocus
.cmdAppend.Enabled = .T.
.cmdChange.Enabled = .T.
.cmdSave.Enabled = .F.
.cmdCancel.Enabled = .F.
.cmdAppendItem.Enabled = .F.
.cmdDeleteItem.Enabled = .F.
.refresh
endwith

10. ให้คุณทำการลากฟิลด์ใน Data Environment ของตาราง INV_HEAD แล้วนำมาว่างไว้ที่ฟอร์ม โดยทำการลากมาทีละฟิลด์ เริ่มจาก INV_NO, DATE, CUST_ID
11. ต่อจากนั้นให้ลากฟิลด์ NAME ที่ตาราง CUSTOMER แล้วมาวางไว้บนฟอร์ม ทำการตกแต่งตามชอบใจ แล้วทำการกำหนด Properties ของแต่ละ object
txtInv_no กำหนด property ดังนี้
Enabled = .F.
txtDate กำหนด property ดังนี้
Enabled = .F.
Format = E
txtCust กำหนด property ดังนี้
Enabled = .F.
ป้อนคำสั่งที่ Valid Event ดังนี้
=SEEK(this.Value,”Customer”)
thisform.refresh
txtName กำหนด property ดังนี้
Enabled = .F.

12. ต่อจากนั้นให้ลากฟิลด์ NAME ที่ตาราง CUSTOMER แล้วมาวางไว้บนฟอร์ม กำหนด property ดังนี้
Enabled = .F.
13. ให้ไปที่ Data Environment แล้วทำการลากตาราง INV_DTL นำมาวางไว้บนฟอร์ม คุณก็จะได้ กริดของตาราง INV_DTL  แล้วกำหนด property ของ กริดดังนี้
AllowHeaderSizing = .F.
AllowRowSizing = .F.
DeleteMark = .F.
Enabled = .F.
ScrollBars = 2
SplitBar = .F.
14. ตอนนี้คุณก็จะได้กริดมาอยู่บนฟอร์มแล้ว แต่ column ในกริดยังไม่เป็นฟิลด์ที่เราต้องการ ฉะนั้นเราจะทำการจัดการกับมันก่อน สิ่งที่เราต้องการให้มีอยู่บนกริดจะประกอบไปด้วย รหัสสินค้า(PROD_ID), ชื่อสินค้า(NAME), จำนวน(QUANTITY), ราคาต่อหน่วย(UNITPRICE), รวมจำนวนเงิน(QUANTITY * UNITPRICE)

ลบคอลัมน์ออกจากกริด
        15. ทำการลบคอลัมน์ที่ไม่ต้องการออกก่อน โดยการคลิ๊กปุ่มขวาที่กริดแล้วเลือก Edit จากนั้นให้คลิ๊กที่ ab| ของคอลัมน์ INV_NO จากนั้นก็ทำการกดปุ่ม Del ที่ keyboard โปรแกรมจะถามว่า Remove column and all contained objects? ให้กดปุ่ม Yes

เพิ่มคอลัมน์ในกริด
        16. ให้คุณทำการคลิกเมาส์ที่ฟอร์มหนึ่งครั้งเพื่อออกจากการ Edit กริดก่อน แล้วทำการคลิ๊กเมาส์ปุ่มขวาที่กริดอีกครั้ง เลือก Properties แล้วกำหนด
ColumnCount = 5
17. มาถึงตรงนี้คุณก็จะได้คอลัมน์จำนวน 5 คอลัมน์ สำรวจว่าแต่ละคอลัมน์มีอะไรบ้าง
COLUMN2 -> ControlSource = inv_dtl.prod_id
COLUMN3 -> ControlSource = inv_dtl.quantity
COLUMN4 -> ControlSource = inv_dtl.unitprice
COLUMN1 -> ControlSource = (none)
COLUMN5 -> ControlSource = (none)
18. ให้ทำการเข้าไปที่ property ของ COLUMN1 แล้วกำหนดดังนี้
ControlSource = product.name
ColumnOrder = 2
19. ให้ทำการเข้าไปที่ property ของ COLUMN2 แล้วกำหนดดังนี้
ControlSource = inv_dtl.quantity * inv_dtl.unitprice

สร้าง combobox เพื่อใช้ในการเลือกใบ invoice มาแสดง
20. ให้ทำการสร้าง Combobox ขึ้นมา 1 ตัวแล้วนำไปวางไว้ใกล้ๆกับ texInv_no แล้วกำหนด  property ดังนี้
High = 25
RowSource = inv_head
RowSourceType = 2
Width = 20
Click Event ป้อนคำสั่ง Thisform.Refresh

21. การสร้าง Command Button ขึ้นมาสองตัว  แล้วกำหนด property ดังนี้
ตัวแรก กำหนด property ดังนี้
Caption = เพิ่มรายการสินค้า
Enabled = .F.
Name = CmdAppendItem
FontName = MS Sans Serif
Click Event ป้อนคำสั่ง
sele inv_dtl
INSERT INTO inv_dtl (inv_no) ;
VALUES (inv_head.Inv_no)
go bott
with thisform.grid1
.column2.setfocus
.refresh
endwith

ตัวที่สอง กำหนด property ดังนี้
Caption = ลบรายการสินค้า
Enabled = .F.
Name = CmdDeleteItem
FontName = MS Sans Serif
Click Event ป้อนคำสั่ง
sele inv_dtl
delete
sele inv_head
thisform.combo1.setfocus
thisform.grid1.column2.setfocus
thisform.refresh

คำนวณผลรวมของใบส่งของ
        22. ให้คุณทำการสร้าง Text Box ขึ้นมาสำหรับแสดงผลรวมของใบส่งของ แล้วกำหนด property ดังนี้
Enabled = .F.
Inputmark = 999,999,999.99
Left = 423
Top = 300
23. ทำการสร้าง method ขึ้นมา โดยคลิ๊กที่ เมนู Form แล้วเลื่อก New Method… ทำการป้อนชื่อเมธอตว่า InvoiceTotal กดปุ่ม Add แล้วกดปุ่ม Close
ต่อจากนั้นทำการป้อนคำสั่งของ เมธอต Form1 -> InvoiceTotal ดังนี้
Select Inv_dtl
Calculate Sum(Inv_dtl.Quantity*Inv_dtl.UnitPrice) ;
For Inv_dtl.inv_no = Thisform.txtinv_no.value ;
To Thisform.text1.value
Select Inv_head
* หมายเหตุ ในส่วนของ เมธอตนี้คุณจะเพิ่มคำสั่งในการคำนวณอื่นๆก็ได้แล้วแต่ความต้องการ
24. ทำการป้อนคำสั่งทึ่ Grid1 ในส่วนของเมธอต Refresh
=Thisform.InvoiceTotal()
25. ทำการป้อนคำสั่งทึ่ Grid1 -> Column3 -> Text1 ในส่วนของเมธอต LostFocus
Local nChange
nChange = Getfldstate(“Quantity”,”Inv_dtl”)
IF nChange # 1 .and. nChange # 3
=Thisform.InvoiceTotal()
ENDIF
25. ทำการป้อนคำสั่งทึ่ Grid1 -> Column3 -> Text1 ในส่วนของเมธอต LostFocus
Local nChange
nChange = Getfldstate(“Unitprice”,”Inv_dtl”)
IF nChange # 1 .and. nChange # 3
=Thisform.InvoiceTotal()
ENDIF

เมื่อคุณกำหนดเสร็จเรียบร้อยก็ทำการ Save แล้ลองเรียกโปรแกรมดูคุณก็จะเข้าใจหลักการของการทำฟอร์มแบบหนึ่งต่อหลาย (one to meny)

ลากแล้ววาง (Drag & Drop)
ตั้งแต่เริ่มมีโปรแกรม Windows เกิดขึ้นมา เราก็ได้รู้จักคำว่า Drag & Drop กันอยู่เสมอ ซึ่งก็คือการลากวัตถุหนึ่งจากที่หนึ่งไปวาง ณ. ตำแหน่งที่ต้องการ สำหรับโปรแกรม Visual FoxPro ก็ได้บรรจุคำสั่งประเภทนี้ไว้ให้ด้วยเหมือนกัน โดยที่วิธีการทำนั้นก็ขึ้นอยู่กับว่าเราทำกับคอนโทรลประเภทใด สำหรับตัวอย่างแรกที่จะนำเสนอต่อไปนี้จะเป็นการ ลากแล้วว่าแบบประถม โดยจะทำการลากจาก คอนโทรล textbox ไปที่ textbox อีกตัวหนึ่ง ดังนี้

1. ให้คุณทำการสร้างฟอร์มขึ้นมาโดยทำการคลิ๊กที่แท๊บ Documents แล้วเลือก Form แล้วทำการคลิ๊กที่ปุ่ม New แล้วเลือก New Form
2. ทำการคลิ๊กขวาที่ฟอร์มแล้วเลือกเมนู Data Environment… เลือกแฟ้มข้อมูล CUSTOMER แล้วคลิ๊กที่ปุ่ม Add จากนั้นคลิ๊กที่ปุ่ม Close
3. ทำการสร้าง TextBox ขึ้นมา 1 ตัว โดยการคลิ๊กที่ TextBox ใน Form Control แล้วก็มาทำการคลิ๊กที่ฟอร์ม
ทำการป้อนคำสั่งของ   Event Method ของ Text1->DragDrop ดังนี้
LPARAMETERS oSource, nXCoord, nYCoord
This.Value = oSource.Value
4. ทำการสร้าง Grid ขึ้นมา โดยคลิ๊กเมาส์ที่แฟ้ม Customer ใน Data Environment แล้วลากมาไว้ในฟอร์ม คุณก็จะได้กริดของ แฟ้ม Customer
ทำการป้อนคำสั่งของ   Event Method ของ Grid1->Column1->Text1->MouseDown ดังนี้
LPARAMETERS nButton, nShift, nXCoord, nYCoord
This.Drag(1)
5. จากนั้นก็กดปุ่ม Ctrl-E เพื่อทำการ Save ฟอร์มแล้วก็ Run ฟอร์ม

จากตัวอย่างข้างต้นเราจะเห็นว่า DragDrop Event จะเป็นตัวรับค่าที่ได้จากการ Drop ส่วน การกำหนดให้ object ตัวใดสามารถทำการ Drag ได้นั้นเราจะป้อนคำสั่งไว้ที่ MouseDown Event โดยใช้คำสั่ง Drag(1) เป็นตัวกำหนด