Flash

ความจริงแล้ว ฟังก์ชั่นนี้มีมาตั้งแต่ AIR 1.0 แล้วครับ แต่ผมเพิ่งค้นพบว่ามันมี!!!

จากกระทู้ Tutorial ที่ ไทยแฟลชเดฟจิ้มที่นี่ )
พี่คีได้นำเอาคำสั่งจาก AIR มาสอนให้ลองเล่นกันครับ
และบทความนี้ จะนำเอา Tutorial จากลิงค์ มาดัดแปลงเล็กน้อย
และแจกจ่ายไปให้เล่นกันอีกที

เอ บางคนอาจจะงง AIR นี่มันอะไร(วะ)
อะ เดี๋ยวผมจะเกริ่นนำให้ฟังคร่าวๆ

AIR หรือ Adobe Integrated Runtime
คือแพล็ตฟอร์มหนึ่งของ Flash ที่รันเป็นโปรแกรมบน Desktop ครับ
หรืออธิบายให้ง่ายลงไปอีกคือ Flash ในภาคที่เป็น Desktop Application* นั่นเอง
(*แปล Desktop Application = โปรแกรมที่รันบนเครื่อง ไม่ได้รันบนเว็บ เช่น Microsoft Word เป็นต้น)

ด้วยความที่มันป็น Desktop Application มันก็เลยมีคำสั่งแปลกๆ ใหม่ๆ
ที่ช่วยให้ทำงานบน Desktop Application ได้ดีขึ้น อย่างเช่น การเขียนไฟล์ลงเครื่อง (AIR 1.5)
การเข้าถึงไฟล์บนเครื่อง การนำไฟล์/ข้อความจากคลิปบอร์ด เป็นต้น

รวมไปถึง การลากไฟล์ ลงไปในโปรแกรมที่เขียนจาก AIR ด้วย
(คือ อย่างผมเนี่ย เวลาเปิดไฟล์ ผมขี้เกียจกด File > Open ผมก็จัดการ ลากไฟล์ใส่โปรแกรมเลย
ง่ายกว่าอีก ในกรณีที่เปิดโฟลเดอร์ทิ้งไว้อยู่แล้ว)

ซึ่งการจะเขียน AIR นั้นจะต้องมีโปรแกรม Flash CS 3 ขึ้นไป
แต่สำหรับ Flash CS 3 นั้น จะต้องไปอัพเดตเป็นเวอร์ชั่น 9.0.2 ก่อน
แล้วลงตัว Add-on เพิ่มเข้าไปให้สามารถสร้างไฟล์ AIR ได้
แต่ถ้าใครใช้ Flash CS 4 ก็สบายหน่อย เพราะเลือก New Flash File (Adobe AIR) ได้เลยจ้ะ

หรือถ้าฝ่ายโปรแกรมเมอร์ที่ทำงากับ Flex อยู่แล้ว
ก็สามารถเลือกคอมไพล์จาก Fex Builder ให้ทำเป็น AIR ได้ทันทีเช่นกัน

สรุปว่า AIR สามารถสร้างได้จาก 3 ทางคือ
- Flash IDE หรือ Flash CS 3, Flash CS 4
- FlexSDK/AIRSDK (หาโหลดได้ฟรี จากเว็บของ Adobe)
- Flex Builder 3

อ้อ.. ใช้ ActionScript 3.0 ในการเขียนเท่านั้นครับ

เกริ่นนำไปบ้างแล้ว มาเข้าสู่เนื้อหาจริงๆ กันเถอะครับ (เดี๋ยวยาว)
เอาล่ะ จาก Tutorial (ลิงค์อยู่ด้านบน) ผมจึงเอามาองทำเป็น แกเลอรี่รูป (เขียนทับศัพท์ถูกมั้ยนี่)
แบบง่ายๆ ดู เผื่อใครปิ๊งไอเดียจะเอาไปพัฒนาต่อ ก็ไม่ว่ากันนะจ๊ะ

หลักการทำงานของโปรแกรมคือ
1. มีการลากไฟล์เข้ามาในพื้นที่ที่กำหนด
2. โปรแกรมตรวจจับได้ว่ามีเหตุการณ์การลากไฟล์เข้ามา (NativeDragEvent.NATIVE_DRAG_ENTER)
3. ตรวจสอบนามสกุลไฟล์ว่าตรงตามที่เราอนุญาตหรือไม่ (ใช่ครับ เรากำหนดได้ว่า จะรับไฟล์อะไร ไม่รับอะไร)
4. เมื่อมีการปล่อยเมาส์ (คือทิ้งไฟล์ลงพื้นที่ที่กำหนด) ก็จะทำการเพิ่มไฟล์เหล่านั้น ลงไปใน TileList
5. TileList ทำการแสดงชื่อ และรูปภาพขนาดเล็ก (จริงๆ คือรูปขนาดเท่าของเดิมแต่โดนบีบให้อยู่ในพื้นที่น่ะครับ)
6. รอจับเหตุการณ์ ถ้ามีการดับเบิ้ลคลิกที่ Thumbnail ให้แสดงรูปใหญ่
7. โดยมี MovieClip ขนาดใหญ่ + UILoader รอรับพาธรูปอยู่แล้ว

คลาสที่ใช้เพิ่มเติม (Import)
แน่นอนครับว่า มันไม่ได้ใช้คลาสพื้นฐานที่ไม่ต้อง import ดังนั้นเราจึงต้อง import เข้ามาให้โปรแกรมรู้จัก
คลาสที่จำเป็นครับ
- flash.desktop.NativeDragManager => เป็นคลาสที่จัดการทุกอย่างที่เกี่ยวกับการลาก-วางไฟล์ครับ
- flash.desktop.Clipboard => คลาสตัวนี้จะจำว่า มีไฟล์อะไรที่กำลังโดนลากอยู่บ้าง
- flash.desktop.ClipboardFormats => คลาสรูปแบบของข้อมูลที่เราต้องการจากคลิปบอร์ดครับ
- flash.events.NativeDragEvent => Event ที่เกี่ยวกับการลาก-วางไฟล์
- fl.events.ListEvent => Event ที่เกี่ยวกับ List ทั้งหลาย เช่น คลิกวัตถุในลิสต์, ข้อมูลในลิสต์เปลี่ยน ฯลฯ
- com.korstudio.utils.EasyFilter => เอ่อ... คลาสขี้เกียจส่วนตัวของผมเองครับ (แนบมาในไฟล์ rar แล้ว)

สิ่งที่ต้องวาด/เตรียม
- พื้นที่สำหรับวางไฟล์ที่ลาก
  วาดเป็นขนาดเท่าไหร่ก็ได้ครับ แล้วทำเป็น MovieClip ตั้ง Instance name ว่า dropArea_mc
- ที่แสดง Thumbnail
  เปิดหน้าต่าง Components (Ctrl+F7) แล้วลาก TileList จากหมวด User Interface มาวางครับ
- ที่แสดงภาพใหญ่
  สร้าง MovieClip มาอันหนึ่ง ด้านในให้วาดกรอบสี่เหลี่ยมใหญ่ๆ ไว้
  แล้วก็ลาก Component ที่ชื่อ UILoader มาวางครับ ตั้ง Instance Name ว่า loader
  จากนั้นวาดรูปปุ่มปิด ทำเป็น Button แล้วตั้ง Instance Name ว่า close_btn
  ตามรูปด้านล่างนี้ครับ

  จากนั้นก็ตั้ง Instace name ให้ Symbol ตัวนี้ว่า bigPanel ครับ (เอามาวางบน Stage ก่อนนะครับ แล้วค่อยตั้ง)

เริ่มทำเลยดีกว่าครับ

1. ขั้นแรก เราก็ต้อง import คลาสที่จำเป็นก่อน (ตามที่ลิสต์ไว้ด้านบนเลย)

import flash.desktop.NativeDragManager;
import flash.events.NativeDragEvent;

import fl.events.ListEvent;

import flash.desktop.Clipboard;
import flash.desktop.ClipboardFormats;

import com.korstudio.utils.EasyFilter;

2. สร้างตัวแปร allowedFileExtension เพื่อกำหนดว่า เราจะอนุญาตให้ลากไฟล์อะไรเข้ามาบ้าง
    ในตัวอย่างนี้อนุญาตไฟล์ jpg png gif และ swf ครับ

var allowedFileExtension:Array = ["jpg","png","swf","gif"];

3. กำหนดให้ bigPanel (กรอบแสดงภาพใหญ่) ซ่อนตัวก่อนครับ อย่าเพิ่งแสดงให้ใครเห็น

 bigPanel.visible = false;

4. เพิ่ม event listener ให้กับตัว dropArea_mc (พื้นที่สำหรับวางไฟล์ที่ลาก) ครับ 3 อย่างคือ
    NATIVE_DRAG_ENTER => เมื่อมีการลากไฟล์เข้ามายังพื้นที่
    NATIVE_DRAG_EXIT => เมื่อคนลากไฟล์เกิดเปลี่ยนใจ เอาไฟล์ที่ลากออกไปนอกกรอบ
    NATIVE_DRAG_DROP => หลังจากคนลากไฟล์ตกลงปลงใจได้แล้ว ก็ปล่อยไฟล์ลงบนพื้นที่

dropArea_mc.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, onDragFileEnter);
dropArea_mc.addEventListener(NativeDragEvent.NATIVE_DRAG_EXIT, onDragFileExit);
dropArea_mc.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, onDropFile);

5. สังเกตว่า ใน event listener เรากำหนดชื่อฟังก์ชั่นไป 3 ฟังก์ชั่นคือ onDragFileEnter onDragFileExit
    และ onDropFile แต่ตอนนี้ยังไม่มีฟังก์ชั่นเหล่านี้จริงๆ ดังนั้น เราจึงต้องมาสร้างฟังก์ชั่นเหล่านี้เองครับ

function onDragFileEnter(event:NativeDragEvent):void{
  //ทำงานต่อเมื่อมีการลากไฟล์เข้ามาในพื้นที่ dropArea_mc
}
function onDragFileExit(event:NativeDragEvent):void{
  //ทำงานเมื่อมีการลากไฟล์ออกจากพื้นที่ dropArea_mc
}
function onDropFile(event:NativeDragEvent):void{
  //ทำงานต่อเมื่อมีการวางไฟล์ลงบนพื้นที่ dropArea_mc
}

6. ลุยทีละอย่างก่อน.. เริ่มที่ onDragFileEnter ครับ

function onDragFileEnter(event:NativeDragEvent):void{
  //สร้างตัวแปร file เพื่อเก็บรายชื่อไฟล์ที่ลากค้างไว้ โดยดึงมาจาก Clipboard
  var file:Array = event.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
  //เอาไฟล์แรกมาเช็คดูนามสกุลไฟล์ว่า อยู่ในรายการที่อนุญาตให้ใช้มั้ย
   //โดยส่งนามสกุลไฟล์ไปที่ฟังก์ชั่น checkExtension เพื่อตรวจเช็ค
   //ซึ่งฟังก์ชั่นดังกล่าวจะเช็คแล้วส่งผลการเช็คกลับมาเป็น true หรือ false ครับ

  if (checkExtension(file[0].extension)) {
    //ถ้านามสกุลไฟล์ อยู่ในลิสต์ที่อนุญาต.. ก็อนุญาตให้วางได้ทั้งหมด
    NativeDragManager.acceptDragDrop(dropArea_mc);
    //ขั้นนี้เป็นการใส่ฟิลเตอร์ Brightness ให้ dropArea_mc ครับ จะได้เห็นว่ามีการตอบสนอง
    EasyFilter.Brightness(dropArea_mc, -20);
  }else{
    //แต่ถ้าไม่.. ก็ให้ trace ออกมาว่า ไม่เอา
    trace("Not accept *."+file[0].extension);
  }

7. ถัดมาครับ มาทำที่ onDragFileExit ที่นี่ไม่มีอะไร นอกจากเอาฟิลเตอร์ออกครับ

function onDragFileExit(event:NativeDragEvent):void{
  //เมื่อมีการลากไฟล์ออกจาก dropArea_mc ก็ให้เอาฟิลเตอร์ออก
  EasyFilter.Remove(dropArea_mc);

8. และมาต่อที่ onDropFile ตรงนี้จะเยอะหน่อยครับ เพราะต้องจัดการนำไฟล์ไปลงที่ TileList ด้วย

function onDropFile(event:NativeDragEvent):void{
  //คนลากไฟล์วางไฟล์ลงมาในพื้นที่แล้ว
    //สร้างตัวแปร files เพื่อเก็บรายการไฟล์ที่ลากไว้อยู่จาก Clipbard ครับ

  var files:Array = event.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
  //วนลูปเพื่อนำไฟล์ไปใส่ใน TileList
  for(var i:int = 0; i < files.length; i++){
    //สร้างตัวแปรเพื่อเก็บค่าต่างๆ (อันนี้ผมว่าคงเดากันได้อยู่แล้ว)
    var fileName:String = files[i].name;
    var ext:String = fileName.substring(fileName.lastIndexOf(".")+1);
    //สร้างตัวแปรเก็บพาธเต็มของรูป แล้วทดสอบให้ trace ออกมาดู
    var nativePath:String = files[i].nativePath;
    trace(nativePath);
    //นำข้อมูลไปใส่ใน TileList (ชื่อไฟล์ และพาธรูปเพื่อแสดงรูป)
    picPanel.addItem({label: fileName, source: nativePath});
  }
  //ลบฟิลเตอร์ออก
  EasyFilter.Remove(dropArea_mc);

9. เก็บตกฟังก์ชั่นที่เหลือครับ คือฟังก์ชั่นที่ใช้เช็คนามสกุลไฟล์นั่นเอง

function checkExtension(ext:String):Boolean{
  //วนลูปจากอาร์เรย์ allowedFileExtension ที่เก็บนามสกุลไฟล์ไว้ครับ
  for(var n:String in allowedFileExtension){
    //แปลงนามสกุลที่ส่งมาเป็นพิมพ์เล็ก แล้วก็นำไปเช็คกับค่าในแต่ละตำแหน่งของอาร์เรย์
    //ถ้าตรงกัน ก็ให้หยุดลูปแล้วส่งไปว่า true
    if(ext.toLowerCase() == allowedFileExtension[n]){
      return true;
    }
  }
  //จนแล้วจนรอดก็ลูปไม่เจอนามสกุลไฟล์ที่ว่าเลย เอิ่ม งั้นก็ไม่อนุญาตนะ ส่งไปว่า false โลด
  return false;
}

10. กด Ctrl+Enter ทดสอบ
      ตอนนี้โปรแกรมพอจะทำงานได้บ้างแล้ว เหลือตรงที่ ดับเบิ้ลคลิกรูป Thumbnail แล้วแสดงรูปใหญ่ครับ

11. กลับมายังหน้าต่าง Actions เพิ่มบรรทัดนี้ลงไป หลังจากบรรทัดที่ addEventListener ของ 
      picPanel (ที่เป็น TileList) ครับ

picPanel.addEventListener(ListEvent.ITEM_DOUBLE_CLICK, onItemDoubleClick); 

12. แล้วก็สร้าง listener ต่อ

function onItemDoubleClick(event:ListEvent):void{
  //สั่งแสดงกรอบใหญ่
  bigPanel.visible = true;
  //แล้วสั่ง UILoader ให้โหลดรูป โดยใช้พาธจาก Thumbnail ที่เลือกอยู่
  bigPanel.loader.source = picPanel.selectedItem.source;
}

13. โค้ดทั้งหมดทั้งมวล จะได้ออกมาตามรูปนี้ครับ (บางจุดที่เห็นไม่เหมือนกันไม่ต้องตกใจครับ)

14. ทดสอบโปรแกรม โดยการลองลากไฟล์มาที่พื้นที่ที่กำหนด จากนั้นก็ลองดับเบิ้ลคลิกรูปเล็กดู

15. ในที่สุด ก็เสร็จสมบูรณ์ครับ เย้ 

แต่อย่าเพิ่งดีใจจนเกินไปนะครับ เพราะว่ามันเป็นเพียงแค่ ตัวอย่าง!!! (ผ่างงง)
หากนำไปใช้จริง เราต้องปรับปรุงอีกมากครับ แต่ก็คงไม่เกินความสามารถของพี่น้องแน่นอน

โหลดไฟล์ fla: ( จิ้มที่นี่ )
โหลดไฟล์ AIR ไปลองเล่น: ( จิ้มที่นี่ )