I'm having some trouble making JLabels and textFields appear on the JPanel.
If I put all of this code in the main method it works fine, however when I move the JLabels and TextFields into their own methods or classes the JPanel remains empty. The image I use is shown.
package gui;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
#SuppressWarnings("serial")
class ImagePanel extends JPanel {
private Image img;
public ImagePanel(String img) {
this(new ImageIcon(img).getImage());
}
public ImagePanel(Image img) {
this.img = img;
Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
setPreferredSize(size);
setMinimumSize(size);
setMaximumSize(size);
setSize(size);
setLayout(null);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, null);
}
}
public class EquippedInput {
private JPanel panel;
public static void main(String[] args){
ImagePanel panel = new ImagePanel(new ImageIcon("Images/Crusader Background.jpg").getImage());
JScrollPane scrollBar = new JScrollPane(panel,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
panel.setLayout(null);
JFrame frame = new JFrame();
frame.getContentPane().add(scrollBar);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1160, 1000);
frame.setVisible(true);
panel.setPreferredSize(new Dimension(1125, 1210));
scrollBar.getVerticalScrollBar().setUnitIncrement(20);
}
public EquippedInput() {
initialize();
}
private void initialize() {
/**
* Stats and slots labels.
*/
JLabel lblWeaponAttacksPerSecond = new JLabel("Weapon Attacks Per Second");
JLabel lblWeaponAttackSpeed = new JLabel("Attack Speed");
JLabel lblMainHand = new JLabel("Main Hand");
JLabel lblOffHand = new JLabel("Off Hand");
JLabel stats[] = {lblWeaponAttacksPerSecond, lblWeaponAttackSpeed};
JLabel slots[] = {lblMainHand, lblOffHand};
/**
* Place stats and slots labels.
*/
for (int i = 0; i < stats.length; i++) {
stats[i].setBounds(10, (40 + 30 * i), 200, 20);
panel.add(stats[i]);
}
for (int i = 0; i < slots.length; i++) {
slots[i].setBounds((220 + 70 * i), 10, 60, 20);
panel.add(slots[i]);
}
/**
* Text fields.
*/
JTextField textField0 = new JTextField();
JTextField textField1 = new JTextField();
JTextField mainHandTextField[] = {textField0, textField1};
/**
* Arrays of whether a stat can roll on an item. 1 = can roll. 0 = can't roll.
*/
int mainHandAvailableStats[] = {0, 1};
/**
* Text field builders, each loop is a single slot.
*/
for (int i = 0; i < mainHandTextField.length; i++) {
panel.add(mainHandTextField[i]);
if(mainHandAvailableStats[i] == 1) {
int textFieldVerticalPosition = 40 + 30 * i;
mainHandTextField[i].setBounds(220, textFieldVerticalPosition, 60, 20);
panel.add(mainHandTextField[i]);
}
}
}
}
The actual code has a lot more content for the JPanel, but this produces the exact same result.
I am going to have to explain this code and this answer later, but it shows:
Getting data from a text file and creating a table model from it
Creating and displaying a JTable with null cells opaque
Showing a background image in a JPanel
The data file is this:
Main_Hand Off_Hand Head Shoulder Neck
Weapon_Attacks_per_sec 5 null null null null
Attack_Speed 20 null null null null
Damage_% 30 null null null null
Min_Bonus_Damage 3 null null null null
Max_Bonus_Damage 40 null null null null
Min_Weapon_Damage 30 null null null null
Max_Weapon_Damage 80 null null null null
Strength 70 50 20 30 30
It must be named TableFunData.txt and be in the same directory/package as the code is in.
The code is:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Scanner;
import java.util.Vector;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
#SuppressWarnings("serial")
public class TableFun extends JPanel {
private static final String IMG_PATH = "https://upload.wikimedia.org/"
+ "wikipedia/commons/d/d1/Ozanne-Brest.jpg";
private JTable table = new JTable();
private BufferedImage img;
public TableFun(BufferedImage img, TableModel model) {
this.img = img;
table = new JTable(model);
table.setDefaultRenderer(Object.class, new MyCellRenderer());
table.setOpaque(false);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
table.setShowGrid(false);
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
setLayout(new BorderLayout());
add(scrollPane, BorderLayout.CENTER);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
Dimension superSize = super.getPreferredSize();
if (isPreferredSizeSet() || img == null) {
return superSize;
}
int supW = superSize.width;
int supH = superSize.height;
int imgW = img.getWidth();
int imgH = img.getHeight();
int w = Math.max(imgW, supW);
int h = Math.max(imgH, supH);
return new Dimension(w, h);
}
private class MyCellRenderer extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (column != 0) {
renderer.setHorizontalAlignment(JLabel.CENTER);
} else {
renderer.setHorizontalAlignment(JLabel.LEADING);
}
renderer.setOpaque(value != null);
return renderer;
}
}
private static void createAndShowGui() {
BufferedImage img = null;
try {
URL imageUrl = new URL(IMG_PATH);
img = ImageIO.read(imageUrl);
} catch (IOException e1) {
e1.printStackTrace();
System.exit(-1);
}
String dataPath = "TableFunData.txt";
DataIO dataIO = new DataIO(dataPath);
TableModel model = null;
try {
model = dataIO.createTableModel();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
JFrame frame = new JFrame("Table Fun");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new TableFun(img, model));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class DataIO {
private static final String NULL = "null";
private String dataPath;
public DataIO(String dataPath) {
this.dataPath = dataPath;
}
public TableModel createTableModel() throws IOException {
InputStream inputStream = getClass().getResourceAsStream(dataPath);
Scanner scanner = new Scanner(inputStream);
Vector<String> columnNames = new Vector<>();
Vector<Vector<Object>> data = new Vector<>();
while (scanner.hasNext()) {
String line = scanner.nextLine();
if (columnNames.size() == 0) {
columnNames = createColumnNames(line);
} else {
Vector<Object> dataRow = createDataRow(line);
data.add(dataRow);
}
}
if (scanner != null) {
scanner.close();
}
DefaultTableModel model = new DefaultTableModel(data, columnNames);
return model;
}
private Vector<String> createColumnNames(String line) {
String[] tokens = line.split("\\s+");
Vector<String> columnNames = new Vector<>();
columnNames.add(" "); // first name is blank
for (String token : tokens) {
if (!token.trim().isEmpty()) {
token = token.replace("_", " "); // add spaces
columnNames.add(token);
}
}
return columnNames;
}
private Vector<Object> createDataRow(String line) {
String[] tokens = line.split("\\s+");
Vector<Object> dataRow = new Vector<>();
for (String token : tokens) {
token = token.trim();
if (!token.isEmpty()) {
// first token is the title
if (dataRow.size() == 0) {
token = token.replace("_", " "); // add spaces
dataRow.add(token);
} else {
// if title already added
if (token.equalsIgnoreCase(NULL)) {
dataRow.add(null);
} else {
int value = Integer.parseInt(token);
dataRow.add(value);
}
}
}
}
return dataRow;
}
}
The GUI looks like:
Now for some explanation:
OK, what this code does:
First I use an external image, one that is freely available from Wikipedia / Wikimedia, so that my code can be run from any computer and demonstrate the use of images in a JPanel. The image path can be found here:
private static final String IMG_PATH = "https://upload.wikimedia.org/"
+ "wikipedia/commons/d/d1/Ozanne-Brest.jpg";
and it's used here to create an image:
URL imageUrl = new URL(IMG_PATH);
img = ImageIO.read(imageUrl);
Which is then drawn within the JPanel's paintComponent method:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
}
My code also extends JPanel as this gives my GUI programs much greater flexibility than they'd have if I extended JFrame:
public class TableFun extends JPanel {
I override the JPanel's getPreferredSize method so that it sizes to the image, unless it needs to be bigger. That's why I first get the super's preferred size, and try to make my GUI big enough to show the image, and bigger if it needs to be to show more components:
#Override
public Dimension getPreferredSize() {
Dimension superSize = super.getPreferredSize();
if (isPreferredSizeSet() || img == null) {
return superSize;
}
int supW = superSize.width;
int supH = superSize.height;
int imgW = img.getWidth();
int imgH = img.getHeight();
int w = Math.max(imgW, supW);
int h = Math.max(imgH, supH);
return new Dimension(w, h);
}
In order to simplify code, I try to separate code from data, and place my data inside of a text file. The DataIO class is a small utility class that exists to read in the text held by the file, and then to parse the data line by line to create and fill a DefaultTableModel object. Note that I get the file not as a "File" but rather as a class resource, since this way I can include it within the jar file if I desire to do so. I use a Scanner to read in each line, exactly as you'd do for a text file.
public TableModel createTableModel() throws IOException {
InputStream inputStream = getClass().getResourceAsStream(dataPath);
Scanner scanner = new Scanner(inputStream);
Once I get a line of text, I split it by white space, which creates an array of Strings with all the white space trimmed off:
String[] tokens = line.split("\\s+");
The JTable uses a table cell renderer called MyCellRenderer
table.setDefaultRenderer(Object.class, new MyCellRenderer());
that makes the cells opaque if they hold data, and non-opaque (clear) if they hold null values:
renderer.setOpaque(value != null);
I also make sure that the JTable itself, the JScrollPane and the scrollpane's viewport are all non-opaque, so that the image can show through:
table.setOpaque(false);
// ....
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
You mention a NPE being thrown, which likely means that your Java program is not finding the text file. Again it must be placed with your class files. You should create a text file with Eclipse in the same directory as your java file, name it precisely TableFunData.txt (spelling and capitalization matter), and when you're done, Eclipse should look something like:
where the code and the data text are seen in the same package using Eclipse's package explorer (highlighted in blue and red), and the code's package statement should show that it is in fact inside this package (in green).
Here is a simple implementation of JTable, as #Hovercraft Full Of Eels suggested.
Background colors are rendered based on data. 1 will cause background color to be blue, while 0 will render as red.
(The demo is based on https://docs.oracle.com/javase/tutorial/displayCode.html?code=https://docs.oracle.com/javase/tutorial/uiswing/examples/components/SimpleTableDemoProject/src/components/SimpleTableDemo.java )
public class TableDemo extends JPanel {
public TableDemo() {
super(new GridLayout(1,0));
String[] columnNames = {" ",
"Main Hand",
"Off Hand",
"Head",
"Shoulder",
"Neck"};
Object[][] data = {
{"Weapon Attacks Per Second", new Integer(1), new Integer(0), new Integer(0),new Integer(0),new Integer(0)},
{"Attack Speed", new Integer(1), new Integer(0), new Integer(1),new Integer(0),new Integer(0)},
{"Damage%", new Integer(1), new Integer(0), new Integer(0),new Integer(0),new Integer(0)},
{"Min Bonus Damage", new Integer(1), new Integer(0), new Integer(0),new Integer(1),new Integer(0)},
{"Max Bonus Damage", new Integer(1), new Integer(1), new Integer(0),new Integer(0),new Integer(0)},
{"Min Weapon Damage", new Integer(1), new Integer(0), new Integer(0),new Integer(1),new Integer(0)},
{"Max Weapon Damage", new Integer(1), new Integer(0), new Integer(1),new Integer(0),new Integer(0)},
};
final JTable table = new JTable(data, columnNames);
table.setPreferredScrollableViewportSize(new Dimension(600, 70));
table.getColumnModel().getColumn(1).setCellRenderer(new ColorRenderer());
table.getColumnModel().getColumn(2).setCellRenderer(new ColorRenderer());
table.getColumnModel().getColumn(3).setCellRenderer(new ColorRenderer());
table.getColumnModel().getColumn(4).setCellRenderer(new ColorRenderer());
table.getColumnModel().getColumn(5).setCellRenderer(new ColorRenderer());
//Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(table);
//Add the scroll pane to this panel.
add(scrollPane);
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("TableDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
TableDemo newContentPane = new TableDemo();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
}
class ColorRenderer extends DefaultTableCellRenderer {
public ColorRenderer() {
setOpaque(true); //MUST do this for background to show up.
}
#Override
public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected,
boolean hasFocus,int row, int column) {
if((int)value == 1) {
setBackground(Color.BLUE);
}else {
setBackground(Color.RED);
}
return this;
}
}
Related
Problem
So my program takes in a .csv file and loads the data and displays it. When data is loaded in, it creates a new JCheckBox for every column header there is in the data. How do I add an ActionListener such that when the user ticks/unticks any of the boxes, it should do a certain function?
When data is loaded in, it updates the JPanel by the code:
public void updateChecklistPanel(){
checklistPanel.removeAll();
checklistPanel.setLayout(new GridLayout(currentData.getColumnNames().length, 1, 10, 0));
for (String columnName : currentData.getColumnNames()){
JCheckBox checkBox = new JCheckBox();
checkBox.setText(columnName);
checklistPanel.add(checkBox);
}
checklistPanel.revalidate();
checklistPanel.repaint();
}
I also have the following at the bottom:
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == newDataFrameItem){
newFile();
System.out.println("New DataFrame Loaded in");
}
if (e.getSource() == loadDataFrameItem){
loadFile();
System.out.println(".csv Data loaded into DataFrame.");
}
if (e.getSource() == saveDataFrameItem){
System.out.println("Saved the data to a .csv file");
}
}
What I'm trying to do is that when a checkbox is unticked, it should hide a column in the JTable and when ticked, it should redisplay the column.
Current Solution
The solution that I have come up with is to make a variable allColumnHeaders that is an ArrayList of Strings. I then also have a variable shownColumnHeaders that is an ArrayList of Booleans. When the user wants to show/hide a column, the showColumn(String columnName) and hideColumn(String columnName) function finds the index of the column Name in allColumnHeaders and sets the Boolean value of the index in shownColumnHeaders to either true/false.
It the proceeds to create a new table model where the columns are only added if the Boolean value for that column is true. It will then set the model for the table to the new table model.
The code for the following is show below:
import java.awt.*;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
public class MRE extends JPanel {
private static JTable table;
private static ArrayList<String> allColumnHeaders = new ArrayList<>();
private static ArrayList<Boolean> shownColumnHeaders = new ArrayList<>();
private static void createAndShowGUI()
{
table = new JTable(5, 7);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );
JPanel buttons = new JPanel( new GridLayout(0, 1) );
for (int i = 0; i < table.getColumnCount(); i++) {
String column = table.getColumnName(i);
allColumnHeaders.add(column);
JCheckBox checkBox = new JCheckBox(column);
checkBox.addActionListener(event -> {
JCheckBox cb = (JCheckBox) event.getSource();
if (cb.isSelected()) {
System.out.println(checkBox.getText() + " is now being displayed");
showColumn(checkBox.getText());
} else {
System.out.println(checkBox.getText() + " is now being hidden");
hideColumn(checkBox.getText());
}
table.setModel(createTableModel());
});
checkBox.setSelected( true );
buttons.add( checkBox );
shownColumnHeaders.add(true);
}
JPanel wrapper = new JPanel();
wrapper.add( buttons );
JFrame frame = new JFrame("MRE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane, BorderLayout.CENTER);
frame.add(wrapper, BorderLayout.LINE_END);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static DefaultTableModel createTableModel(){
DefaultTableModel tableModel = new DefaultTableModel(0, 0);
String[] columnValues = new String[1];
for (int i = 0; i < shownColumnHeaders.size(); i++){
if (shownColumnHeaders.get(i)){
tableModel.addColumn(allColumnHeaders.get(i), columnValues);
}
}
return tableModel;
}
public static void showColumn(String columnName){
for (int i = 0; i < allColumnHeaders.size(); i++) {
if (allColumnHeaders.get(i).equals(columnName)){
shownColumnHeaders.set(i, true);
}
}
}
public static void hideColumn(String columnName){
for (int i = 0; i < allColumnHeaders.size(); i++) {
if (allColumnHeaders.get(i).equals(columnName)){
shownColumnHeaders.set(i, false);
}
}
}
public static void main(String[] args) throws Exception
{
SwingUtilities.invokeLater( () -> createAndShowGUI() );
}
}
Introduction
It took me a while, but I came up with the following JTable GUI. Here's the starting display.
Here's the GUI after I remove the item description.
Here's the GUI after I remove the item price.
Here's the GUI after I add the columns back.
Explanation
I created an Item class to hold one item.
I created an Inventory class to hold a List of Item instances and a String array of the column headers.
I created the JFrame and two JPanels. One JPanel holds the JTable and the other holds the JCheckBoxes. I used Swing layout managers to create the JPanels.
So far, so basic. Creating the JTable took a bit of effort. I wanted to display the item price as currency, but that wasn't important for this example GUI.
I created an ActionListener to add and remove columns from the JTable. I had to experiment a bit. The TableColumnModel addColumn method appends the column to the table.
I had to create a DisplayTableColumn class to hold a TableColumn and a boolean that tells me whether or not to display the TableColumn. I wound up removing all the columns from the JTable and adding all the columns back to the JTable so that I could maintain the column sequence. I probably ran 100 tests before I could get this code to work.
Code
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public class JCheckBoxTableGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new JCheckBoxTableGUI());
}
private final Inventory inventory;
private final InventoryTableModel tableModel;
private JFrame frame;
private JTable table;
public JCheckBoxTableGUI() {
this.tableModel = new InventoryTableModel();
this.inventory = new Inventory();
String[] columns = inventory.getTableHeader();
for (String column : columns) {
tableModel.addColumn(column);
}
List<Item> items = inventory.getInventory();
for (Item item : items) {
Object[] object = new Object[5];
object[0] = item.getItemNumber();
object[1] = item.getItemName();
object[2] = item.getItemDescription();
object[3] = item.getItemQuantity();
object[4] = item.getItemPrice();
tableModel.addRow(object);
}
}
#Override
public void run() {
frame = new JFrame("JCheckBox Table GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createTablePanel(), BorderLayout.CENTER);
frame.add(createSelectionPanel(), BorderLayout.AFTER_LINE_ENDS);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createTablePanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
table = new JTable(tableModel);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.getColumnModel().getColumn(0).setPreferredWidth(100);
table.getColumnModel().getColumn(1).setPreferredWidth(150);
table.getColumnModel().getColumn(2).setPreferredWidth(150);
table.getColumnModel().getColumn(3).setPreferredWidth(100);
table.getColumnModel().getColumn(4).setPreferredWidth(100);
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setPreferredSize(new Dimension(620, 300));
panel.add(scrollPane, BorderLayout.CENTER);
return panel;
}
private JPanel createSelectionPanel() {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JPanel innerPanel = new JPanel(new GridLayout(0, 1, 5, 5));
ColumnListener listener = new ColumnListener(this);
String[] columns = inventory.getTableHeader();
for (String column : columns) {
JCheckBox checkBox = new JCheckBox("Display " + column);
checkBox.addActionListener(listener);
checkBox.setActionCommand(column);
checkBox.setSelected(true);
innerPanel.add(checkBox);
}
panel.add(innerPanel);
return panel;
}
public JTable getTable() {
return table;
}
public JFrame getFrame() {
return frame;
}
public class ColumnListener implements ActionListener {
private final JCheckBoxTableGUI frame;
private final List<DisplayTableColumn> displayColumns;
public ColumnListener(JCheckBoxTableGUI frame) {
this.frame = frame;
this.displayColumns = new ArrayList<>();
TableColumnModel tcm = frame.getTable().getColumnModel();
for (int index = 0; index < tcm.getColumnCount(); index++) {
TableColumn tc = tcm.getColumn(index);
displayColumns.add(new DisplayTableColumn(tc, true));
}
}
#Override
public void actionPerformed(ActionEvent event) {
JCheckBox checkBox = (JCheckBox) event.getSource();
String column = event.getActionCommand();
TableColumnModel tcm = frame.getTable().getColumnModel();
for (int index = 0; index < displayColumns.size(); index++) {
DisplayTableColumn dtc = displayColumns.get(index);
if (dtc.isShowTableColumn()) {
tcm.removeColumn(dtc.getTableColumn());
}
}
int columnIndex = getColumnIndex(column);
displayColumns.get(columnIndex).setShowTableColumn(
checkBox.isSelected());
for (int index = 0; index < displayColumns.size(); index++) {
DisplayTableColumn dtc = displayColumns.get(index);
if (dtc.isShowTableColumn()) {
tcm.addColumn(dtc.getTableColumn());
}
}
frame.getFrame().pack();
}
private int getColumnIndex(String column) {
for (int index = 0; index < displayColumns.size(); index++) {
DisplayTableColumn dtc = displayColumns.get(index);
if (column.equals(dtc.getTableColumn().getHeaderValue())) {
return index;
}
}
return -1;
}
}
public class DisplayTableColumn {
private boolean showTableColumn;
private final TableColumn tableColumn;
public DisplayTableColumn(TableColumn tableColumn, boolean showTableColumn) {
this.tableColumn = tableColumn;
this.showTableColumn = showTableColumn;
}
public boolean isShowTableColumn() {
return showTableColumn;
}
public void setShowTableColumn(boolean showTableColumn) {
this.showTableColumn = showTableColumn;
}
public TableColumn getTableColumn() {
return tableColumn;
}
}
public class InventoryTableModel extends DefaultTableModel {
private static final long serialVersionUID = 1L;
#Override
public Class<?> getColumnClass(int columnIndex) {
if (columnIndex <= 2) {
return String.class;
} else if (columnIndex == 3) {
return Integer.class;
} else {
return Integer.class;
}
}
}
public class Inventory {
private final List<Item> inventory;
private final String[] tableHeader;
public Inventory() {
this.tableHeader = new String[] { "Item Number", "Item Name",
"Item Description", "Item Quantity",
"Item Price" };
this.inventory = new ArrayList<>();
inventory.add(new Item("X101111", "Samsung Camera", " ", 20, 69.99));
inventory.add(new Item("X101112", "Samsung Monitor", " ", 10, 279.99));
inventory.add(new Item("X101113", "Samsung Smartphone", " ", 110, 599.99));
inventory.add(new Item("X101114", "Apple Watch", " ", 20, 1259.99));
inventory.add(new Item("X101115", "Sony Playstation 5", " ", 0, 399.99));
}
public String[] getTableHeader() {
return tableHeader;
}
public List<Item> getInventory() {
return inventory;
}
}
public class Item {
private int itemPrice;
private int itemQuantity;
private final String itemNumber;
private final String itemName;
private final String itemDescription;
public Item(String itemNumber, String itemName,
String itemDescription, int itemQuantity, double itemPrice) {
this.itemNumber = itemNumber;
this.itemName = itemName;
this.itemDescription = itemDescription;
this.itemQuantity = itemQuantity;
setItemPrice(itemPrice);
}
public int getItemPrice() {
return itemPrice;
}
public void setItemPrice(double itemPrice) {
this.itemPrice = (int) Math.round(itemPrice * 100.0);
}
public int getItemQuantity() {
return itemQuantity;
}
public void setItemQuantity(int itemQuantity) {
this.itemQuantity = itemQuantity;
}
public String getItemNumber() {
return itemNumber;
}
public String getItemName() {
return itemName;
}
public String getItemDescription() {
return itemDescription;
}
}
}
This only demonstrates how to create a basic MRE:
the csv file is irrelevant.
data in the model is irrelevant.
your loadFile, newFile and saveFile buttons are irrelevant.
the TableModel is irrelevant
Your question is about adding an ActionListener to dynamically created checkboxes based on the columns of the table.
So all you need is a table with some columns and the resulting checkboxes.
import java.awt.*;
import javax.swing.*;
public class MRE extends JPanel
{
private static void createAndShowGUI()
{
JTable table = new JTable(5, 7);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );
JPanel buttons = new JPanel( new GridLayout(0, 1) );
for (int i = 0; i < table.getColumnCount(); i++)
{
String column = table.getColumnName(i);
JCheckBox checkBox = new JCheckBox("Display " + column);
checkBox.setSelected( true );
buttons.add( checkBox );
}
JPanel wrapper = new JPanel();
wrapper.add( buttons );
JFrame frame = new JFrame("MRE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane, BorderLayout.CENTER);
frame.add(wrapper, BorderLayout.LINE_END);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
SwingUtilities.invokeLater( () -> createAndShowGUI() );
}
}
If you can modify this to demonstrate how to use your "reusable class" to manage column visibility, then I will update the above code to use my reusable class with 4 additional lines of code.
Edit:
Suggested improvements to your code:
Make the code reusable and self contained
Don't use static methods
Don't change the data.
Your original question was:
How do I add an ActionListener to a JCheckBox?
So to do that you need a class that:
implements an ActionListener
is self contained to implement the functionality you require.
So the basic structure could be like the following:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SomeFunction implements ActionListener
{
private JTable table;
public SomeFunction(JTable table)
{
this.table = table;
}
#Override
public void actionPerformed(ActionEvent e)
{
if (e.getSource() instanceof AbstractButton)
{
String command = e.getActionCommand();
AbstractButton button = (AbstractButton)e.getSource();
if (button.isSelected())
doSelected( command );
else
doUnselected( command );
}
}
private void doSelected(String command)
{
System.out.println(command + " selected");
}
private void doUnselected(String command)
{
System.out.println(command + " unselected");
}
private static void createAndShowGUI()
{
JTable table = new JTable(5, 7);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );
JPanel buttons = new JPanel( new GridLayout(0, 1) );
SomeFunction listener = new SomeFunction( table ); // added
// TableColumnManager listener = new TableColumnManager(table, false);
// ColumnListener listener = new ColumnListener();
for (int i = 0; i < table.getColumnCount(); i++)
{
String column = table.getColumnName(i);
JCheckBox checkBox = new JCheckBox("Display " + column);
checkBox.setSelected( true );
checkBox.setActionCommand( column ); // added
checkBox.addActionListener( listener ); // added
buttons.add( checkBox );
}
JPanel wrapper = new JPanel();
wrapper.add( buttons );
JFrame frame = new JFrame("MRE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane, BorderLayout.CENTER);
frame.add(wrapper, BorderLayout.LINE_END);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
SwingUtilities.invokeLater( () -> createAndShowGUI() );
}
}
Whatever your function does it only needs to know about the table it should act upon.
So try to restructure your code into a reusable class.
If you want to use Gilberts code, then you need to restructure the ColumnListener class into a separate reusable self contained class.
Finally you can also try my reusable class. Check out Table Column Manager for the class to download.
Whatever reusable class you decide to use, you will only need to change a single line of code from the above example (once your functionality is contained in a reusable class).
Note the static methods would not be part of the final class. They are only there so simplify testing and posting of an MRE in a single class file.
Hope this helps with future design considerations.
I have a textbox with search button, if i click on search text, String gets highlighted in JTable cells, if the search text is having multiple Strings with comma separated, all those comma separated Strings has to be displayed in a different colors dynamically.
Can you please suggest what changes i need to do to the below working code(single String highlight)
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.DefaultHighlighter;
import java.awt.*;
public class TableExample {
JFrame f;
private JTextField textField;
TableExample() {
f = new JFrame();
String data[][] = {{"101", "lala", "670000"}, {"101", "lala", "670000"}, {"102", "Jai", "780000"},
{"101", "Sachin", "700000"}};
String column[] = {"ID", "NAME", "SALARY"};
JTable jt = new JTable();
jt.setBounds(30, 40, 200, 300);
JScrollPane sp = new JScrollPane(jt);
DefaultTableModel dtm = new DefaultTableModel(data, column);
dtm.setColumnIdentifiers(column);
jt.setModel(dtm);
JPanel inputpanel = new JPanel();
inputpanel.setLayout(new BoxLayout(inputpanel, BoxLayout.LINE_AXIS));
textField = new JTextField();
JButton button = new JButton("Highlight");
button.addActionListener(e -> {
jt.repaint();
});
inputpanel.add(textField);
inputpanel.add(button);
jt.setDefaultRenderer(Object.class, new CellHighlightRenderer());
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, inputpanel, sp);
f.add(splitPane);
f.setSize(300, 400);
}
class CellHighlightRenderer extends JTextField implements TableCellRenderer {
public DefaultHighlighter high = new DefaultHighlighter();
public DefaultHighlighter.DefaultHighlightPainter highlight_painter = new DefaultHighlighter.DefaultHighlightPainter(
Color.YELLOW);
public CellHighlightRenderer() {
setBorder(BorderFactory.createEmptyBorder());
setHighlighter(high);
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
setFont(table.getFont());
setValue(value);
int pos = 0;
String pattern = textField.getText(); // Grab the text.
if (pattern != null && pattern.trim().length() > 0)
while ((pos = value.toString().indexOf(pattern, pos)) >= 0) {
try {
high.addHighlight(pos, pos + pattern.length(), highlight_painter);
pos += pattern.length();
} catch (Exception e) {
e.printStackTrace();
}
}
return this;
}
protected void setValue(Object value) {
setText((value == null) ? "" : value.toString());
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(()->{
TableExample te = new TableExample();
te.f.setVisible(true);
});
}
}
I have done what i think you asked. Read commends inside the code. Whenever u see a comment, try to compare it with your code. I didnt know what colors you want so i have done with random color to each word.
Preview:
package test;
import java.awt.Color;
import java.awt.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.DefaultHighlighter;
public class TableExample {
JFrame f;
private JTextField textField; // make the textfield a field so u can grab its text whenever u need it (in our
// case in renderer)
private HashMap<String, Color> words = new HashMap<>();
TableExample() {
f = new JFrame();
// I changed the data a bit for my tests, take care of that.
String data[][] = { { "101", "lala", "670000" }, { "101", "lala", "670000" }, { "102", "Jai", "780000" },
{ "101", "Sachin", "700000" } };
String column[] = { "ID", "NAME", "SALARY" };
JTable jt = new JTable();
jt.setBounds(30, 40, 200, 300);
JScrollPane sp = new JScrollPane(jt); // You were not adding the sp into your panel, take care that next time.
DefaultTableModel dtm = new DefaultTableModel(data, column); // Create the model with our data.
dtm.setColumnIdentifiers(column);
jt.setModel(dtm);
JPanel inputpanel = new JPanel();
inputpanel.setLayout(new BoxLayout(inputpanel, BoxLayout.LINE_AXIS));
textField = new JTextField();
JButton button = new JButton("Highlight");
button.addActionListener(e -> { // Button should only repaint the table (a.k.a read the renderer again).
words.clear(); //Clear the map with the words
String text = textField.getText(); // Grab the text.
if (text.trim().length() > 0) {
String[] splitPattern = text.split(","); //Split the words
for (String s : splitPattern) {
words.put(s, getARandomColor()); //Put each word with a RANDOM color.
}
}
jt.repaint();// Changing the table's renderer is bad on every button click, and no needed.
});
inputpanel.add(textField);
inputpanel.add(button);
jt.setDefaultRenderer(Object.class, new CellHighlightRenderer()); // Add the renderer only 1 time.
// I add sp here, not the table (if you want your table to actually have a
// scrollpane)
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, inputpanel, sp);
f.add(splitPane);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Hopefully you didnt forget this.
f.setSize(300, 400);
f.pack(); // Use pack() to the frame between set it visible.
// f.setVisible(true); //setVisible to constructor is bad idea. I suggest you to
// avoid that, and show your frame after its initiation.
}
class CellHighlightRenderer extends JTextField implements TableCellRenderer {
public DefaultHighlighter high = new DefaultHighlighter();
public DefaultHighlighter.DefaultHighlightPainter highlight_painter = new DefaultHighlighter.DefaultHighlightPainter(
Color.YELLOW);
public CellHighlightRenderer() {
setBorder(BorderFactory.createEmptyBorder());
setHighlighter(high);
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
setFont(table.getFont());
setValue(value);
int pos = 0;
if (words.size() > 0) {
for (String word : words.keySet()) {
while ((pos = value.toString().indexOf(word, pos)) >= 0) {
try {
highlight_painter = new DefaultHighlighter.DefaultHighlightPainter(words.get(word));
// high.addHighlight(first, last, highlight_painter);
high.addHighlight(pos, pos + word.length(), highlight_painter);
pos += word.length();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return this;
}
protected void setValue(Object value) {
setText((value == null) ? "" : value.toString());
}
}
private Color getARandomColor() {
return new Color((int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255));
}
public static void main(String[] args) {
/* *******THIS IS VERY IMPORTANT******* */
/* All swing applications should run in their own thread, named EDT */
SwingUtilities.invokeLater(() -> {
TableExample te = new TableExample();
te.f.setVisible(true); // Here, make it visisble
});
}
}
I am newbie on java-swing. I am trying to add icon in table cell. but when i add ImageIcon in cell then it's showing only path instead of icon.
Here is my code.
public void createGUI(ArrayList<String> params, String type) {
try {
DefaultTableModel model = new DefaultTableModel();
model.addColumn("ParameterName");
model.addColumn("ParameterType");
model.addColumn("Operation");
for (int i = 0; i < params.size() - 4; i++) {
String param_name = params.get(i).toString().substring(0, params.get(i).toString().indexOf("["));
String param_type = params.get(i).toString().substring(params.get(i).toString().indexOf("[") + 1, params.get(i).toString().indexOf("]"));
//URL url = ClassLoader.getSystemClassLoader().getResource("");
ImageIcon image = new ImageIcon("/com/soastreamer/resources/delete_idle.png");
// JLabel label = new JLabel(image);
model.addRow(new Object[]{param_name, param_type.toUpperCase(),image});
}
Action delete = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JTable table = (JTable) e.getSource();
int modelRow = Integer.valueOf(e.getActionCommand());
((DefaultTableModel) table.getModel()).removeRow(modelRow);
}
};
Here is image for clear understanding.
Please give me hint or any reference.
Thank you.
The problem lies with your TableModel, you have to tell the table that it has to render an image in that column overriding the getColumnClass(int column) method of the model.
Look at this answer by camickr.
UPDATE
Minimal example of a JTable with an ImageIcon using DefaultTableModel's renderer to paint it. I borrowed the updateRowHeights() code from this answer again by camickr, without it the icon was bigger than the row and wasn't fully displayed.
The important thing here is that now when the renderer calls getColumnClass(1), it gets ImageIcon.class so the code to render icons will be executed. By default this method would return Object.class and the renderer would ignore the fact that it's an icon.
import java.awt.BorderLayout;
import java.awt.Component;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
public class ImageIconTable
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ImageIconTable().initGUI();
}
});
}
public void initGUI()
{
JFrame frame = new JFrame();
DefaultTableModel tableModel = new DefaultTableModel()
{
#Override
public Class getColumnClass(int column)
{
if (column == 1) return ImageIcon.class;
return Object.class;
}
};
tableModel.addColumn("Row 1");
tableModel.addColumn("Icons Row");
tableModel.addRow(new Object[]{"This cell is an Object", new ImageIcon("icon.jpg")});
_table = new JTable(tableModel);
updateRowHeights();
frame.add(new JScrollPane(_table), BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private void updateRowHeights()
{
try
{
for (int row = 0; row < _table.getRowCount(); row++)
{
int rowHeight = _table.getRowHeight();
for (int column = 0; column < _table.getColumnCount(); column++)
{
Component comp = _table.prepareRenderer(_table.getCellRenderer(row, column), row, column);
rowHeight = Math.max(rowHeight, comp.getPreferredSize().height);
}
_table.setRowHeight(row, rowHeight);
}
}
catch(ClassCastException e) {}
}
private JTable _table;
}
It looks like this:
First, I suggest you to use ImageIo.read() and use the BufferedImage returned as argument for your ImageIcon object.
Second, use the Class.getResource() facility
YourClass.class.getResource("/com/soastreamer/resources/delete_idle.png");
Then, everything should work.
There are a lot of time, that I'm trying to make the Cell Renderer in the JavaOne 2007's talk maked by Shanon Hickey, Romain Guy and Chris Campbell, in the pages 38 and 39 (that you can find here : http://docs.huihoo.com/javaone/2007/desktop/TS-3548.pdf).
I asked Romain Guy, and Chris campbell, but without success, they say that they cannot pulish the source code.
So, any one can, give an idea, or even a source code on how to make this complex cell renderer ?
I learned this slides of many times, they say :
1)Cell Renderer: Column Spanning
Viewport clips column contents
and
2) Viewport moves to
expose the right text
for each column
I don't understand that, please can you give more in depth explanations ?
Cheers
Windows 7
JDK 1.7.0_21
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
public class ComplexCellRendererTest {
private static boolean DEBUG = true;
private JRadioButton r1 = new JRadioButton("scrollRectToVisible");
private JRadioButton r2 = new JRadioButton("setViewPosition");
public JComponent makeUI() {
String[] columnNames = {"AAA", "BBB"};
Object[][] data = {
{new Test("1", "aaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"), "4"},
{new Test("2", "1234567890\nabcdefghijklmdopqrstuvwxyz"), "5"},
{new Test("3", "ccccccccccccccccccccccccccccccccccc\ndddddddddddd"), "6"},
};
DefaultTableModel model = new DefaultTableModel(data, columnNames) {
#Override public boolean isCellEditable(int row, int column) {
return false;
}
};
final JTable table = new JTable(model);
table.getTableHeader().setReorderingAllowed(false);
table.setRowSelectionAllowed(true);
table.setFillsViewportHeight(true);
table.setShowVerticalLines(false);
table.setIntercellSpacing(new Dimension(0,1));
table.setRowHeight(56);
for(int i=0; i<table.getColumnModel().getColumnCount(); i++) {
TableColumn c = table.getColumnModel().getColumn(i);
c.setCellRenderer(new ComplexCellRenderer());
c.setMinWidth(50);
}
ActionListener al = new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
DEBUG = (e.getSource()==r1);
table.repaint();
}
};
Box box = Box.createHorizontalBox();
ButtonGroup bg = new ButtonGroup();
box.add(r1); bg.add(r1); r1.addActionListener(al);
box.add(r2); bg.add(r2); r2.addActionListener(al);
r1.setSelected(true);
JPanel p = new JPanel(new BorderLayout());
p.add(box, BorderLayout.NORTH);
p.add(new JScrollPane(table));
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new ComplexCellRendererTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
static class ComplexCellRenderer extends JPanel implements TableCellRenderer {
private final JTextArea textArea = new JTextArea(2, 999999);
private final JLabel label = new JLabel();
private final JScrollPane scroll = new JScrollPane();
public ComplexCellRenderer() {
super(new BorderLayout(0,0));
scroll.setViewportView(textArea);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scroll.setBorder(BorderFactory.createEmptyBorder());
scroll.setViewportBorder(BorderFactory.createEmptyBorder());
scroll.setOpaque(false);
scroll.getViewport().setOpaque(false);
textArea.setBorder(BorderFactory.createEmptyBorder());
//textArea.setMargin(new Insets(0,0,0,0));
textArea.setForeground(Color.RED);
textArea.setOpaque(false);
label.setBorder(BorderFactory.createMatteBorder(0,0,1,1,Color.GRAY));
setBackground(Color.WHITE);
setOpaque(true);
add(label, BorderLayout.NORTH);
add(scroll);
}
#Override public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
Test test;
if(value instanceof Test) {
test = (Test)value;
} else {
String title = value.toString();
Test t = (Test)table.getModel().getValueAt(row, 0);
test = new Test(title, t.text);
}
label.setText(test.title);
textArea.setText(test.text);
Rectangle cr = table.getCellRect(row, column, false);
if(DEBUG) {
//Unexplained flickering on first row?
textArea.scrollRectToVisible(cr);
} else {
//Work fine for me (JDK 1.7.0_21, Windows 7 64bit):
scroll.getViewport().setViewPosition(cr.getLocation());
}
if(isSelected) {
setBackground(Color.ORANGE);
} else {
setBackground(Color.WHITE);
}
return this;
}
}
}
class Test {
public final String title;
public final String text;
//public final Icon icon;
public Test(String title, String text) {
this.title = title;
this.text = text;
}
}
I have a Jtable with a checkbox in first column. I want to strikethrough text of a row when the checkbox is selected. (eg same as we do in microsoft outlook when our task is complete.) I have tried using AttributeString, but not able to do it.
Can anyone please guide me to solve it?
String strStrike;
AttributedString as;
public void setTextStrikeThrough() {
for(int r=0;r< taskcells.length;r++) {
if (ttable.getValueAt(r,0).equals(Boolean.TRUE)) {
for(int c=2;c<7;c++) {
strStrike+=taskcells[r][c-1];
}//end inner for as=new
AttributedString(strStrike);
as.addAttribute(TextAttribute.STRIKETHROUGH,
TextAttribute.STRIKETHROUGH_ON);
as.getIterator();
}//end if
}//end for
}
I am not getting exactly where to call this method. I want to strikethrough text of a row when checkbox of that row has been checked.
I don't know that an ActionListener will work well for a JCheckBox in a JTable since the check box isn't a real button but rather a rendering of a checkbox. Perhaps playing with the table model will help. For instance you can use HTML to display a strike through of Strings displayed in table cells. For instance below I create a custom TableModel that extends DefaultTableModel and holds rows with a Boolean object followed by objects of a TextWrapper class that I've created that changes its toString result depending on a boolean.
e.g.,
import java.util.Vector;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
public class StrikeThroughRow {
public static final Object[][] DATA = {{Boolean.TRUE, "Monday", "fe"},
{Boolean.FALSE, "Tuesday", "fi"}, {Boolean.TRUE, "Wednesday", "fo"},
{Boolean.FALSE, "Thursday", "fum"}, {Boolean.TRUE, "Friday", "foo"}};
public StrikeThroughRow() {
}
private static void createAndShowUI() {
JTable table = new JTable(new StrikeThroughModel(DATA));
JScrollPane scrollpane = new JScrollPane(table);
JFrame frame = new JFrame("StrikeThroughRow");
frame.getContentPane().add(scrollpane);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class StrikeThroughModel extends DefaultTableModel {
public StrikeThroughModel(Object[][] data) {
super(new String[]{"Check", "Work Day", "Giant Speak"}, 0);
for (int i = 0; i < data.length; i++) {
Vector<Object> rowVect = new Vector<Object>();
rowVect.add(data[i][0]);
if (data[i].length > 1) {
for (int j = 1; j < data[i].length; j++) {
rowVect.add(new TextWrapper(data[i][j].toString(), (Boolean)data[i][0]));
}
}
addRow(rowVect);
}
}
#Override
public Class<?> getColumnClass(int columnIndex) {
if (columnIndex == 0) {
return Boolean.class;
}
return super.getColumnClass(columnIndex);
}
#Override
public void setValueAt(Object value, int row, int column) {
if (column == 0) {
for (int i = 1; i < getColumnCount(); i++) {
TextWrapper textWrapper = (TextWrapper) getValueAt(row, i);
textWrapper.setStrikeThrough((Boolean) value);
fireTableCellUpdated(row, i);
}
}
super.setValueAt(value, row, column);
}
}
class TextWrapper {
private String text;
private boolean strikeThrough = false;
public TextWrapper(String text) {
this.text = text;
}
public TextWrapper(String text, boolean strikeThrough) {
this(text);
this.strikeThrough = strikeThrough;
}
#Override
public String toString() {
if (strikeThrough) {
return "<html><strike>" + text + "</html></strike>";
}
return text;
}
public void setStrikeThrough(boolean strikeThrough) {
this.strikeThrough = strikeThrough;
}
}
I'm betting that there are better solutions including creating a custom renderer for your cells, but the code above offers a quick and dirty fix.
Here is how you can create a "strike through font":
Map attributes = component.getFont().getAttributes();
attributes.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
component.setFont( new Font(attributes) );
One way to apply the font is to use the Table Row Rendering approach. Take a look at the background color example. Instead of setting the background of the renderer you can set the Font.
Otherwise you would need to create a custom renderer for the columns in your table to use the appropriate Font.
Add a listener to the checkbox which will add/remove the from the label. Here is an example of box and label maybe helpful:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class check {
public static void main(String args[]) {
JFrame frame = new JFrame("for bsm");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JCheckBox box = new JCheckBox("check me");
final JLabel label = new JLabel("<html>text</html>");
label.setFont(new Font("helvetica", Font.PLAIN, 12));
label.setForeground(new Color(50, 50, 25));
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
AbstractButton abstractButton = (AbstractButton) actionEvent.getSource();
if(abstractButton.getModel().isSelected())
label.setText(label.getText().replace("<html>", "<html><strike>").replace("</html>", "</strike></html>"));
else
label.setText(label.getText().replace("<html><strike>", "<html>").replace("</strike></html>", "</html>"));
}
};
box.addActionListener(actionListener);
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout(10, 10));
panel.add(label, BorderLayout.NORTH);
panel.add(box, BorderLayout.SOUTH);
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
frame.add(panel);
frame.setSize(300, 200);
frame.setVisible(true);
}
}