ในตอนที่แล้วเราได้พูดถึง Excel VBA พื้นฐาน กันแบบสุดๆ กันไปแล้ว คราวนี้เรามาดูเรื่อง VBA Object ซึ่งเป็นหัวใจสำคัญของ Excel VBA กันเพื่อเป็นพื้นฐานก่อนที่จะเขียน Loop ในตอนถัดไปครับ ซึ่งในตอนนี้จะเป็นทฤษฎีเยอะหน่อย ขอให้อดทนนิดนึงนะ
สารบัญ
VBA Object Hierarchy
ในความเป็นจริงแล้ว VBA นั้นมอง Excel เป็น Object หรือวัตถุแบบนึง ซึ่งประกอบไปด้วยวัตถุย่อยๆ อีกหลายๆ ตัว ซึ่งตัวที่เป็นตัวหลักที่สุดก็คือตัวโปรแกรม Excel เอง เรียกว่า Application Object และภายใต้มันก็ประกอบไปด้วย Object อีกหลายตัวมากๆ แต่ตัวที่เรารู้จักกันเป็นอย่างดีก็คือ Workbook Object (แต่ละไฟล์) ซึ่งย่อยลงไปอีกก็จะเป็น Worksheet Object (แต่ละชีท) และ Range Object (แต่ละ range/cell) ตามลำดับ ซึ่งเรื่องนี้คือหัวใจสำคัญของ VBA เลยล่ะ
โชคดีที่มีคนทำ Diagram Object ที่ใช้บ่อยออกมาเป็นภาพที่ดูง่ายให้แล้วดังนี้
ซึ่งถ้าแบบเต็มๆ จริงๆ แล้ว Object จะมีเยอะมากๆ ดังนี้ (อาจมีอีกด้วยซ้ำ เพราะภาพนี้ก็เก่าแล้ว ช๊อคแปป…)
Tips : ถ้าอยากดูทั้งหมดจริงๆ สามารถกดปุ่ม F2 ใน VBE เพื่อเปิดดู Object Browser ได้ด้วยนะ
Collections และ Object ลูก
ถ้าสังเกตดีๆ แล้วล่ะก็ตัว Object เองก็จะมีบางอันมีทั้งแบบพหูพจน์และแบบเอกพจน์ด้วย เช่น
- Workbooks/Workbook
- Worksheets/Worksheet
- Charts/Chart
- Names/Name
- และอีกมากมาย
ตัวที่เป็นพหูพจน์เรียกว่า Collection ซึ่งก็คือ Object ที่เก็บ Object ย่อยที่มีลักษณะแบบเดียวกันไว้ด้วยกัน
เช่น Workbooks คือ Collection ที่รวบรวม Workbook แต่ละไฟล์เอาไว้ ซึ่งถ้าดูใน Model แล้วมันก็จะสามารถมีตัวย่อยคือ Worksheets ซึ่งก็คือ Collection ที่รวบรวม Worksheet แต่ละแผ่นเอาไว้ ซึ่งก็จะเก็บตัวย่อยคือ Range เอาไว้ได้ ดังนั้นถ้าจะไล่จากต้นสุดไปถึง Cell B3 ที่อยู่ใน Sheetที่ชื่อว่า แผนก ซึ่งเป็นชีทที่ 2 ของไฟล์ A จะต้องไล่ประมาณนี้
Application -> Workbooks ซึ่งมี Workbook ชื่อว่า A -> Worksheets ซึ่งมี Worksheet ชื่อว่า แผนก -> Range B3
ซึ่งการอ้างอิง Object เรามีหลักการดังนี้
- การอ้างอิง Object ลูก เราจะใช้ . (จุด) เป็นตัวเชื่อมไปเรื่อยๆ
- การอ้างอิง Collection จะใช้ Collection_name(“Object_name”) หรือ Collection_name(Index_number) ซึ่ง index_number คือลำดับของ object นั้น เช่นถ้าอยู่ชีทที่ 2 ใน Workbook ก็เป็นลำดับ 2
สรุปแล้วเราจะอ้างอิงได้หลายแบบเลย ดังนี้
Application.Workbooks("A.xlsx").Worksheets("แผนก").Range("B3")
Application.Workbooks("A.xlsx").Worksheets(2).Range("B3")
'assume ว่า sheet ที่ต้องการวางอยู่ลำดับที่ 2
Application.Workbooks(1).Worksheets(2).Range("B3")
'assume ว่าเป็น Workbook ที่เปิดอยู่ไฟล์แรก
Properties and Methods
แต่ละ Object มีสิ่งสำคัญอยู่ 2 อย่าง คือ Property กับ Method ซึ่งต่างกันดังนี้
- Property = สิ่งที่ใช้อธิบายลักษณะของ Object นั้นๆ (คิดซะว่าเป็น Adjective) เช่น จำนวน ขนาด สี ค่าต่างๆ
- Method = Action ที่ใช้กระทำเกี่ยวกับ Object นั้นๆ (คิดซะว่าเป็น Verb) เช่น เพิ่มจำนวน ลบ Copy Paste เป็นต้น
ซึ่งทั้งสองตัวใช้ในรูปแบบที่เหมือนกันเลย ก็คือ ใช้อยู่หลังจุด เช่น
- Object.Property เช่น Worksheets.Count เพื่อนับว่าใน Collection Worksheets นั้นมีทั้งหมดกี่ชีท
- Object.Method เช่น Range(“A1:C3”).Clear เพื่อ Clear ทั้ง Content และ Format ของ Range(“A1:C3”)
เราจะรู้ได้ยังไงว่า Object นั้นๆ มี Property หรือ Method อะไร?
เราสามารถพิมพ์ชื่อ Object แล้วตามด้วย . แล้วมันจะมี Tool Tips ขึ้นมาช่วยเอง เช่น
- ส่วนตัวที่เป็นรูปมือชี้ๆ (ชี้อธิบายลักษณะ) นั่นคือ Property
- ตัวที่เป็นสีเขียวๆ พุ่งๆ (มี Action) นั่นคือ Method
คิดว่าแบบนี้น่าจะดีขึ้นแล้วเนอะ (แต่ก็ยังเยอะจนเลือกไม่ค่อยถูกอยู่ดี 555)
ละไว้ในฐานที่(โปรแกรม)เข้าใจ
สังเกตมั้ยว่า ตอนที่เราเขียน Code ในตอนที่แล้ว เราเขียนแค่ Range(“A1”)=10 แค่นี้มันก็ทำงานได้แล้ว ไม่ได้เขียน Object ตั้งแต่ Application ด้วยซ้ำ ไม่เห็นจะได้เขียน Property/Method อะไรซักอย่างเลย
ทั้งนี้เป็นเพราะการเขียน Code VBA เราสามารถเขียนแบบย่อได้ ซึ่งมันจะ Assume ตามค่า Default ให้เราหลายๆ อย่างดังนี้
- Application Object ไม่จำเป็นต้องใส่ก็ได้ เพราะมันเข้าใจอยู่แล้วว่าทำงานด้วยโปรแกรม Excel
- Workbook
- กรณีเขียน Code ใน Module : หากไม่ระบุ Workbook มันจะทำงานสั่งไปที่ตัวที่ Active อยู่
- กรณีเขียน Code ใน This Workbook : หากไม่ระบุ Workbook จะหมายถึง Workbook ที่มี Code นั้นอยู่
- Worksheet
- กรณีเขียน Code ใน Module : หากไม่ระบุ Worksheet มันจะทำงานสั่งไปที่ตัวที่ Active อยู่
- กรณีเขียน Code ใน Sheet : หากไม่ระบุ Worksheet จะหมายถึง Worksheet ที่มี Code นั้นอยู่
- Default Property
- Object แต่ละอันก็จะมี Default Property อยู่ เช่น Range ก็มีตัว .Value เป็นตัว Default ให้
จากรูปจะเห็นว่าเราเขียน Code ได้หลายที่เลย ทั้งที่ Sheet/ThisWorkbook/Module ซึ่งในตอนที่แล้วเราเขียนใน Module ไป มันก็จะเรียกไปที่ Active Workbook/ Active Sheet ให้ และจะอ้างอิงไปถึง Property Value ให้โดยอัตโนมัติ
ดังนั้นการเขียนว่า
inputName=Range("B1")
สามารถเขียนเต็มๆ ได้ว่า
inputName = Application.Workbooks("vba-basic.xlsm").Worksheets("Sheet1").Range("B1").Value
แล้วอะไรคือ Active? แล้ว Selection ล่ะ?
การจะเข้าใจเรื่องนี้ได้ดี จะต้องเข้าใจความแตกต่างของคำที่คล้ายๆ กันด้วย นั่นคือ Active/Activate vs Selection/Select
สมมติว่าเราเลือกข้อมูลใน Excel ด้วยการลากคลุมพื้นที่ B2:D4 แบบนี้เราเรียกว่ามีการเลือก (Select) Range B2 ถึง D4 แต่ว่า Cell Range ที่มีการเลือกอันแรกสุดจะกลายเป็น Active Cell แค่อันเดียว
หรือกรณีเลือกพื้นที่หลายอัน ด้วยการกด Ctrl ค้างไว้แล้วเลือก ก็จะมี Active Cell อันเดียว
เวลาเราเขียนสูตรหรือพิมพ์ค่าคงที่ลงไป แล้วกด Enter ปกติมันก็จะใส่สูตรลงไปใน Active Cell แค่ตัวเดียวเท่านั้น แล้ว Active Cell ก็จะเลื่อนไป Selection ช่องถัดไปให้โดยอัตโนมัติ (เพราะกด Enter)
Tips : ถ้าเราจะใส่ทุกช่องที่เลือก (Selection ทั้งหมด) พร้อมกันก็ต้องกด Ctrl+Enter แทน
สรุป
มีประเด็นสำคัญ 2 อัน คือ
- Selection สามารถมีได้มากกว่า 1 อัน แต่ Active มีได้แค่อันเดียว
ซึ่งใน VBA ก็จะมี Method ที่เกี่ยวข้องกับ 2 ตัวนี้ นั่นก็คือ Range.Select กับ Range.Activate นั่นเอง
เดี๋ยวลองมาลองทำสอบ Code กัน
ถ้าเราลองสั่ง Activate Object มันจะทำการ Select Object นั้นไปด้วยในตัวเลย แต่ก็จะ Select แค่ตัวเดียวเท่านั้นนะ
Worksheets("Sheet2").Activate
Tips : เราสามารถ Run Code VBA ได้ด้กวยการกดปุ่ม Run หรือปุ่ม F5 ก็ได้ ไม่จำเป็นต้อง Assign Button เสมอไป
แบบนี้ก็จะทำการ Activate Sheet ที่ชื่อว่า Sheet 2 ซึ่งสามารถทำได้โดยไม่ต้อง Select ไว้ก่อนเลย
แต่ถ้าใช้กับ Range ได้เช่นกัน แบบนี้ก็จะ Activate Range B5 ของ Active Sheet (ซึ่งของผมอยู่ที่ Sheet2)
Range("B5").Activate
คราวนี้ลอง Select บ้าง
ถ้า Select Cell เดียว Cell นั้นก็จะ Active ไปด้วยเช่นกัน (เหมือนกับ Activate ก็จะ Select ไปด้วย)
แต่ถ้า Select เป็น Range ปกติจะ Active ที่ Cell ซ้ายบน ยกเว้นว่าจะระบุชัดเจนไปเลยว่าจะให้ตัวไหน Active
Range("B3:D7").Select
Range("C6").Activate
จะเห็นว่าเราสามารถ Select Range เป็นช่วงได้ และสามารถ Activate Cell ภายในนั้นได้ (ถ้า Activate นอก Range เดิม Selection ก็จะหายไป)
หวังว่าเพื่อนๆ จะเข้าใจความหมายของ Select กับ Activate มากขึ้นแล้วนะครับ
อย่างไรก็ตาม การจะทำอะไรกับ Cell เราก็ไม่จำเป็นต้อง Select หรือ Activate มันก่อนเสมอไปนะ เช่นที่เราทำในบทความก่อนหน้า เราก็ยัดค่าลง Value ลง Range ได้เลย เช่น Range(“B5”)=10 แบบนี้ ก็ไม่ได้ Select หรือ Activate ก่อนเลย
แต่ข้อดีของ Select กับ Activate นั้นทำให้สามารถอ้างอิงได้ด้วยคำว่า Selection หรือ ActiveCell, ActiveSheet, ActiveWorkbook เป็นต้น เช่น
Range("B6").Select
Selection = 10
'หรือแบบข้างล่างก็ได้
Selection.Value = 10
ActiveCell = 10
ActiveCell.Value = 10
อย่างไรก็ตามเราจะไม่สามารถไป Select/Activate Range ใน Sheet อื่น หากว่าไม่ได้ Select/Activate Sheet นั้นๆ ก่อน เช่น
ถ้า Select Sheet ก่อนแบบนี้จะไม่มีปัญหา
Sub Macro3()
Worksheets("Sheet1").Select
Range("E5:G8").Select
End Sub
ตอนต่อไป
สำหรับบทความนี้ก็น่าจะเนื้อหาเริ่มเยอะแล้ว เดี๋ยวจะปวดหัวกันเกินไป ตอนนี้เราก็ได้เรียนรู้เรื่อง Object ต่างๆ ไปพอสมควรแล้ว เดี๋ยวตอนหน้าก็ถึงเวลาที่จะเรียนรู้เรื่อง Loop กันซักทีครับ