Hướng dẫn dùng java学习 JavaScript
About Us Show
Website đã được tạo ra từ tháng 3 năm 2014 bởi một nhóm lập trình viên và tác giả đến từ Việt Nam. Hiện tại dự án hỗ trợ 5 ngôn ngữ, bao gồm Tiếng Anh, tiếng Pháp, tiếng Đức, tiếng Nga và tiếng Việt. Một vài thành viên sáng lập tới từ Giacat.vn Donate Buymeacoffee With the The rest of this section shows you how to accomplish some common table-related tasks. Here are the topics this section covers:
Creating a Simple TableTry this:
The table in String[] columnNames = {"First Name", "Last Name", "Sport", "# of Years", "Vegetarian"}; Its data is initialized and stored in a two-dimensional Object array: Object[][] data = { {"Kathy", "Smith", "Snowboarding", new Integer(5), new Boolean(false)}, {"John", "Doe", "Rowing", new Integer(3), new Boolean(true)}, {"Sue", "Black", "Knitting", new Integer(2), new Boolean(false)}, {"Jane", "White", "Speed reading", new Integer(20), new Boolean(true)}, {"Joe", "Brown", "Pool", new Integer(10), new Boolean(false)} }; Then the Table is constructed using these data and columnNames: JTable table = new JTable(data, columnNames); There are two
The advantage of these constructors is that they are easy to use. However, these constructors also have disadvantages:
If you want to get around these restrictions, you need to implement your own table model, as described in Creating a Table Model. Adding a Table to a ContainerHere is typical code for creating a scroll pane that serves as a container for a table: JScrollPane scrollPane = new JScrollPane(table); table.setFillsViewportHeight(true); The two lines in this snippet do the following:
The scroll pane automatically places the table header at the top of the viewport. The column names remain visible at the top of the viewing area when the table data is scrolled. If you are using a table without a scroll pane, then you must get the table header component and place it yourself. For example: container.setLayout(new BorderLayout()); container.add(table.getTableHeader(), BorderLayout.PAGE_START); container.add(table, BorderLayout.CENTER); Setting and Changing Column WidthsBy default, all columns in a table start out with equal width, and the columns automatically fill the entire width of the table. When the table becomes wider or narrower (which might happen when the user resizes the window containing the table), all the column widths change appropriately. When the user resizes a column by dragging its right border, then either other columns must change size, or the table's size must change. By default, the table's size remains the same, and all columns to the right of the drag point resize to accommodate space added to or removed from the column to the left of the drag point. To customize initial column widths, you can invoke TableColumn column = null; for (int i = 0; i < 5; i++) { column = table.getColumnModel().getColumn(i); if (i == 2) { column.setPreferredWidth(100); //third column is bigger } else { column.setPreferredWidth(50); } } As the preceding code shows, each column in a table is represented by a When the user explicitly resizes columns, the columns' preferred widths are set such that the user-specified sizes become the columns' new current widths. However, when table itself is resized — typically because the window has resized —; the columns' preferred widths do not change. Instead, the existing preferred widths are used to calculate new column widths to fill the available space. You can change a table's resize behavior by invoking
User SelectionsIn its default configuration, a table supports a selection that consists of one or more rows. The user can select a contiguous range of rows or an arbitrary set of rows. The last cell that the user indicated gets a special indication; in the Metal look and feel, the cell is outlined. This cell is known as the lead selection; it is sometimes called "the cell with the focus" or "the current cell". The user uses the mouse and/or keyboard to make selections, as described in the following table:
To see how selections work, click the Launch button to run This example program presents the familiar table, and allows the user to manipulate certain JTable options. There is also a text pane that logs selection events. In the screenshot below, a user has run the program, clicked in the first row, then control-clicked in the third row. Notice the outline around the last cell clicked; this is how the Metal look and feel highlights the lead selection. Under "Selection Mode" there are a set of radio buttons. Click the one labelled "Single Selection". Now you can only select one row at a time. If you click on the "Single Interval Selection" radio button, you can select a set of rows that must be contiguous. All of the radio buttons under
"Selection Mode" invoke Returning to
NOTE: If you clear all three check boxes (setting all three bound properties to You may notice that the "Cell Selection" check box is disabled in multiple interval selection mode. This is because cell selection is not supported in this mode in the demo. You can specify selection by cell in multiple interval selection mode, but the result is a table that does not produce useful selections. You may also notice that changing any of the three selection options can affect the others. This is because allowing both row selection and column selection is exactly the same as enabling
cell selection. NOTE: Setting To
retrieve the current selection, use String.format("Lead Selection: %d, %d. ", table.getSelectionModel().getLeadSelectionIndex(), table.getColumnModel().getSelectionModel().getLeadSelectionIndex()); User selections generate a number of events. For information on these, refer to How to Write a List Selection Listener in the Writing Event Listeners lesson. NOTE: Selection data actually describes selected cells in the "view" (table data as it appears after any sorting or filtering) rather than in the table model. This distinction does not matter unless your viewed data has been rearranged by sorting, filtering, or user manipulation of columns. In that case, you must convert selection coordinates using the conversion methods described in Sorting and Filtering. Creating a Table ModelEvery table object uses a table model object to manage the actual table data. A table model object must implement the The new AbstractTableModel() { public String getColumnName(int col) { return columnNames[col].toString(); } public int getRowCount() { return rowData.length; } public int getColumnCount() { return columnNames.length; } public Object getValueAt(int row, int col) { return rowData[row][col]; } public boolean isCellEditable(int row, int col) { return true; } public void setValueAt(Object value, int row, int col) { rowData[row][col] = value; fireTableCellUpdated(row, col); } } As the preceding code shows, implementing a table model can be simple. Generally, you implement your table model in a subclass of the Your model might hold its data in an array, vector, or hash map, or it might get the data from an outside source such as a database. It might even generate the data at execution time. This
table is different from the
See below the code taken from
public TableDemo() { ... JTable table = new JTable(new MyTableModel()); ... } class MyTableModel extends AbstractTableModel { private String[] columnNames = ...//same as before... private Object[][] data = ...//same as before... public int getColumnCount() { return columnNames.length; } public int getRowCount() { return data.length; } public String getColumnName(int col) { return columnNames[col]; } public Object getValueAt(int row, int col) { return data[row][col]; } public Class getColumnClass(int c) { return getValueAt(0, c).getClass(); } /* * Don't need to implement this method unless your table's * editable. */ public boolean isCellEditable(int row, int col) { //Note that the data/cell address is constant, //no matter where the cell appears onscreen. if (col < 2) { return false; } else { return true; } } /* * Don't need to implement this method unless your table's * data can change. */ public void setValueAt(Object value, int row, int col) { data[row][col] = value; fireTableCellUpdated(row, col); } ... } Listening for Data ChangesA table model can have a set of listeners that are notified whenever the table data changes. Listeners are instances of import javax.swing.event.*; import javax.swing.table.TableModel; public class SimpleTableDemo ... implements TableModelListener { ... public SimpleTableDemo() { ... table.getModel().addTableModelListener(this); ... } public void tableChanged(TableModelEvent e) { int row = e.getFirstRow(); int column = e.getColumn(); TableModel model = (TableModel)e.getSource(); String columnName = model.getColumnName(column); Object data = model.getValueAt(row, column); ...// Do something with the data... } ... } Firing Data Change EventsIn order to fire data change events the table model must know how to construct a If
Concepts: Editors and RenderersBefore you go on to the next few tasks, you need to understand how tables draw their cells. You might expect each cell in a table to be a component. However, for performance reasons, Swing tables are implemented differently. Instead, a single cell renderer is generally used to draw all of the cells that contain the same type of data. You can think of the renderer as a configurable ink stamp that the table uses to stamp appropriately formatted data onto each cell. When the user starts to edit a cell's data, a cell editor takes over the cell, controlling the cell's editing behavior. For example, each cell in the # of Years column in To choose the renderer that displays the cells in a column, a table first determines whether you specified a renderer for that particular column. If you did not, then the table invokes the table model's
Cell editors are chosen using a similar algorithm. Remember that if you let a table create its own model, it uses Keep in mind that although renderers determine how each cell or column header looks and can specify its tool tip text, a renderer does not handle events. If you need to pick up the events that take place inside a table, the technique you use varies by the sort of event you are interested in:
The next few sections tell you how to customize display and editing by specifying renderers and editors. You can specify cell renderers and editors either by column or by data type. Using Custom RenderersThis section tells you how to create and specify a cell renderer. You can set a type-specific cell renderer using the It is easy to customize the text or image rendered by the default renderer, static class DateRenderer extends DefaultTableCellRenderer { DateFormat formatter; public DateRenderer() { super(); } public void setValue(Object value) { if (formatter==null) { formatter = DateFormat.getDateInstance(); } setText((value == null) ? "" : formatter.format(value)); } } If extending In the
snapshot of public class ColorRenderer extends JLabel implements TableCellRenderer { ... public ColorRenderer(boolean isBordered) { this.isBordered = isBordered; setOpaque(true); //MUST do this for background to show up. } public Component getTableCellRendererComponent( JTable table, Object color, boolean isSelected, boolean hasFocus, int row, int column) { Color newColor = (Color)color; setBackground(newColor); if (isBordered) { if (isSelected) { ... //selectedBorder is a solid border in the color //table.getSelectionBackground(). setBorder(selectedBorder); } else { ... //unselectedBorder is a solid border in the color //table.getBackground(). setBorder(unselectedBorder); } } setToolTipText(...); //Discussed in the following section return this; } } Here is the code from
table.setDefaultRenderer(Color.class, new ColorRenderer(true)); To specify a cell-specific renderer, you need to define a TableCellRenderer weirdRenderer = new WeirdRenderer(); table = new JTable(...) { public TableCellRenderer getCellRenderer(int row, int column) { if ((row == 0) && (column == 0)) { return weirdRenderer; } // else... return super.getCellRenderer(row, column); } }; Specifying Tool Tips for CellsBy default, the tool tip text displayed for a table cell is determined by the cell's renderer. However, sometimes it can be simpler to specify tool tip text by overriding To add a tool tip to a cell using its renderer, you first need to get or create the cell renderer. Then, after making sure the rendering component is a An example of setting tool tips for cells is in The source code is in
//Set up tool tips for the sport cells. DefaultTableCellRenderer renderer = new DefaultTableCellRenderer(); renderer.setToolTipText("Click for combo box"); sportColumn.setCellRenderer(renderer); Although the tool tip text in the previous example is static, you can also implement tool tips whose text changes depending on the state of the cell or program. Here are a couple ways to do so:
An example of adding code to a cell renderer is in
public class ColorRenderer extends JLabel implements TableCellRenderer { ... public Component getTableCellRendererComponent( JTable table, Object color, boolean isSelected, boolean hasFocus, int row, int column) { Color newColor = (Color)color; ... setToolTipText("RGB value: " + newColor.getRed() + ", " + newColor.getGreen() + ", " + newColor.getBlue()); return this; } } Here is an example of what the tool tip looks like: You can specify tool tip text by overriding The cells with tool tips are in the Sport and Vegetarian columns. Here is a picture of its tool tip: Here is the code from
JTable table = new JTable(new MyTableModel()) { //Implement table cell tool tips. public String getToolTipText(MouseEvent e) { String tip = null; java.awt.Point p = e.getPoint(); int rowIndex = rowAtPoint(p); int colIndex = columnAtPoint(p); int realColumnIndex = convertColumnIndexToModel(colIndex); if (realColumnIndex == 2) { //Sport column tip = "This person's favorite sport to " + "participate in is: " + getValueAt(rowIndex, colIndex); } else if (realColumnIndex == 4) { //Veggie column TableModel model = getModel(); String firstName = (String)model.getValueAt(rowIndex,0); String lastName = (String)model.getValueAt(rowIndex,1); Boolean veggie = (Boolean)model.getValueAt(rowIndex,4); if (Boolean.TRUE.equals(veggie)) { tip = firstName + " " + lastName + " is a vegetarian"; } else { tip = firstName + " " + lastName + " is not a vegetarian"; } } else { //another column //You can omit this part if you know you don't //have any renderers that supply their own tool //tips. tip = super.getToolTipText(e); } return tip; } ... } The code is fairly straightforward, except perhaps for the call to
Specifying Tool Tips for Column HeadersYou can add a tool tip to a column header by setting the tool tip text for the table's An example of using the same tool tip text for all column headers
is in table.getTableHeader().setToolTipText( "Click to sort; Shift-Click to sort in reverse order");
You will see the tool tips when you mouse over any column header except for the first two. No tool tips were supplied for the name columns since they seemed self-explanatory. Here is a picture of one of the column header tool tips: The following code implements the tool tips. Basically, it creates a subclass of protected String[] columnToolTips = { null, // "First Name" assumed obvious null, // "Last Name" assumed obvious "The person's favorite sport to participate in", "The number of years the person has played the sport", "If checked, the person eats no meat"}; ... JTable table = new JTable(new MyTableModel()) { ... //Implement table header tool tips. protected JTableHeader createDefaultTableHeader() { return new JTableHeader(columnModel) { public String getToolTipText(MouseEvent e) { String tip = null; java.awt.Point p = e.getPoint(); int index = columnModel.getColumnIndexAtX(p.x); int realIndex = columnModel.getColumn(index).getModelIndex(); return columnToolTips[realIndex]; } }; } }; Sorting and FilteringTable sorting and filtering is managed by a sorter object. The easiest way to provide a sorter object is to set JTable table = new JTable(); table.setAutoCreateRowSorter(true); This action defines a row sorter that is an instance of
To have more control over sorting, you can construct an instance of TableRowSorter
Comparator This example is fairly simplistic; more typically, a To determine which
For more sophisticated kinds of sorting, subclass To specify the sort order and sort precedence for columns, invoke
List In addition to reordering
the results, a table sorter can also specify which rows will be displayed. This is known as filtering. In the following example code, you explicitly create a sorter object so you can later use it to specify a filter: MyTableModel model = new MyTableModel(); sorter = new TableRowSorter Then you filter based on the current value of a text field: private void newFilter() { RowFilter In a subsequent example, When a table uses a sorter, the data the users sees may be in a different order than that specified by the data model, and may not include all rows specified by the data model. The data the user actually sees is known as the view, and has its
own set of coordinates. NOTE: When using a sorter, always remember to translate cell coordinates. The following example brings together the ideas discussed in this section.
If the user clicks twice on the second column, the fourth row becomes the first row — but only in the view: As previously noted, the text the user enters in the "Filter Text" text field defines a filter that determines which rows are shown. As with sorting, filtering can cause view coordinates to diverge from model coordinates: Here is the code that updates the status field to reflect the current selection: table.getSelectionModel().addListSelectionListener( new ListSelectionListener() { public void valueChanged(ListSelectionEvent event) { int viewRow = table.getSelectedRow(); if (viewRow < 0) { //Selection got filtered away. statusText.setText(""); } else { int modelRow = table.convertRowIndexToModel(viewRow); statusText.setText( String.format("Selected Row in view: %d. " + "Selected Row in model: %d.", viewRow, modelRow)); } } } ); Using a Combo Box as an EditorSetting up a combo box as an editor is simple, as the following example shows. The bold line of code sets up the combo box as the editor for a specific column. TableColumn sportColumn = table.getColumnModel().getColumn(2); ... JComboBox comboBox = new JComboBox(); comboBox.addItem("Snowboarding"); comboBox.addItem("Rowing"); comboBox.addItem("Chasing toddlers"); comboBox.addItem("Speed reading"); comboBox.addItem("Teaching high school"); comboBox.addItem("None"); sportColumn.setCellEditor(new DefaultCellEditor(comboBox)); Here is a picture of the combo box editor in use: The preceding code is from
Using Other EditorsWhether you are setting the editor for a single column of cells (using the What if you want to specify an editor other than a
text field, check box, or combo box? As Your cell editor class needs to define at least two methods — Here is a picture of a table with a dialog that serves, indirectly, as a cell editor. When the user begins editing a cell in the Favorite Color column, a button (the true cell editor) appears and brings up the dialog, with which the user can choose a different color. You can run Here is the code, taken from
public class ColorEditor extends AbstractCellEditor implements TableCellEditor, ActionListener { Color currentColor; JButton button; JColorChooser colorChooser; JDialog dialog; protected static final String EDIT = "edit"; public ColorEditor() { button = new JButton(); button.setActionCommand(EDIT); button.addActionListener(this); button.setBorderPainted(false); //Set up the dialog that the button brings up. colorChooser = new JColorChooser(); dialog = JColorChooser.createDialog(button, "Pick a Color", true, //modal colorChooser, this, //OK button handler null); //no CANCEL button handler } public void actionPerformed(ActionEvent e) { if (EDIT.equals(e.getActionCommand())) { //The user has clicked the cell, so //bring up the dialog. button.setBackground(currentColor); colorChooser.setColor(currentColor); dialog.setVisible(true); fireEditingStopped(); //Make the renderer reappear. } else { //User pressed dialog's "OK" button. currentColor = colorChooser.getColor(); } } //Implement the one CellEditor method that AbstractCellEditor doesn't. public Object getCellEditorValue() { return currentColor; } //Implement the one method defined by TableCellEditor. public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { currentColor = (Color)value; return button; } } As you can see, the code is pretty simple. The only part that is a bit tricky is the call to Using an Editor to Validate User-Entered TextIf a cell's default editor allows text entry, you get some error checking for free if the cell's type is specified as something other than The automatic checking of user-entered strings occurs when the default editor attempts to create a new instance of the class associated with the cell's column. The default editor creates this instance using a constructor that takes a If you like having a text field as the editor for a cell, but want to customize it — perhaps to check user-entered text more strictly or to react differently when the text is invalid — you can change the cell editor to use a formatted text field. The formatted text field can check the value either continuously while the user is typing or after the user has indicated the end of typing (such as by pressing Enter). The following code, taken from a demo named
The following code makes the formatted text field the editor for all columns that contain data of type table.setDefaultEditor(Integer.class, new IntegerEditor(0, 100)); The The override of Printing
try { if (! table.print()) { System.err.println("User cancelled printing"); } } catch (java.awt.print.PrinterException e) { System.err.format("Cannot print %s%n", e.getMessage()); } Invoking
MessageFormat header = new MessageFormat("Page {0,number,integer}"); try { table.print(JTable.PrintMode.FIT_WIDTH, header, null); } catch (java.awt.print.PrinterException e) { System.err.format("Cannot print %s%n", e.getMessage()); } For more sophisticated printing applications, use
Examples that Use TablesThis table lists examples that use
|