JTable: ข้อมูลหลายชนิดใน Column เดียวกันสมชัย หลิมศิโรรัตน์ 7/05/2546 : มอบบทความนี้ให้เว็บ Jarticles.com
นำไปเผยแพร่ |
เกริ่นนำการใช้ javax.swing.JTable ในภาษา Java เก็บข้อมูลเป็นตารางนั้น นับว่าสะดวกมาก แต่ JTable ที่ทาง Sun ออกแบบไว้นั้นก็มีข้อจำกัด คือ จะต้องใส่ข้อมูลชนิดเดียวกัน ไว้ในคอลลัมน์เดียวกัน ข้อจำกัดอันนี้ ทำให้การสร้างโปรแกรม ที่แสดง Property ของข้อมูล คือ คอลลัมน์ที่แสดงค่าจะมีค่าได้หลากหลายชนิด ทำให้เรานำเอา JTable มาใช้งานตรงๆเลยไม่ได้ เมื่อหลายปีก่อน ผมได้พยายามทำความเข้าใจการทำงานของ JTable และคิดหาวิธีแก้ไขข้อจำกัดอันนี้ขึ้นมา แต่ก็ไม่ได้เผยแพร่ให้ใครได้รู้ จนมาถึงวันนี้ ผมได้มีโอกาสเข้าไปคุยในเว็บบอร์ด หลายแห่ง และพบว่ามีหลายคนที่มีประสพการณ์ดีๆ และมีอุดมการณ์ที่จะเผยแพร่ความรู้ โดยไม่ได้รับค่าตอบแทนใดๆ ผมจึงอยากจะเผยแพร่ความรู้อันนี้ของผมบ้าง แต่ก่อนจะเขียนบทความนี้ขึ้นมา ผมก็ได้สำรวจและพบบทความหนึ่งที่แก้ปัญหานี้ด้วยเหมือนกัน อยู่ที่ JavaWorld แต่วิธีการต่างจากของผม ซึ่งผมก็ได้เข้าไปคุยแลกเปลี่ยนความคิดเห็นในเว็บบอร์ดที่ Narisa.com เพื่อให้หลายๆคนได้วิจารณ์ว่าวิธีการที่ผมใช้ กับวิธีการของ JavaWorld มีข้อดีและข้อเสียอย่างไร ก็ได้รับความเห็นว่า วิธีของ JavaWorld นั้นยังมีข้อจำกัดอยู่ในกรณีที่มีข้อมูลมากๆ หลายๆ row อาจจะทำให้ประสิทธิภาพการทำงานตกลงได้ ซึ่งวิธีการของผม จะไม่มีปัญหาตรงนี้ ผมจึงคิดว่าควรจะเขียนเรื่องนี้เป็นบทความ ให้ทุกคนได้อ่านกัน พื้นฐานความรู้เนื่องจากบทความนี้ต้องการเน้นเฉพาะเรื่องการแก้ปัญหา กรณีข้อมูลหลายชนิดใน column เดียวของ JTable เท่านั้น ผู้อ่านควรจะมีพื้นความรู้การใช้งาน JTable เป็นอย่างดีมาก่อนแล้ว หากท่านยังไม่มี แต่สนใจเรื่องนี้ ผมขอแนะนำให้อ่านวิธีการใช้งาน JTable ในหัวข้อ How to use Tables จากหนังสือ The Java Tutorial ซึ่งเป็นการรวมหนังสือ 3 เล่มไว้ที่เดียวกัน และมีไฟล์ให้ดาวโหลดมาอ่านได้ฟรีด้วยครับ ข้อจำกัดการใช้งาน JTable นั้น ถูกออกแบบมาในลักษณะของ MVC (Model-View-Controller) ซึ่งมี javax.swing.table.TableModel เป็น interface สำหรับให้เราสร้าง model ของข้อมูลแบบของเราเองได้ ข้อจำกัดของ JTable ก็เกิดจากการที่ TableModel นั้น ถูกออกแบบมาให้มี method getColumnClass(int col) เพื่อใช้ตรวจสอบชนิดของข้อมูลในแต่ละ column แต่ไม่มี method ใดๆสำหรับตรวจสอบชนิดของข้อมูลในแต่ละ cell หรือ row เลย การ implement ใน javax.swing.table.AbstractTableModel ซึ่งเป็นคลาสแม่ของ javax.swing.table.DefalutTableModel นั้น เขียน method getColumnClass ไว้ดังนี้ public Class getColumnClass(int columnIndex) { return Object.class; } เราจะไม่สามารถใช้ method นี้แก้ปัญหาใดๆได้ เพราะ parameter ของ method นี้มีเพียงตัวเดียวคือหมายเลข column หากต้องการระบุว่าเป็นข้อมูลที่ cell ไหน จะตัองระบุทั้ง column และ row ใน JTable จะมี method getCellEditor(int row, int col) และ getCellRenderer(int row, int col) ซึ่งเป็น method สำหรับหาตัววาด/แก้ไข cell นั้นๆมา ใน method ทั้งสองอันนี้ จะเรียกใช้ method getColumnClass(int col) เพื่อหาชนิดของข้อมูลมา แล้วใช้ method getDefaultEditor/Renderer เพื่อหา Editor/Renderer มา นี่คือ source code บางส่วนของ JTable คัดลอกมาเฉพาะส่วนที่เกี่ยวข้อง public Class getColumnClass(int column) { return getModel().getColumnClass(convertColumnIndexToModel(column)); } public TableCellEditor getCellEditor(int row, int column) { TableColumn tableColumn = getColumnModel().getColumn(column); TableCellEditor editor = tableColumn.getCellEditor(); if (editor == null) { editor = getDefaultEditor(getColumnClass(column)); } return editor; } public TableCellRenderer getCellRenderer(int row, int column) { TableColumn tableColumn = getColumnModel().getColumn(column); TableCellRenderer renderer = tableColumn.getCellRenderer(); if (renderer == null) { renderer = getDefaultRenderer(getColumnClass(column)); } return renderer; } ทางแก้ในบทความของ JavaWorld นั้นแก้ปัญหานี้ด้วยการ override method getCellEditor ของ JTable ให้ไปค้นหา Editor ตาม row ที่กำหนด ซึ่งจะมี RowEditorModel ที่สร้างขึ้นมาใหม่ ให้เป็นตัวจัดการเก็บ Editor ไว้และเพิ่มเติม method สำหรับ set/getRowEditorModel เข้ามา แต่วิธีการของผมนั้น ผมจะเพิ่ม method getCellClass(int row, int column) ซึ่งมี row เพิ่มเข้ามา และใน JTable จะ override ให้ getCellEditor และ getCellRenderer ให้เรียกใช้ getCellClass ตัวนี้แทน ดังนี้ public class CellIndependentTable extends JTable { // ... constructor public Class getCellClass(int row,int col) { Object obj = getModel().getValueAt(row,col); public TableCellEditor getCellEditor(int row, int column) { จะทำให้ได้ชนิดของข้อมูลจริงๆที่ตำแหน่ง cell นั้นๆเลย และจะทำให้เราสามารถแสดงข้อมูลได้อย่างอิสระ คือ เป็นไปตามชนิดของข้อมูลจริงที่อยู่ใน cell นั้นๆ ตัวอย่างผมได้ทำตัวอย่างการใช้งานเป็น Property Editor ขึ้นมาซึ่งเป็นเป้าหมายหลักของปัญหานี้ โดย source code ทั้งหมดนั้นประกอบด้วยหลายไฟล์ เพราะผมได้สร้าง Editor/Renderer ของข้อมูลหลายๆแบบไว้ด้วย จึงขอไม่นำมาลงในบทความนะครับ กรุณาดาวโหลดตามลิ้งค์ท้ายบทความ นะครับ Editor/Renderer ที่สร้างไว้ได้แก่
หมายเหตุ: เนื่องจากผมคิดว่า การแสดงผล cell ที่แก้ไขไม่ได้ ควรจะแสดงสีที่จางลง ทำให้อาจจะไม่ตรงกับความต้องการของผู้ใช้ในบางกรณีครับ จากโปรแกรมตัวอย่าง org.vsl.examples.TestCITable การนำ CellIndependentTable มาใช้งานก็ง่ายๆคือ สร้าง TableModel สำหรับข้อมูลที่ต้องการ แล้วส่งให้ตอนที่สร้างตาราง เช่น table = new CellIndependentTable(new DefaultTableModel(data1,colname1)); ตัวแปร data1 และ colname1 นั้นเก็บข้อมูล และชื่อคอลลัมน์ตามที่ต้องการ ซึ่งภาษา Java มีความสามารถสูงมากตรงที่เราสามารถสร้าง array ของ Object ใดๆได้ ผลลัพธ์ที่ได้ ดังภาพแรก เป็นการแสดงให้เห็นว่าสามารถใช้ Renderer แสดงของข้อมูลต่างชนิดกันได้ ซึ่งในตัวอย่างนี้มีข้อมูลชนิดต่างๆคือ
เมื่อคลิกเพื่อแก้ไขข้อมูล ก็จะมีตัว Editor มาโต้ตอบกับเรา ขึ้นอยู่กับชนิดของข้อมูลในช่องนั้นๆ เช่น ภาพที่สองเลือกแก้ไข field ข้อมูล Single ซึ่งเป็นข้อมูลแบบ Boolean ผมได้ใช้ JComboBox ให้เลือกคำว่า True/False ภาพที่สาม เลือกแก้ไข File ซึ่งเป็นข้อมูลแบบที่ผมสร้างเอง คือ class FileName โดย Editor จะผสมระหว่าง JTextField กับ JButton คือจะป้อนชื่อไฟล์เองหรือ กดที่ปุ่มเพื่อเปิดหน้าต่าง JFileChooser ก็ได้นะครับ ภาพสุดท้าย จะเป็นการแสดงให้เห็นว่า เราสามารถใช้ table ตัวเดิม รองรับข้อมูลแบบอื่นๆได้ทันที เพียงแค่สั่ง setTableModel() ใหม่ให้กับตัว table นั้น ซึ่งผมได้ทำปุ่ม "Change Data" ไว้ เมื่อกด ก็จะเปลี่ยนข้อมูลที่ผมเตรียมไว้ แสดงให้เห็นว่า ข้อมูลจะเป็นอะไรก็ได้ อยู่ที่ cell ไหนก็ได้ เหมือน Spread Sheet เลย API Documentนอกจากนี้ ผมได้พยายามเขียน API Document เป็นภาษาไทย เพื่อให้ท่านอ่านและทำความเข้าใจได้สะดวกขึ้นด้วย ขอขอบคุณ
สรุปเทคนิคของผมนี้ จะช่วยให้เราสร้างโปรแกรมที่ทำงานกับข้อมูลแบบตารางได้อย่างไร้ขีดจำกัดอีกต่อไป ซึ่งอาจจะนำไปปรับปรุงทำเป็นโปรแกรม Spread Sheet ก็ได้ นอกจากนี้ในโปรแกรมตัวอย่างนี้ยังมีเทคนิคการสร้าง Editor/Renderer แบบต่างๆอีกมากมายนะครับ ไฟล์
|
since September
2002 Copyright © 2002-2004 Somchai LIMSIRORATANA. All rights reserved. |